social-butterfly
Version:
Incorporate federated social network protocols easily. Used with Hello, world federated blog.
145 lines (109 loc) • 4.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _activitystreams = require("./activitystreams");
var _cheerio = _interopRequireDefault(require("cheerio"));
var _draftJs = require("draft-js");
var _email = require("./email");
var _url_factory = require("./util/url_factory");
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
var _crawler = require("./util/crawler");
var _webmention = require("./webmention");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = options => async function syndicate(req, contentOwner, localContent, opt_remoteContent, opt_isComment) {
if (localContent.hidden) {
return;
}
await webSubPush(req, options, localContent);
await parseMentions(req, options, contentOwner, localContent, opt_remoteContent);
if (opt_isComment) {
const localContentUser = await options.getLocalUser(localContent.url, req);
(0, _email.comment)(req, opt_remoteContent.username, opt_remoteContent.comment_user, localContentUser.email, localContent.url, opt_remoteContent);
}
};
exports.default = _default;
function findMentionsInDraftJS(draftJsContent) {
const contentState = (0, _draftJs.convertFromRaw)(JSON.parse(draftJsContent));
return Object.keys(contentState.entityMap).map(key => contentState.getEntity(contentState.entityMap[key])).filter(entity => entity.type === 'mention' || entity.type === 'rsvp').map(entity => entity.data.mention.link);
}
async function parseMentions(req, options, contentOwner, content, opt_remoteContent) {
const remoteUsers = [];
const mentionedRemoteUsers = [];
async function addToUsersList(userRemote, threadUrl, shouldAddToMentions) {
if (!userRemote && threadUrl) {
const webpage = await (0, _crawler.fetchText)(threadUrl);
const $ = _cheerio.default.load(webpage);
let webmention_url = $('link[rel="webmention"]').attr('href');
webmention_url = (0, _url_factory.ensureAbsoluteUrl)(threadUrl, webmention_url); // TODO(mime): pretty funky smell. refactor.
if (webmention_url) {
userRemote = {
webmention_url
};
}
}
if (!userRemote || remoteUsers.find(el => el.profile_url === userRemote.profile_url)) {
return;
}
if (userRemote.salmon_url || userRemote.activitypub_inbox_url || userRemote.webmention_url) {
remoteUsers.push(userRemote);
shouldAddToMentions && mentionedRemoteUsers.push(userRemote);
}
} // Add user from original thread as mentioned user.
if (content.thread) {
const threadContent = await options.getRemoteContent(content.username, content.thread);
let threadUserRemote;
if (threadContent) {
threadUserRemote = await options.getRemoteUser(content.username, threadContent.from_user);
}
await addToUsersList(threadUserRemote, content.thread, true);
} // Find mentions in the text.
// TODO(mime): support @blah@blah.com
const mentions = content.content && findMentionsInDraftJS(content.content) || [];
for (const mention of mentions) {
const userRemote = await options.getRemoteUser(content.username, mention);
await addToUsersList(userRemote, undefined
/* threadUrl */
, true);
} // Find all users from the comments.
if (content.comments_count) {
const comments = await options.getRemoteCommentsOnLocalContent(content.url);
for (const comment of comments) {
const userRemote = await options.getRemoteUser(content.username, comment.from_user);
await addToUsersList(userRemote, undefined
/* threadUrl */
, false);
}
}
if (opt_remoteContent) {
// Find mentions in the comment text.
// TODO(mime): support @blah@blah.com
const mentions = opt_remoteContent.content && findMentionsInDraftJS(opt_remoteContent.content) || [];
for (const mention of mentions) {
const userRemote = await options.getRemoteUser(content.username, mention);
await addToUsersList(userRemote, undefined
/* threadUrl */
, true);
}
}
for (const userRemote of remoteUsers) {
if (userRemote.activitypub_inbox_url || userRemote.salmon_url) {
(0, _activitystreams.reply)(req, contentOwner, content, userRemote, mentionedRemoteUsers);
} else if (userRemote.webmention_url) {
(0, _webmention.reply)(req, contentOwner, content, userRemote, mentionedRemoteUsers);
}
}
}
async function webSubPush(req, options, content) {
try {
await (0, _nodeFetch.default)(options.constants.webSubHub, {
method: 'POST',
body: new URLSearchParams({
'hub.url': content.url,
'hub.mode': 'publish'
})
});
} catch (ex) {// Not a big deal if this fails.
}
}