in src/directLine.ts [789:840]
private postMessageWithAttachments(message: Message) {
const { attachments } = message;
// We clean the attachments but making sure every attachment has unique name.
// If the file do not have a name, Chrome will assign "blob" when it is appended to FormData.
const attachmentNames: string[] = dedupeFilenames(attachments.map((media: Media) => media.name || 'blob'));
const cleansedAttachments = attachments.map((attachment: Media, index: number) => ({
...attachment,
name: attachmentNames[index]
}));
let formData: FormData;
// If we're not connected to the bot, get connected
// Will throw an error if we are not connected
return this.checkConnection(true)
.flatMap(_ => {
// To send this message to DirectLine we need to deconstruct it into a "template" activity
// and one blob for each attachment.
formData = new FormData();
formData.append('activity', new Blob([JSON.stringify({
...message,
// Removing contentUrl from attachment, we will send it via multipart
attachments: cleansedAttachments.map(({ contentUrl: string, ...others }) => ({ ...others }))
})], { type: 'application/vnd.microsoft.activity' }));
return Observable.from(cleansedAttachments, this.services.scheduler)
.flatMap((media: Media) =>
this.services.ajax({
method: "GET",
url: media.contentUrl,
responseType: 'arraybuffer'
})
.do(ajaxResponse =>
formData.append('file', new Blob([ajaxResponse.response], { type: media.contentType }), media.name)
)
)
.count()
})
.flatMap(_ =>
this.services.ajax({
method: "POST",
url: `${this.domain}/conversations/${this.conversationId}/upload?userId=${message.from.id}`,
body: formData,
timeout: this.timeout,
headers: {
...this.commonHeaders()
}
})
.map(ajaxResponse => ajaxResponse.response.id as string)
.catch(error => this.catchPostError(error))
)
.catch(error => this.catchPostError(error));
}