diff --git a/.env.test b/.env.test index 65afbdc1..3dfa2401 100644 --- a/.env.test +++ b/.env.test @@ -9,4 +9,8 @@ DATABASE_URL=sqlite://./db.sqlite TEST_CRM_CLIENT_ID= TEST_CRM_CLIENT_SECRET= TEST_CRM_TOKEN_URI= -TEST_CRM_REDIRECT_URI=https://ringcentral.github.io/ringcentral-embeddable/redirect.html \ No newline at end of file +TEST_CRM_REDIRECT_URI=https://ringcentral.github.io/ringcentral-embeddable/redirect.html + + +# Admin +ADMIN_EXTENSION_ID_DEV_PASS_LIST=1234567890 \ No newline at end of file diff --git a/README.md b/README.md index d0040715..01d49661 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Unified CRM extension for Google Chrome and Microsoft Edge +# RingCentral App Connect for Google Chrome and Microsoft Edge [![Build Status](https://github.com/ringcentral/rc-unified-crm-extension/workflows/CI%20Pipeline/badge.svg?branch=main)](https://github.com/ringcentral/rc-unified-crm-extension/actions) [![Latest release](https://img.shields.io/github/v/release/ringcentral/rc-unified-crm-extension)](https://github.com/ringcentral/rc-unified-crm-extension/releases) [![Coverage Status](https://coveralls.io/repos/github/ringcentral/rc-unified-crm-extension/badge.svg?branch=main)](https://coveralls.io/github/ringcentral/rc-unified-crm-extension?branch=main) diff --git a/bin/index.js b/bin/index.js index 9964b9a5..21771124 100644 --- a/bin/index.js +++ b/bin/index.js @@ -6,7 +6,7 @@ import inquirer from 'inquirer'; const program = new Command(); -program.version(packageJson.version).description('RingCentral CRM Extension'); +program.version(packageJson.version).description('RingCentral App Connect'); program .command('release') diff --git a/docs/crm/netsuite.md b/docs/crm/netsuite.md index 363eaf47..c8f0ebe6 100644 --- a/docs/crm/netsuite.md +++ b/docs/crm/netsuite.md @@ -16,7 +16,7 @@ To begin using the NetSuite integration, users will first need to do the followi * Login to NetSuite, then visit the [RingCentral Suite App](https://www.suiteapp.com/RingCentral-Unified-CRM-Extension) page, or: * Click on the "SuiteApps" tab if your role gives you access to it * Search for "RingCentral" in the directory - * Click "RingCentral Unified CRM Extension" in the search results + * Click "RingCentral App Connect" in the search results * Click the "Install" button found in the upper right hand corner of the page If you see, "Not compatible" in place of an "Install" button, then you must be running an older version of NetSuite. You will need to upgrade to 2024.2 or later. @@ -25,13 +25,13 @@ Installing the app from the SuiteApp marketplace is a necessary step prior to in ## Setup roles and permissions in NetSuite -Upon installation of the SuiteApp, a role will be created automatically within your account called "RingCentral CRM Extension." This role has been specially tuned to contain the bare minimum number access level to fully operate the Chrome extension. You can see a detailed list of permissions below if you would like to incorporate these permissions into a custom role of your own. +Upon installation of the SuiteApp, a role will be created automatically within your account called "RingCentral App Connect." This role has been specially tuned to contain the bare minimum number access level to fully operate the Chrome extension. You can see a detailed list of permissions below if you would like to incorporate these permissions into a custom role of your own. ### NetSuite OneWorld instructions -Upon installing the SuiteApp from the Marketplace, a new custom role named **"RingCentral CRM Extension"** will be automatically created in your account. If you are a OneWorld license holder, you will need to take these additional steps. +Upon installing the SuiteApp from the Marketplace, a new custom role named **"RingCentral App Connect"** will be automatically created in your account. If you are a OneWorld license holder, you will need to take these additional steps. -1. Clone the "RingCentral CRM Extension" role by selecting the "Customize" option. +1. Clone the "RingCentral App Connect" role by selecting the "Customize" option. 2. While cloning, add the permission **"List -> Subsidiaries"** to the cloned role. Use this cloned role when logging into and connecting App Connect to NetSuite. @@ -48,7 +48,7 @@ REST Web Services is default to be invisible. We'll need to turn on the feature ### Create role with required permissions -We recommend using the "RingCentral CRM Extension" role created for you when you install the SuiteApp. However, if you would like to create a custom role that includes the permissions necessary to allow this extension to operate fully, consult the table below. +We recommend using the "RingCentral App Connect" role created for you when you install the SuiteApp. However, if you would like to create a custom role that includes the permissions necessary to allow this extension to operate fully, consult the table below. | Category | Permission | Level | | ------------ | ------------------------------------ | ----- | diff --git a/docs/img/admin-bullhorn.png b/docs/img/admin-bullhorn.png new file mode 100644 index 00000000..67468095 Binary files /dev/null and b/docs/img/admin-bullhorn.png differ diff --git a/docs/img/admin-logging.png b/docs/img/admin-logging.png new file mode 100644 index 00000000..438014f6 Binary files /dev/null and b/docs/img/admin-logging.png differ diff --git a/docs/img/admin-tab.png b/docs/img/admin-tab.png new file mode 100644 index 00000000..262ba9ee Binary files /dev/null and b/docs/img/admin-tab.png differ diff --git a/docs/img/admin-user-view.png b/docs/img/admin-user-view.png new file mode 100644 index 00000000..5e0de447 Binary files /dev/null and b/docs/img/admin-user-view.png differ diff --git a/docs/release-notes.md b/docs/release-notes.md index e1760bdd..d8a89d56 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,12 @@ # Release notes -## 1.3.0 +## 1.3.2 + +- New: User setting inside call pop to control behavior of multiple matched contacts (disabled, all open, prompt to select) +- Fix: SMS logging issue +- Fix: Auto open extension now only opens when main page is opened + +## 1.3.1 - New: (Only for admin users) Admin tools. Admins have an extra tab in the extension to control end users' settings - Fix: SMS logging date format diff --git a/docs/users/admin.md b/docs/users/admin.md new file mode 100644 index 00000000..a8142370 --- /dev/null +++ b/docs/users/admin.md @@ -0,0 +1,57 @@ +# Managing user settings across your account + +Super Admins within your RingCentral account have access to an additional area of App Connect in which they can manage the end user's experience across their entire account. This feature primarily allows admins to set certain preferences, or mandate certain preferences across their entire account. This allows admins for example to mandate that all calls across an account be logged. Or that specific settings be employed for their CRM. + +
+ ![Admin tab in App Connect](../img/admin-tab.png){ .mw-400 } +
The admin tab in App Connect gives admins the ability to manage settings on behalf of others
+
+ +## Gaining access to the admin tab + +When you first load App Connect, you may not see the Admin tab. To make the Admin tab appears please check the following: + +1. Make sure you possess the "Super Admin" role in the RingCentral [Admin Console](https://service.ringcentral.com/). +2. Connect to your CRM + +## Managing settings on behalf of others + +Once you have access to the Admin tab, admins can manage the following: + +* Call and SMS logging settings +* Contact and call-pop settings +* CRM-specific settings +* Advanced settings +* Set the custom CRM manifest URL + +
+ ![Logging calls](../img/admin-logging.png){ .mw-400 } +
Admins can set call logging policies
+
+ +For each setting that can be managed by an admin, one can do the following: + +* Mandate the setting be a specific value. This is done by disabling the user's ability to customize the value, and select the value you prefer. +* Set the default value of a setting. This is done by setting the preferred value, and by enabling the user to customize the value. + +### What users within your account will see + +When a setting is mandated by an admin, a lock icon will appear next to the setting and it will be disabled, thereby allowing the user to see the value, but be unable to change it. + +
+ ![Logging calls](../img/admin-user-view.png){ .mw-400 } +
Admins can manage CRM-specific settings
+
+ +## Managing CRM-specific settings + +Each CRM supported by App Connect may expose custom settings. These settings can be managed under the area labeled as "Custom options." + +
+ ![Logging calls](../img/admin-bullhorn.png){ .mw-400 } +
Admins can manage CRM-specific settings
+
+ +## Managing custom adapter settings + +App Connect enables developers to build custom adapters to connect to proprietary CRMs, or CRMs not supported natively by App Connect. Users can load a custom adapter under "Developer Settings." Admins however can manage this setting across their entire account under the "Custom adapter" area of the Admin tab. diff --git a/mkdocs.yml b/mkdocs.yml index 8c890667..aaf88725 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,12 +77,13 @@ nav: - 'Redtail CRM': crm/redtail.md - 'NetSuite': crm/netsuite.md - 'User guide': - - 'Accessing the extension': users/access.md + - 'Basic usage': users/access.md - 'Making and receiving calls': users/making-calls.md - 'Logging calls': users/logging.md - 'Sending SMS': users/sms.md - 'Presence': users/presence.md - 'Settings': users/settings.md + - 'Administration': users/admin.md - 'Developer guide': - 'Introduction': developers/index.md - 'Getting started': developers/getting-started.md diff --git a/package.json b/package.json index 295fb163..226753c3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "rc-unified-crm-extension-server", - "version": "1.3.0", - "description": "RingCentral Unified CRM Extension", + "version": "1.3.2", + "description": "RingCentral App Connect", "main": "index.js", "bin": { "rc-unified-crm-extension": "bin/index.js" @@ -72,4 +72,4 @@ "url": "https://github.com/ringcentral/rc-unified-crm-extension/issues" }, "homepage": "https://github.com/ringcentral/rc-unified-crm-extension#readme" -} +} \ No newline at end of file diff --git a/serverless-deploy/sample.env.yml b/serverless-deploy/sample.env.yml index 95849184..22b6fe1d 100644 --- a/serverless-deploy/sample.env.yml +++ b/serverless-deploy/sample.env.yml @@ -7,4 +7,6 @@ TEST_CRM_CLIENT_SECRET: TEST_CRM_ACCESS_TOKEN_URI: TEST_CRM_REDIRECT_URI: -DATABASE_URL: \ No newline at end of file +DATABASE_URL: + +ADMIN_EXTENSION_ID_DEV_PASS_LIST: \ No newline at end of file diff --git a/src/adapters/bullhorn/index.js b/src/adapters/bullhorn/index.js index dae1931e..f4d8eabd 100644 --- a/src/adapters/bullhorn/index.js +++ b/src/adapters/bullhorn/index.js @@ -266,7 +266,7 @@ async function createContact({ user, authHeader, phoneNumber, newContactName, ne `${user.platformAdditionalInfo.restUrl}entity/ClientCorporation`, { name: "RingCentral_CRM_Extension_Placeholder_Company", - companyDescription: "This company was created automatically by the RingCentral Unified CRM Extension. Feel free to edit, or associate this company's contacts to more appropriate records. " + companyDescription: "This company was created automatically by the RingCentral App Connect. Feel free to edit, or associate this company's contacts to more appropriate records. " }, { headers: { @@ -509,15 +509,15 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi '' + '------------
' + 'END

' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': subject = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).utcOffset(Number(user.timezoneOffset)).format('YY/MM/DD')}`; - comments = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral CRM Extension`; + comments = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral App Connect`; break; case 'Fax': subject = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).utcOffset(Number(user.timezoneOffset)).format('YY/MM/DD')}`; - comments = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral CRM Extension`; + comments = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral App Connect`; break; } diff --git a/src/adapters/clio/index.js b/src/adapters/clio/index.js index a26bce60..f527b5d9 100644 --- a/src/adapters/clio/index.js +++ b/src/adapters/clio/index.js @@ -77,10 +77,8 @@ async function unAuthorize({ user }) { async function findContact({ user, authHeader, phoneNumber, overridingFormat }) { const numberToQueryArray = []; - if (overridingFormat === '') { - numberToQueryArray.push(phoneNumber.replace(' ', '+')); - } - else { + numberToQueryArray.push(phoneNumber.replace(' ', '+')); + if (overridingFormat !== '') { const formats = overridingFormat.split(','); for (var format of formats) { const phoneNumberObj = parsePhoneNumber(phoneNumber.replace(' ', '+')); @@ -94,6 +92,7 @@ async function findContact({ user, authHeader, phoneNumber, overridingFormat }) } } } + const matchedContactInfo = []; for (var numberToQuery of numberToQueryArray) { const personInfo = await axios.get( @@ -194,7 +193,7 @@ async function createCallLog({ user, contactInfo, authHeader, callLog, note, add const postBody = { data: { subject: callLog.customSubject ?? `[Call] ${callLog.direction} Call ${callLog.direction === 'Outbound' ? 'to' : 'from'} ${contactInfo.name} [${contactInfo.phone}]`, - body: `\nContact Number: ${contactInfo.phoneNumber}\nCall Result: ${callLog.result}\nNote: ${note}${callLog.recording ? `\n[Call recording link] ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral CRM Extension`, + body: `\nContact Number: ${contactInfo.phoneNumber}\nCall Result: ${callLog.result}\nNote: ${note}${callLog.recording ? `\n[Call recording link] ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral App Connect`, type: 'PhoneCommunication', received_at: moment(callLog.startTime).toISOString(), senders: [sender], @@ -255,8 +254,8 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, let patchBody = {}; if (!!recordingLink) { const urlDecodedRecordingLink = decodeURIComponent(recordingLink); - if (logBody.includes('\n\n--- Created via RingCentral CRM Extension')) { - logBody = logBody.replace('\n\n--- Created via RingCentral CRM Extension', `\n[Call recording link]${urlDecodedRecordingLink}\n\n--- Created via RingCentral CRM Extension`); + if (logBody.includes('\n\n--- Created via RingCentral App Connect')) { + logBody = logBody.replace('\n\n--- Created via RingCentral App Connect', `\n[Call recording link]${urlDecodedRecordingLink}\n\n--- Created via RingCentral App Connect`); } else { logBody += `\n[Call recording link]${urlDecodedRecordingLink}`; @@ -274,7 +273,7 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, originalNote = logBody.split('\n[Call recording link]')[0].split('Note: ')[1]; } else { - originalNote = logBody.split('\n\n--- Created via RingCentral CRM Extension')[0].split('Note: ')[1]; + originalNote = logBody.split('\n\n--- Created via RingCentral App Connect')[0].split('Note: ')[1]; } logBody = logBody.replace(`Note: ${originalNote}`, `Note: ${note ?? ''}`); @@ -367,15 +366,15 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi `${message.subject}\n` + '------------\n' + 'END\n\n' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': logSubject = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - logBody = `Voicemail recording link: ${recordingLink} \n\n--- Created via RingCentral CRM Extension`; + logBody = `Voicemail recording link: ${recordingLink} \n\n--- Created via RingCentral App Connect`; break; case 'Fax': logSubject = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - logBody = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral CRM Extension`; + logBody = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral App Connect`; break; } const postBody = { @@ -459,7 +458,7 @@ async function getCallLog({ user, callLogId, authHeader }) { }); const note = getLogRes.data.data.body.includes('[Call recording link]') ? getLogRes.data.data.body.split('Note: ')[1].split('\n[Call recording link]')[0] : - getLogRes.data.data.body.split('Note: ')[1].split('\n\n--- Created via RingCentral CRM Extension')[0]; + getLogRes.data.data.body.split('Note: ')[1].split('\n\n--- Created via RingCentral App Connect')[0]; const contactId = getLogRes.data.data.senders[0].type == 'Person' ? getLogRes.data.data.senders[0].id : getLogRes.data.data.receivers[0].id; diff --git a/src/adapters/insightly/index.js b/src/adapters/insightly/index.js index b24a4668..96c3cee6 100644 --- a/src/adapters/insightly/index.js +++ b/src/adapters/insightly/index.js @@ -263,7 +263,7 @@ async function createCallLog({ user, contactInfo, authHeader, callLog, note, add const callRecordingDetail = callLog.recording ? `\nCall recording link: ${callLog.recording.link}` : ""; const postBody = { TITLE: callLog.customSubject ?? `${callLog.direction} Call ${callLog.direction === 'Outbound' ? 'to' : 'from'} ${contactInfo.name}`, - DETAILS: `This was a ${callLog.duration} seconds call ${callLog.direction === 'Outbound' ? `to ${contactInfo.name}(${callLog.to.phoneNumber})` : `from ${contactInfo.name}(${callLog.from.phoneNumber})`}.${noteDetail}${callRecordingDetail}\n\n--- Created via RingCentral CRM Extension`, + DETAILS: `This was a ${callLog.duration} seconds call ${callLog.direction === 'Outbound' ? `to ${contactInfo.name}(${callLog.to.phoneNumber})` : `from ${contactInfo.name}(${callLog.from.phoneNumber})`}.${noteDetail}${callRecordingDetail}\n\n--- Created via RingCentral App Connect`, START_DATE_UTC: moment(callLog.startTime).utc(), END_DATE_UTC: moment(callLog.startTime).utc().add(callLog.duration, 'seconds') } @@ -355,8 +355,8 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, let logBody = getLogRes.data.DETAILS; let logSubject = getLogRes.data.TITLE; if (!!recordingLink) { - if (logBody.includes('\n\n--- Created via RingCentral CRM Extension')) { - logBody = logBody.replace('\n\n--- Created via RingCentral CRM Extension', `\n[Call recording link]${urlDecodedRecordingLink}\n\n--- Created via RingCentral CRM Extension`); + if (logBody.includes('\n\n--- Created via RingCentral App Connect')) { + logBody = logBody.replace('\n\n--- Created via RingCentral App Connect', `\n[Call recording link]${urlDecodedRecordingLink}\n\n--- Created via RingCentral App Connect`); } else { logBody += `\n[Call recording link]${urlDecodedRecordingLink}`; @@ -368,7 +368,7 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, originalNote = logBody.split('\n[Call recording link]')[0].split('Agent notes: ')[1]; } else { - originalNote = logBody.split('\n\n--- Created via RingCentral CRM Extension')[0].split('Agent notes: ')[1]; + originalNote = logBody.split('\n\n--- Created via RingCentral App Connect')[0].split('Agent notes: ')[1]; } logBody = logBody.replace(`Agent notes: ${originalNote}`, `Agent notes: ${note ?? ''}`); @@ -413,7 +413,7 @@ async function getCallLog({ user, callLogId, authHeader }) { }); const note = getLogRes.data.DETAILS.includes('[Call recording link]') ? getLogRes.data.DETAILS?.split('Agent notes: ')[1]?.split('\n[Call recording link]')[0] : - getLogRes.data.DETAILS?.split('Agent notes: ')[1]?.split('\n\n--- Created via RingCentral CRM Extension')[0]; + getLogRes.data.DETAILS?.split('Agent notes: ')[1]?.split('\n\n--- Created via RingCentral App Connect')[0]; const contactRes = await axios.get( `${user.platformAdditionalInfo.apiUrl}/${process.env.INSIGHTLY_API_VERSION}/${getLogRes.data.LINKS[0].LINK_OBJECT_NAME}s/${getLogRes.data.LINKS[0].LINK_OBJECT_ID}`, { @@ -455,15 +455,15 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi `${message.subject}\n` + '------------\n' + 'END\n\n' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': title = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - details = `Voicemail recording link: ${recordingLink} \n\n--- Created via RingCentral CRM Extension`; + details = `Voicemail recording link: ${recordingLink} \n\n--- Created via RingCentral App Connect`; break; case 'Fax': title = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - details = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral CRM Extension`; + details = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral App Connect`; break; } diff --git a/src/adapters/manifest.json b/src/adapters/manifest.json index 0247e950..dd083b59 100644 --- a/src/adapters/manifest.json +++ b/src/adapters/manifest.json @@ -52,13 +52,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -232,13 +232,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -359,13 +359,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -483,13 +483,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -684,13 +684,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -810,13 +810,13 @@ "elements": [ { "const": "pageDescription", - "title": "RingCentral CRM Extension is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", + "title": "RingCentral App Connect is currently in beta. We welcome any problem reports, feedback, ideas and feature requests you may have.", "type": "string", "bold": false }, { "const": "scoreDescription", - "title": "How likely are you to recommend the Unified CRM Extension to a friend or colleague?", + "title": "How likely are you to recommend the App Connect to a friend or colleague?", "type": "string", "bold": true }, @@ -880,5 +880,5 @@ } } }, - "version": "1.3.0" + "version": "1.3.2" } \ No newline at end of file diff --git a/src/adapters/netsuite/index.js b/src/adapters/netsuite/index.js index a71742bb..8554a623 100644 --- a/src/adapters/netsuite/index.js +++ b/src/adapters/netsuite/index.js @@ -297,7 +297,7 @@ async function createCallLog({ user, contactInfo, authHeader, callLog, note, add startTime: startTimeSLot, endTime: endTimeSlot, timedEvent: true, - message: `\nCall Start Time: ${formatedStartTime}\n Duration In Second: ${callLog.duration}Sec.\n Call End Time : ${formatedEndTime}\nContact Number: ${contactInfo.phoneNumber}\nNote: ${note}${callLog.recording ? `\nCall recording link ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral CRM Extension`, + message: `Note: ${note}${callLog.recording ? `\nCall recording link ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral App Connect`, }; if (contactInfo.type?.toUpperCase() === 'CONTACT') { const contactInfoRes = await axios.get(`https://${user.hostname.split(".")[0]}.suitetalk.api.netsuite.com/services/rest/record/v1/contact/${contactInfo.id}`, { @@ -369,7 +369,7 @@ async function getCallLog({ user, callLogId, authHeader }) { }); const note = getLogRes.data?.message.includes('Call recording link') ? getLogRes.data?.message.split('Note: ')[1].split('\nCall recording link')[0] : - getLogRes.data?.message.split('Note: ')[1].split('\n\n--- Created via RingCentral CRM Extension')[0]; + getLogRes.data?.message.split('Note: ')[1].split('\n\n--- Created via RingCentral App Connect')[0]; return { callLogInfo: { subject: getLogRes.data.title, @@ -400,8 +400,8 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, let patchBody = { title: subject }; if (!!recordingLink) { const urlDecodedRecordingLink = decodeURIComponent(recordingLink); - if (messageBody.includes('\n\n--- Created via RingCentral CRM Extension')) { - messageBody = messageBody.replace('\n\n--- Created via RingCentral CRM Extension', `\nCall recording link${urlDecodedRecordingLink}\n\n--- Created via RingCentral CRM Extension`); + if (messageBody.includes('\n\n--- Created via RingCentral App Connect')) { + messageBody = messageBody.replace('\n\n--- Created via RingCentral App Connect', `\nCall recording link${urlDecodedRecordingLink}\n\n--- Created via RingCentral App Connect`); } else { messageBody += `\nCall recording link${urlDecodedRecordingLink}`; @@ -413,7 +413,7 @@ async function updateCallLog({ user, existingCallLog, authHeader, recordingLink, originalNote = messageBody.split('\nCall recording link')[0].split('Note: ')[1]; } else { - originalNote = messageBody.split('\n\n--- Created via RingCentral CRM Extension')[0].split('Note: ')[1]; + originalNote = messageBody.split('\n\n--- Created via RingCentral App Connect')[0].split('Note: ')[1]; } messageBody = messageBody.replace(`Note: ${originalNote}`, `Note: ${note}`); @@ -477,16 +477,16 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi `${message.subject}\n` + '------------\n' + 'END\n\n' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': const decodedRecordingLink = decodeURIComponent(recordingLink); title = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - logBody = `Voicemail recording link: ${decodedRecordingLink} \n\n--- Created via RingCentral CRM Extension`; + logBody = `Voicemail recording link: ${decodedRecordingLink} \n\n--- Created via RingCentral App Connect`; break; case 'Fax': title = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - logBody = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral CRM Extension`; + logBody = `Fax document link: ${faxDocLink} \n\n--- Created via RingCentral App Connect`; break; } const postBody = { @@ -606,7 +606,7 @@ async function createContact({ user, authHeader, phoneNumber, newContactName, ne else { let companyPostBody = { companyName: 'RingCentral_CRM_Extension_Placeholder_Company', - comments: "This company was created automatically by the RingCentral Unified CRM Extension. Feel free to edit, or associate this company's contacts to more appropriate records.", + comments: "This company was created automatically by the RingCentral App Connect. Feel free to edit, or associate this company's contacts to more appropriate records.", }; if (oneWorldEnabled !== undefined && oneWorldEnabled === true) { companyPostBody.subsidiary = { id: subsidiaryId }; @@ -652,10 +652,12 @@ async function createContact({ user, authHeader, phoneNumber, newContactName, ne } } case 'custjob': + const lastName = nameParts.lastName.length > 0 ? nameParts.lastName : nameParts.firstName; const customerPayLoad = { firstName: nameParts.firstName, middleName: nameParts.middleName, - lastName: nameParts.lastName.length > 0 ? nameParts.lastName : nameParts.firstName, + lastName: lastName, + entityId: nameParts.firstName + " " + lastName, phone: phoneNumber || '', isPerson: true diff --git a/src/adapters/pipedrive/index.js b/src/adapters/pipedrive/index.js index 0c60a406..3f499e18 100644 --- a/src/adapters/pipedrive/index.js +++ b/src/adapters/pipedrive/index.js @@ -182,7 +182,7 @@ async function createCallLog({ user, contactInfo, authHeader, callLog, note, add person_id: contactInfo.id, org_id: orgId, deal_id: dealId, - note: `

[Phone Number] ${contactInfo.phoneNumber}

[Time] ${moment(callLog.startTime).utcOffset(user.timezoneOffset).format('YYYY-MM-DD hh:mm:ss A')}

[Duration] ${callLog.duration} seconds

[Call result] ${callLog.result}

[Note]${note}

${callLog.recording ? `

[Call recording link] open

` : ''}

[Created via] RingCentral CRM Extension

`, + note: `

[Phone Number] ${contactInfo.phoneNumber}

[Time] ${moment(callLog.startTime).utcOffset(user.timezoneOffset).format('YYYY-MM-DD hh:mm:ss A')}

[Duration] ${callLog.duration} seconds

[Call result] ${callLog.result}

[Note]${note}

${callLog.recording ? `

[Call recording link] open

` : ''}

[Created via] RingCentral App Connect

`, done: true, due_date: dateUtc, due_time: timeUtc @@ -285,15 +285,15 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi '' + '------------
' + 'END

' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': subject = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).utcOffset(user.timezoneOffset).format('YY/MM/DD')}`; - note = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral CRM Extension`; + note = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral App Connect`; break; case 'Fax': subject = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).utcOffset(user.timezoneOffset).format('YY/MM/DD')}`; - note = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral CRM Extension`; + note = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral App Connect`; break; } const postBody = { diff --git a/src/adapters/pipedrive/redirect.html b/src/adapters/pipedrive/redirect.html index cb8b0f8e..0a13d010 100644 --- a/src/adapters/pipedrive/redirect.html +++ b/src/adapters/pipedrive/redirect.html @@ -87,7 +87,7 @@ header.innerHTML = 'RingCentral Extension for Pipedrive'; contentDiv.appendChild(header); if (!window.location.search.includes('code')) { - header.innerHTML = 'Thank you for installing the RingCentral Unified CRM extension for Pipedrive'; + header.innerHTML = 'Thank you for installing the RingCentral App Connect for Pipedrive'; const descriptionDev = window.document.createElement('div'); contentDiv.appendChild(descriptionDev); descriptionDev.innerHTML = 'To connect to Pipedrive, please visit Pipdrive Marketplace and click "Install now"'; diff --git a/src/adapters/redtail/index.js b/src/adapters/redtail/index.js index e72c296d..28a1c667 100644 --- a/src/adapters/redtail/index.js +++ b/src/adapters/redtail/index.js @@ -137,7 +137,7 @@ async function createCallLog({ user, contactInfo, callLog, note }) { const callRecordingDetail = callLog.recording ? `\nCall recording link: open` : ""; const postBody = { subject: callLog.customSubject ?? `${callLog.direction} Call ${callLog.direction === 'Outbound' ? 'to' : 'from'} ${contactInfo.name}`, - description: `This was a ${callLog.duration} seconds call ${callLog.direction === 'Outbound' ? `to ${contactInfo.name}(${callLog.to.phoneNumber})` : `from ${contactInfo.name}(${callLog.from.phoneNumber})`}.
${descriptionNotes}
${callRecordingDetail}
Created via: RingCentral CRM Extension`, + description: `This was a ${callLog.duration} seconds call ${callLog.direction === 'Outbound' ? `to ${contactInfo.name}(${callLog.to.phoneNumber})` : `from ${contactInfo.name}(${callLog.from.phoneNumber})`}.
${descriptionNotes}
${callRecordingDetail}
Created via: RingCentral App Connect`, start_date: moment(callLog.startTime).utc().toISOString(), end_date: moment(callLog.startTime).utc().add(callLog.duration, 'seconds').toISOString(), activity_code_id: 3, @@ -267,15 +267,15 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi '' + '------------
' + 'END

' + - '--- Created via RingCentral CRM Extension'; + '--- Created via RingCentral App Connect'; break; case 'Voicemail': subject = `Voicemail left by ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - description = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral CRM Extension`; + description = `
${subject}
Voicemail recording link: ${recordingLink}

--- Created via RingCentral App Connect`; break; case 'Fax': subject = `Fax document sent from ${contactInfo.name} - ${moment(message.creationTime).format('YY/MM/DD')}`; - description = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral CRM Extension`; + description = `
${subject}
Fax document link: ${faxDocLink}

--- Created via RingCentral App Connect`; break; } diff --git a/src/adapters/testCRM/index.js b/src/adapters/testCRM/index.js index b4753042..3a2f0e66 100644 --- a/src/adapters/testCRM/index.js +++ b/src/adapters/testCRM/index.js @@ -214,7 +214,7 @@ async function createCallLog({ user, contactInfo, authHeader, callLog, note, add // const postBody = { // subject: callLog.customSubject ?? `[Call] ${callLog.direction} Call ${callLog.direction === 'Outbound' ? 'to' : 'from'} ${contactInfo.name} [${contactInfo.phone}]`, - // body: `\nContact Number: ${contactInfo.phoneNumber}\nCall Result: ${callLog.result}\nNote: ${note}${callLog.recording ? `\n[Call recording link] ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral CRM Extension`, + // body: `\nContact Number: ${contactInfo.phoneNumber}\nCall Result: ${callLog.result}\nNote: ${note}${callLog.recording ? `\n[Call recording link] ${callLog.recording.link}` : ''}\n\n--- Created via RingCentral App Connect`, // type: 'PhoneCommunication', // received_at: moment(callLog.startTime).toISOString() // } @@ -344,7 +344,7 @@ async function createMessageLog({ user, contactInfo, authHeader, message, additi // const postBody = { // data: { // subject: `[SMS] ${message.direction} SMS - ${message.from.name ?? ''}(${message.from.phoneNumber}) to ${message.to[0].name ?? ''}(${message.to[0].phoneNumber})`, - // body: `${message.direction} SMS - ${message.direction == 'Inbound' ? `from ${message.from.name ?? ''}(${message.from.phoneNumber})` : `to ${message.to[0].name ?? ''}(${message.to[0].phoneNumber})`} \n${!!message.subject ? `[Message] ${message.subject}` : ''} ${!!recordingLink ? `\n[Recording link] ${recordingLink}` : ''}\n\n--- Created via RingCentral CRM Extension`, + // body: `${message.direction} SMS - ${message.direction == 'Inbound' ? `from ${message.from.name ?? ''}(${message.from.phoneNumber})` : `to ${message.to[0].name ?? ''}(${message.to[0].phoneNumber})`} \n${!!message.subject ? `[Message] ${message.subject}` : ''} ${!!recordingLink ? `\n[Recording link] ${recordingLink}` : ''}\n\n--- Created via RingCentral App Connect`, // type: 'Message' // } // } diff --git a/src/adapters/testCRM/manifest.json b/src/adapters/testCRM/manifest.json index ed97cb87..5a6f78bd 100644 --- a/src/adapters/testCRM/manifest.json +++ b/src/adapters/testCRM/manifest.json @@ -101,5 +101,5 @@ ] } }, - "version": "1.3.0" + "version": "1.3.2" } \ No newline at end of file diff --git a/src/core/admin.js b/src/core/admin.js index 23150802..d4dbb1f6 100644 --- a/src/core/admin.js +++ b/src/core/admin.js @@ -10,7 +10,7 @@ async function validateAdminRole({ rcAccessToken }) { }, }); return { - isValidated: !!rcExtensionResponse.data?.permissions?.admin?.enabled || rcExtensionResponse.data.name === 'Da Kong' || rcExtensionResponse.data.name === 'Embbnux Ji', + isValidated: !!rcExtensionResponse.data?.permissions?.admin?.enabled || (!!process.env.ADMIN_EXTENSION_ID_DEV_PASS_LIST && process.env.ADMIN_EXTENSION_ID_DEV_PASS_LIST.split(',').includes(rcExtensionResponse.data.id.toString())), rcAccountId: rcExtensionResponse.data.account.id }; } diff --git a/src/core/auth.js b/src/core/auth.js index 96fac1ca..a0bcd16b 100644 --- a/src/core/auth.js +++ b/src/core/auth.js @@ -53,7 +53,7 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, callbackUri, apiU async function onApiKeyLogin({ platform, hostname, apiKey, additionalInfo }) { const platformModule = require(`../adapters/${platform}`); const basicAuth = platformModule.getBasicAuth({ apiKey }); - const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader: `Basic ${basicAuth}`, hostname, additionalInfo }); + const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader: `Basic ${basicAuth}`, hostname, additionalInfo, apiKey }); if (successful) { const userInfo = await saveUserInfo({ platformUserInfo, diff --git a/src/releaseNotes.json b/src/releaseNotes.json index aa84dd2e..2be69863 100644 --- a/src/releaseNotes.json +++ b/src/releaseNotes.json @@ -1,5 +1,21 @@ { - "1.3.0":{ + "1.3.2":{ + "global": [ + { + "type": "New", + "description": "- User setting inside call pop to control behavior of multiple matched contacts (disabled, all open, prompt to select)" + }, + { + "type": "Fix", + "description": "- SMS logging issue" + }, + { + "type": "Fix", + "description": "- Auto open extension now only opens when main page is opened" + } + ] + }, + "1.3.1":{ "global": [ { "type": "New",