UNPKG

@sava.team/broid-messenger

Version:

Convert Facebook Messenger messages into Activity Streams 2 with Broid Integration

199 lines (198 loc) 8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const broid_schemas_1 = require("@sava.team/broid-schemas"); const broid_utils_1 = require("@sava.team/broid-utils"); const Promise = require("bluebird"); const R = require("ramda"); const uuid = require("uuid"); class Parser { constructor(serviceName, serviceID, logLevel) { this.serviceID = serviceID; this.generatorName = serviceName; this.logger = new broid_utils_1.Logger('parser', logLevel); } validate(event) { this.logger.debug('Validation process', { event }); const parsed = broid_utils_1.cleanNulls(event); if (!parsed || R.isEmpty(parsed)) { return Promise.resolve(null); } if (!parsed.type) { this.logger.debug('Type not found.', { parsed }); return Promise.resolve(null); } return broid_schemas_1.default(parsed, 'activity') .then(() => parsed) .catch(err => { this.logger.error(err); return null; }); } parse(event) { this.logger.debug('Parse process', { event }); const normalized = broid_utils_1.cleanNulls(event); if (!normalized || R.isEmpty(normalized)) { return Promise.resolve(null); } const activitystreams = this.createActivityStream(normalized); activitystreams.actor = { id: R.path(['authorInformation', 'id'], normalized), name: broid_utils_1.concat([ R.path(['authorInformation', 'first_name'], normalized), R.path(['authorInformation', 'last_name'], normalized) ]), type: 'Person' }; if (normalized.pageId) { activitystreams.actor.botId = normalized.pageId; } activitystreams.target = { id: normalized.channel, name: normalized.channel, type: 'Person' }; return Promise.map(normalized.attachments, attachment => this.parseAttachment(attachment)) .then(R.reject(R.isNil)) .then(attachments => { const places = R.filter(attachment => attachment.type === 'Place', attachments); const objectID = normalized.mid || this.createIdentifier(); if (R.length(places) === 1) { activitystreams.object = places[0]; activitystreams.object.id = objectID; } else if (R.length(attachments) === 1) { const attachment = attachments[0]; activitystreams.object = { id: objectID, type: attachment.type, url: attachment.url }; if (attachment.mediaType) { activitystreams.object.mediaType = attachment.mediaType; } } else if (R.length(attachments) > 1) { activitystreams.object = { attachment: attachments, content: normalized.content || '', id: objectID, type: 'Note' }; } else if (R.path(['quickReply', 'payload'], normalized)) { activitystreams.object = { content: R.path(['quickReply', 'payload'], normalized), id: objectID, name: normalized.content || '', type: 'Note' }; } return activitystreams; }) .then(as2 => { if (!as2.object && !R.isEmpty(normalized.content)) { as2.object = { content: normalized.content, id: normalized.mid || this.createIdentifier(), type: 'Note' }; } if (normalized.title) { as2.object.name = normalized.title; } return as2; }); } normalize(event) { var _a; this.logger.debug('Event received to normalize'); const req = event.request; const body = req.body; const pageId = ((_a = body === null || body === void 0 ? void 0 : body.entry[0]) === null || _a === void 0 ? void 0 : _a.id) || null; if (!body || R.isEmpty(body)) { return Promise.resolve(null); } const messages = R.map((entry) => R.map((data) => { if (data.message || data.postback) { if (data.postback) { return { pageId, attachments: [], author: data.sender.id, authorInformation: {}, channel: data.sender.id, content: data.postback.payload || null, createdTimestamp: data.timestamp, mid: data.timestamp.toString(), quickReply: [], seq: data.timestamp.toString(), title: data.postback.title || null }; } else { return { pageId, attachments: data.message.attachments || [], author: data.sender.id, authorInformation: {}, channel: data.sender.id, content: data.message.text || null, createdTimestamp: data.timestamp, mid: data.message.mid, quickReply: data.message.quick_reply || [], seq: data.message.seq }; } } return null; }, entry.messaging), body.entry); return Promise.resolve(R.reject(R.isNil)(R.flatten(messages))); } createIdentifier() { return uuid.v4(); } createActivityStream(normalized) { return { '@context': 'https://www.w3.org/ns/activitystreams', generator: { id: this.serviceID, name: this.generatorName, type: 'Service' }, published: normalized.createdTimestamp ? Math.floor(normalized.createdTimestamp / 1000) : Math.floor(Date.now() / 1000), type: 'Create' }; } parseAttachment(attachment) { var _a, _b, _c; let attachmentType = attachment.type || ''; attachmentType = attachmentType.toLowerCase(); if (['image', 'audio', 'video', 'file'].indexOf(attachmentType) > -1) { const url = R.path(['payload', 'url'], attachment); const a = { type: broid_utils_1.capitalizeFirstLetter(attachmentType === 'file' ? 'document' : attachmentType), content: (_c = (_b = (_a = url === null || url === void 0 ? void 0 : url.split('/')) === null || _a === void 0 ? void 0 : _a.reverse()[0]) === null || _b === void 0 ? void 0 : _b.split('?')[0]) !== null && _c !== void 0 ? _c : '', url }; return Promise.resolve(a).then(am => { if (am.url) { return broid_utils_1.fileInfo(am.url, this.logger).then(infos => R.assoc('mediaType', infos.mimetype, am)); } return null; }); } else if (attachmentType === 'location') { return Promise.resolve({ id: this.createIdentifier(), latitude: R.path(['payload', 'coordinates', 'lat'], attachment), longitude: R.path(['payload', 'coordinates', 'long'], attachment), name: attachment.title, type: 'Place' }); } return Promise.resolve(null); } } exports.Parser = Parser;