@sava.team/broid-messenger
Version:
Convert Facebook Messenger messages into Activity Streams 2 with Broid Integration
199 lines (198 loc) • 8 kB
JavaScript
"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;