Skip to content

Commit

Permalink
feat: api to add attachments for mms (#743)
Browse files Browse the repository at this point in the history
* feat: support to add attachments for mms

* feat: api to send mms

* misc: use attachment.content

* feat: limit attachment mime
  • Loading branch information
embbnux authored Dec 4, 2023
1 parent 2401b09 commit 1699d58
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 54 deletions.
11 changes: 10 additions & 1 deletion docs/integration/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,17 +279,26 @@ document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-sms',
phoneNumber: `phone number`,
text: `your text`,
// attachments: [{
// name: 'test.txt',
// content: 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', // base64 encoded data URI
// }], // optional for sending MMS message with attachments
}]
}, '*');
```

If you are using Adapter JS way, just you can just call `RCAdapter.clickToSMS('phonenumber')`.
If you are using Adapter JS way, just you can just call `RCAdapter.clickToSMS('phonenumber', 'text')`.

### Auto-populate SMS conversation text

```js
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-auto-populate-conversation',
text: `your text`,
// attachments: [{
// name: 'test.png',
// content: 'data:image/png;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', // base64 encoded data URI. Limitation: https://developers.ringcentral.com/guide/messaging/sms/sending-images
// }], // optional for sending MMS message with attachments, supported from v1.10.0.
}, '*');
```

Expand Down
3 changes: 2 additions & 1 deletion src/lib/Adapter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,14 @@ class Adapter extends AdapterCore {
});
}

clickToSMS(phoneNumber, text, conversation) {
clickToSMS(phoneNumber, text, conversation, attachments = undefined) {
this.setMinimized(false);
this._postMessage({
type: 'rc-adapter-new-sms',
phoneNumber,
text,
conversation,
attachments,
});
}

Expand Down
118 changes: 118 additions & 0 deletions src/modules/Adapter/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {
messageIsTextMessage,
} from '@ringcentral-integration/commons/lib/messageHelper';

export function findExistedConversation(conversations, phoneNumber) {
return conversations.find((conversation) => {
if (!conversation.to || conversation.to.length > 1) {
return false;
}
if (!messageIsTextMessage(conversation)) {
return false;
}
if (conversation.direction === 'Inbound') {
return conversation.from && (
conversation.from.phoneNumber === phoneNumber ||
conversation.from.extensionNumber === phoneNumber
);
}
return conversation.to.find(
number => (
number.phoneNumber === phoneNumber ||
number.extensionNumber === phoneNumber
)
);
});
}

export function setOutputDeviceWhenCall(webphone, audioSettings) {
if (webphone._webphone) {
if (webphone._remoteVideo && webphone._remoteVideo.setSinkId) {
if (audioSettings.outputDeviceId === 'default') {
const defaultDevice = audioSettings.outputDevice;
const defaultDeviceLabel = defaultDevice.label;
const deviceLabel = defaultDeviceLabel.split(' - ')[1];
if (deviceLabel) {
const device = audioSettings.availableOutputDevices.find(
(device) => device.label === deviceLabel
);
if (device) {
webphone._remoteVideo.setSinkId(device.deviceId);
}
}
} else {
webphone._remoteVideo.setSinkId(audioSettings.outputDeviceId);
}
}
}
}

const SUPPORTED_MIME = [
'image/jpeg',
'image/png',
'image/bmp',
'image/gif',
'image/tiff',
'image/svg+xml',
'video/3gpp',
'video/mp4',
'video/mpeg',
'video/msvideo',
'audio/mpeg',
'text/vcard',
'application/zip',
'application/gzip',
'application/rtf'
];

function dataURLtoBlob(dataUrl) {
const arr = dataUrl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
if (!SUPPORTED_MIME.includes(mime)) {
console.warn('Unsupported mime type:', mime);
return null;
}
const bStr = atob(arr[1]);
let n = bStr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bStr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}

export function getValidAttachments(attachments = []) {
if (!attachments || !attachments.length) {
return [];
}
const validAttachments = [];
attachments.forEach((attachment) => {
if (!attachment || !attachment.name || !attachment.content) {
console.warn('Invalid attachment:', attachment);
return;
}
if (typeof attachment.name !== 'string') {
console.warn('Invalid attachment name:', attachment.name);
return;
}
// only support base64 url
if (
typeof attachment.content !== 'string' ||
attachment.content.indexOf('data:') !== 0 ||
attachment.content.indexOf(';base64,') === -1
) {
console.warn('Invalid attachment content:', attachment.content);
return;
}
const blob = dataURLtoBlob(attachment.content);
if (!blob) {
return;
}
validAttachments.push({
name: attachment.name,
file: blob,
size: blob.size,
});
});
return validAttachments;
}
78 changes: 26 additions & 52 deletions src/modules/Adapter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import {
import debounce from '@ringcentral-integration/commons/lib/debounce';
import { Module } from '@ringcentral-integration/commons/lib/di';
import ensureExist from '@ringcentral-integration/commons/lib/ensureExist';
import {
messageIsTextMessage,
} from '@ringcentral-integration/commons/lib/messageHelper';
import normalizeNumber
from '@ringcentral-integration/commons/lib/normalizeNumber';
import {
Expand Down Expand Up @@ -42,51 +39,11 @@ import {
import PopupWindowManager from '../../lib/PopupWindowManager';
import actionTypes from './actionTypes';
import getReducer from './getReducer';

function findExistedConversation(conversations, phoneNumber) {
return conversations.find((conversation) => {
if (!conversation.to || conversation.to.length > 1) {
return false;
}
if (!messageIsTextMessage(conversation)) {
return false;
}
if (conversation.direction === 'Inbound') {
return conversation.from && (
conversation.from.phoneNumber === phoneNumber ||
conversation.from.extensionNumber === phoneNumber
);
}
return conversation.to.find(
number => (
number.phoneNumber === phoneNumber ||
number.extensionNumber === phoneNumber
)
);
});
}

function setOutputDeviceWhenCall(webphone, audioSettings) {
if (webphone._webphone) {
if (webphone._remoteVideo && webphone._remoteVideo.setSinkId) {
if (audioSettings.outputDeviceId === 'default') {
const defaultDevice = audioSettings.outputDevice;
const defaultDeviceLabel = defaultDevice.label;
const deviceLabel = defaultDeviceLabel.split(' - ')[1];
if (deviceLabel) {
const device = audioSettings.availableOutputDevices.find(
(device) => device.label === deviceLabel
);
if (device) {
webphone._remoteVideo.setSinkId(device.deviceId);
}
}
} else {
webphone._remoteVideo.setSinkId(audioSettings.outputDeviceId);
}
}
}
}
import {
findExistedConversation,
setOutputDeviceWhenCall,
getValidAttachments,
} from './helper';

@Module({
name: 'Adapter',
Expand Down Expand Up @@ -306,13 +263,13 @@ export default class Adapter extends AdapterModuleCore {
}
break;
case 'rc-adapter-new-sms':
this._newSMS(data.phoneNumber, data.text, data.conversation);
this._newSMS(data.phoneNumber, data.text, data.conversation, data.attachments);
break;
case 'rc-adapter-new-call':
this._newCall(data.phoneNumber, data.toCall);
break;
case 'rc-adapter-auto-populate-conversation':
this._autoPopulateConversationText(data.text);
this._autoPopulateConversationText(data.text, data.attachments);
break;
case 'rc-adapter-control-call':
this._controlCall(data.callAction, data.callId, data.options);
Expand Down Expand Up @@ -897,7 +854,7 @@ export default class Adapter extends AdapterModuleCore {
}
}

_newSMS(phoneNumber, text, conversation) {
_newSMS(phoneNumber, text, conversation, attachments = null) {
if (!this._auth.loggedIn) {
return;
}
Expand All @@ -913,12 +870,18 @@ export default class Adapter extends AdapterModuleCore {
normalizedNumber,
);
}
const validAttachments = getValidAttachments(attachments);
if (existedConversation) {
this._router.push(`/conversations/${existedConversation.conversationId}`);
if (text && text.length > 0) {
this._conversations.loadConversation(existedConversation.conversationId);
this._conversations.updateMessageText(String(text));
}
if (validAttachments.length > 0) {
validAttachments.forEach((attachment) => {
this._conversations.addAttachment(attachment);
})
}
return;
}
this._router.push('/composeText');
Expand All @@ -928,6 +891,11 @@ export default class Adapter extends AdapterModuleCore {
if (text && text.length > 0) {
this._composeText.updateMessageText(String(text));
}
if (validAttachments.length > 0) {
validAttachments.forEach((attachment) => {
this._composeText.addAttachment(attachment);
});
}
}

_newCall(phoneNumber, toCall = false) {
Expand All @@ -948,13 +916,19 @@ export default class Adapter extends AdapterModuleCore {
}
}

_autoPopulateConversationText(text) {
_autoPopulateConversationText(text, attachments) {
if (!this._conversations.currentConversationId) {
return;
}
if (typeof text === 'string') {
this._conversations.updateMessageText(text);
}
const validAttachments = getValidAttachments(attachments);
if (validAttachments.length > 0) {
validAttachments.forEach((attachment) => {
this._conversations.addAttachment(attachment);
});
}
}

_isCallOngoing(phoneNumber) {
Expand Down

0 comments on commit 1699d58

Please sign in to comment.