@app-connect/core
Version:
RingCentral App Connect Core
493 lines (473 loc) • 16.7 kB
JavaScript
/* eslint-disable no-param-reassign */
const { parsePhoneNumber } = require('awesome-phonenumber');
const moment = require('moment');
const {
performRequest,
mapFindContactResponse,
mapCreateCallLogResponse,
mapGetCallLogResponse,
getByPath,
} = require('./engine');
const { Connector } = require('../../models/dynamo/connectorSchema');
const { UserModel } = require('../../models/userModel');
async function loadPlatformConfig(proxyId) {
if (!proxyId) {
return null;
}
try {
const proxyConfig = await Connector.getProxyConfig(proxyId);
return proxyConfig;
} catch (error) {
console.error('Error getting proxy config: ', proxyId);
return null;
}
}
async function getAuthType({ proxyId, proxyConfig } = {}) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(proxyId));
if (!cfg) {
return 'apiKey';
}
return cfg.auth.type || 'apiKey';
}
async function getOauthInfo({ proxyId, proxyConfig, tokenUrl, hostname } = {}) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(proxyId));
if (!cfg) {
return {};
}
return {
clientId: cfg.auth.clientId,
clientSecret: cfg.auth.clientSecret,
accessTokenUri: tokenUrl || cfg.auth.tokenUrl,
redirectUri: cfg.auth.redirectUri,
};
}
function getBasicAuth({ apiKey }) {
return Buffer.from(`${apiKey}:`).toString('base64');
}
async function getUserInfo({ authHeader, hostname, additionalInfo, platform, apiKey, proxyId, proxyConfig } = {}) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(proxyId));
if (!cfg || !cfg.operations?.getUserInfo) {
// Fallback if no getUserInfo operation defined
return {
successful: false,
returnMessage: {
messageType: 'warning',
message: `Could not load user information. The platform does not support getUserInfo operation.`,
ttl: 1000
}
};
}
const response = await performRequest({
config: cfg,
opName: 'getUserInfo',
inputs: {
additionalInfo,
apiKey,
hostname,
platform,
},
user: {},
authHeader
});
const map = cfg.operations.getUserInfo.responseMapping || {};
const responseCtx = {
body: response.data,
additionalInfo,
apiKey,
hostname,
platform,
};
const rawUserId = map.idPath ? getByPath(responseCtx, map.idPath) : undefined;
const id = `${rawUserId}-${platform}`;
const name = map.namePath ? getByPath(responseCtx, map.namePath) : rawUserId;
const timezoneName = map.timezoneNamePath ? getByPath(responseCtx, map.timezoneNamePath) : undefined;
const overridingApiKey = map.overridingApiKeyPath ? getByPath(responseCtx, map.overridingApiKeyPath) : undefined;
// platformAdditionalInfo mapping and cleanup
const platformAdditionalInfo = Object.assign({}, additionalInfo || {});
if (platformAdditionalInfo.password) delete platformAdditionalInfo.password;
if (map.platformAdditionalInfoPaths && typeof map.platformAdditionalInfoPaths === 'object') {
for (const [key, expr] of Object.entries(map.platformAdditionalInfoPaths)) {
platformAdditionalInfo[key] = getByPath(responseCtx, expr);
}
}
const message = map.messagePath ? (getByPath(responseCtx, map.messagePath) || `Connected to ${platform}.`) : `Connected to ${platform}.`;
return {
successful: true,
platformUserInfo: Object.assign(
{ id, name },
timezoneName ? { timezoneName } : {},
overridingApiKey ? { overridingApiKey } : {},
Object.keys(platformAdditionalInfo).length ? { platformAdditionalInfo } : {}
),
returnMessage: {
messageType: 'success',
message,
ttl: 1000
}
};
}
async function getUserList({ user, authHeader, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.getUserList) {
return [];
}
const response = await performRequest({
config: cfg,
opName: 'getUserList',
inputs: { user },
user,
authHeader
});
const map = cfg.operations.getUserList.responseMapping || {};
const responseCtx = { body: response.data };
const userList = map.listPath ? getByPath(responseCtx, map.listPath) : [];
return (userList || []).map(item => ({
id: getByPath(item, map.idPath || 'id'),
name: getByPath(item, map.namePath || 'name'),
email: getByPath(item, map.emailPath || 'email'),
}));
}
async function unAuthorize({ user }) {
const cfg = await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId);
if (cfg?.operations?.unAuthorize) {
await performRequest({
config: cfg,
opName: 'unAuthorize',
inputs: {},
user,
});
}
user.accessToken = '';
user.refreshToken = '';
await user.save();
return {
successful: true,
returnMessage: {
messageType: 'success',
message: 'Logged out',
ttl: 1000
}
};
}
async function findContact({ user, authHeader, phoneNumber, overridingFormat, isExtension, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.findContact) {
return { successful: true, matchedContactInfo: [] };
}
let formattedPhoneNumber = phoneNumber.replace(' ', '+')
const parsedPhoneNumber = parsePhoneNumber(formattedPhoneNumber);
const response = await performRequest({
config: cfg,
opName: 'findContact',
inputs: { phoneNumber, parsedPhoneNumber, overridingFormat, isExtension },
user,
authHeader
});
const matchedContactInfo = mapFindContactResponse({ config: cfg, response });
return {
successful: true,
matchedContactInfo,
returnMessage: {
messageType: 'success',
message: `Found ${matchedContactInfo.length} contacts`,
ttl: 3000
}
};
}
async function createContact({ user, authHeader, phoneNumber, newContactName, newContactType, additionalSubmission, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.createContact) {
return { contactInfo: null, returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
const response = await performRequest({
config: cfg,
opName: 'createContact',
inputs: { phoneNumber, newContactName, newContactType, additionalSubmission },
user,
authHeader
});
const map = cfg.operations.createContact.responseMapping || {};
const responseCtx = { body: response.data };
const contactInfo = map.idPath ? {
id: getByPath(responseCtx, map.idPath || 'body.id'),
name: getByPath(responseCtx, map.namePath || 'body.name'),
type: getByPath(responseCtx, map.typePath || 'body.type') || 'Contact',
} : null;
return { contactInfo, returnMessage: { message: 'Contact created', messageType: 'success', ttl: 2000 } };
}
async function findContactWithName({ user, authHeader, name, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.findContactWithName) {
return { successful: true, matchedContactInfo: [] };
}
const response = await performRequest({
config: cfg,
opName: 'findContactWithName',
inputs: { name },
user,
authHeader
});
const matchedContactInfo = mapFindContactResponse({ config: cfg, response });
return {
successful: true,
matchedContactInfo,
returnMessage: {
messageType: 'success',
message: `Found ${matchedContactInfo.length} contacts`,
ttl: 3000
}
};
}
function getLogFormatType(platform, proxyConfig) {
return proxyConfig ? proxyConfig.meta?.logFormat : 'custom';
}
async function createCallLog({
user,
contactInfo,
authHeader,
callLog,
note,
additionalSubmission,
aiNote,
transcript,
ringSenseTranscript = '',
ringSenseSummary = '',
ringSenseAIScore = '',
ringSenseBulletedSummary = '',
ringSenseLink = '',
composedLogDetails,
hashedAccountId,
isFromSSCL,
proxyConfig = null,
}) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg || !cfg.operations?.createCallLog) {
return { logId: undefined, returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
const response = await performRequest({
config: cfg,
opName: 'createCallLog',
inputs: {
contactInfo,
callLog,
note,
additionalSubmission,
aiNote,
transcript,
composedLogDetails,
hashedAccountId,
isFromSSCL,
subject: callLog.customSubject ?? `${callLog.direction} Call ${callLog.direction === 'Outbound' ? 'to' : 'from'} ${contactInfo.name}`,
startTime: moment(callLog.startTime).utc().toISOString(),
endTime: moment(callLog.startTime).utc().add(callLog.duration, 'seconds').toISOString(),
ringSenseTranscript,
ringSenseSummary,
ringSenseAIScore,
ringSenseBulletedSummary,
ringSenseLink,
},
user,
authHeader
});
const { logId } = mapCreateCallLogResponse({ config: cfg, response });
return {
logId,
returnMessage: {
message: 'Call logged',
messageType: 'success',
ttl: 2000
}
};
}
async function getCallLog({ user, callLogId, contactId, authHeader, proxyConfig = null }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg || !cfg.operations?.getCallLog) {
return { callLogInfo: null, returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
const response = await performRequest({
config: cfg,
opName: 'getCallLog',
inputs: { thirdPartyLogId: callLogId, contactId },
user,
authHeader
});
const mapped = mapGetCallLogResponse({ config: cfg, response });
return Object.assign(mapped, { returnMessage: { message: 'Call log fetched.', messageType: 'success', ttl: 3000 } });
}
async function updateCallLog({
user,
existingCallLog,
authHeader,
recordingLink,
recordingDownloadLink,
subject,
note,
startTime,
duration,
result,
aiNote,
transcript,
legs,
ringSenseTranscript = '',
ringSenseSummary = '',
ringSenseAIScore = '',
ringSenseBulletedSummary = '',
ringSenseLink = '',
additionalSubmission,
composedLogDetails,
existingCallLogDetails,
hashedAccountId,
isFromSSCL,
proxyConfig = null,
}) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg || !cfg.operations?.updateCallLog) {
return { returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
await performRequest({
config: cfg,
opName: 'updateCallLog',
inputs: {
thirdPartyLogId: existingCallLog?.thirdPartyLogId,
existingCallLog,
recordingLink,
recordingDownloadLink,
subject,
note,
startTime: moment(startTime).utc().toISOString(),
endTime: moment(startTime).utc().add(duration, 'seconds').toISOString(),
duration,
result,
aiNote,
transcript,
legs,
additionalSubmission,
composedLogDetails,
existingCallLogDetails,
hashedAccountId,
isFromSSCL,
ringSenseTranscript,
ringSenseSummary,
ringSenseAIScore,
ringSenseBulletedSummary,
ringSenseLink,
},
user,
authHeader
});
return {
updatedNote: null,
returnMessage: {
message: 'Call log updated.',
messageType: 'success',
ttl: 3000
}
};
}
async function upsertCallDisposition({ user, existingCallLog, authHeader, dispositions, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.upsertCallDisposition) {
return { returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
await performRequest({
config: cfg,
opName: 'upsertCallDisposition',
inputs: { existingCallLog, dispositions, thirdPartyLogId: existingCallLog?.thirdPartyLogId },
user,
authHeader
});
return { logId: existingCallLog.thirdPartyLogId, returnMessage: { message: 'Disposition updated', messageType: 'success', ttl: 2000 } };
}
async function createMessageLog({ user, contactInfo, authHeader, message, additionalSubmission, recordingLink, faxDocLink, faxDownloadLink, imageLink, videoLink, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.createMessageLog) {
return { logId: undefined, returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
const response = await performRequest({
config: cfg,
opName: 'createMessageLog',
inputs: {
contactInfo,
message,
additionalSubmission,
recordingLink,
faxDocLink,
faxDownloadLink,
imageLink,
videoLink,
creationTime: moment(message.creationTime).utc().toISOString(),
},
user,
authHeader
});
const map = cfg.operations.createMessageLog.responseMapping || {};
const responseCtx = { body: response.data };
const logId = getByPath(responseCtx, map.idPath || 'body.id');
return {
logId: logId ? String(logId) : undefined,
returnMessage: { message: 'Message logged', messageType: 'success', ttl: 1000 }
};
}
async function updateMessageLog({ user, contactInfo, existingMessageLog, message, authHeader, additionalSubmission, imageLink, videoLink, proxyConfig }) {
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(user?.platformAdditionalInfo?.proxyId));
if (!cfg.operations?.updateMessageLog) {
return { returnMessage: { message: 'Not supported', messageType: 'warning', ttl: 2000 } };
}
await performRequest({
config: cfg,
opName: 'updateMessageLog',
inputs: {
contactInfo,
existingMessageLog,
thirdPartyLogId: existingMessageLog?.thirdPartyLogId,
message,
additionalSubmission,
imageLink,
videoLink,
creationTime: moment(message.creationTime).utc().toISOString(),
},
user,
authHeader
});
return { returnMessage: { message: 'Message log updated', messageType: 'success', ttl: 3000 } };
}
async function getLicenseStatus({ userId, platform }) {
const user = await UserModel.findByPk(userId);
if (!user || !user.accessToken) {
return { isLicenseValid: false, licenseStatus: 'Invalid (User not found)', licenseStatusDescription: '' };
}
const proxyId = user.platformAdditionalInfo?.proxyId;
const cfg = await loadPlatformConfig(proxyId);
if (!cfg.operations?.getLicenseStatus) {
return { isLicenseValid: true, licenseStatus: 'Basic', licenseStatusDescription: '' };
}
const response = await performRequest({
config: cfg,
opName: 'getLicenseStatus',
inputs: { userId, platform },
user,
});
const map = cfg.operations.getLicenseStatus.responseMapping || {};
const responseCtx = { body: response.data };
const isLicenseValid = getByPath(responseCtx, map.isLicenseValidPath || 'body.isLicenseValid');
const licenseStatus = getByPath(responseCtx, map.licenseStatusPath || 'body.licenseStatus');
const licenseStatusDescription = getByPath(responseCtx, map.licenseStatusDescriptionPath || 'body.licenseStatusDescription');
return { isLicenseValid, licenseStatus, licenseStatusDescription };
}
exports.getAuthType = getAuthType;
exports.getOauthInfo = getOauthInfo;
exports.getBasicAuth = getBasicAuth;
exports.getUserInfo = getUserInfo;
exports.createCallLog = createCallLog;
exports.updateCallLog = updateCallLog;
exports.getCallLog = getCallLog;
exports.createMessageLog = createMessageLog;
exports.updateMessageLog = updateMessageLog;
exports.findContact = findContact;
exports.createContact = createContact;
exports.findContactWithName = findContactWithName;
exports.unAuthorize = unAuthorize;
exports.getLicenseStatus = getLicenseStatus;
exports.upsertCallDisposition = upsertCallDisposition;
exports.getUserList = getUserList;
exports.getLogFormatType = getLogFormatType;