social-butterfly
Version:
Incorporate federated social network protocols easily. Used with Hello, world federated blog.
236 lines (215 loc) • 11.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GenericFeed = GenericFeed;
exports.default = void 0;
var _exceptions = require("./util/exceptions");
var _react = _interopRequireWildcard(require("react"));
var _url_factory = require("./util/url_factory");
var _server = require("react-dom/server");
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const LICENSES = {
'http://creativecommons.org/licenses/by/3.0/': {
name: 'Creative Commons Attribution 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by/3.0/88x31.png'
},
'http://creativecommons.org/licenses/by-sa/3.0/': {
name: 'Creative Commons Attribution-ShareAlike 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by-sa/3.0/88x31.png'
},
'http://creativecommons.org/licenses/by-nd/3.0/': {
name: 'Creative Commons Attribution-NoDerivs 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by-nd/3.0/88x31.png'
},
'http://creativecommons.org/licenses/by-nc/3.0/': {
name: 'Creative Commons Attribution-NonCommercial 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by-nc/3.0/88x31.png'
},
'http://creativecommons.org/licenses/by-nc-sa/3.0/': {
name: 'Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png'
},
'http://creativecommons.org/licenses/by-nc-nd/3.0/': {
name: 'Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License',
img: 'https://i.creativecommons.org/l/by-nc-nd/3.0/88x31.png'
},
'http://purl.org/atompub/license#unspecified': {
name: 'Simple Copyright',
img: ''
},
'http://www.opensource.org/licenses/mit-license.php': {
name: 'MIT License',
img: ''
}
};
var _default = options => async (req, res, next) => {
const contentOwner = await options.getLocalUser(req.query.resource, req);
if (!contentOwner) {
return res.sendStatus(404);
}
const feed = await options.getLocalLatestContent(req.query.resource, req);
let renderedTree = `<?xml version='1.0' encoding='UTF-8'?>` + (0, _server.renderToString)( /*#__PURE__*/_react.default.createElement(ContentFeed, {
req: req,
feed: feed,
contentOwner: contentOwner,
constants: options.constants
})); // XXX(mime): in the feeds I have some attributes that are `ref`. However, ref isn't allowed in React,
// so in the DOM they are `refXXX`. Return them to normal here, sigh.
renderedTree = renderedTree.replace(/refXXX="([^"]+)"/g, 'ref="$1"');
res.type('xml');
res.send(renderedTree);
};
exports.default = _default;
function ContentFeed({
feed,
contentOwner,
constants,
req
}) {
const updatedAt = feed.length && feed[0].updatedAt;
return /*#__PURE__*/_react.default.createElement(GenericFeed, {
contentOwner: contentOwner,
constants: constants,
req: req,
updatedAt: updatedAt
}, feed.map(content => /*#__PURE__*/_react.default.createElement(Entry, {
key: content.name,
content: content,
req: req
})));
}
function GenericFeed({
req,
children,
constants,
contentOwner,
updatedAt
}) {
if (!contentOwner) {
throw new _exceptions.HTTPError(404, undefined, 'feed: no content owner');
}
const feedUrl = (0, _url_factory.buildUrl)({
req,
pathname: req.originalUrl
});
const salmonUrl = (0, _url_factory.buildUrl)({
req,
pathname: '/api/social/salmon',
searchParams: {
resource: contentOwner.url
}
});
const namespaces = {
xmlLang: 'en-US',
xmlns: 'http://www.w3.org/2005/Atom',
'xmlns:activity': 'http://activitystrea.ms/spec/1.0/',
'xmlns:poco': 'http://portablecontacts.net/spec/1.0',
'xmlns:media': 'http://purl.org/syndication/atommedia',
'xmlns:thr': 'http://purl.org/syndication/thread/1.0'
};
return /*#__PURE__*/_react.default.createElement("feed", namespaces, /*#__PURE__*/_react.default.createElement("generator", {
uri: "https://github.com/mimecuvalo/helloworld"
}, "Hello, world."), /*#__PURE__*/_react.default.createElement("id", null, feedUrl), /*#__PURE__*/_react.default.createElement("title", null, contentOwner.title), /*#__PURE__*/_react.default.createElement("subtitle", null, "a hello world site."), /*#__PURE__*/_react.default.createElement("link", {
rel: "self",
href: feedUrl
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "alternate",
type: "text/html",
href: contentOwner.url
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "hub",
href: constants.webSubHub
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "salmon",
href: salmonUrl
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "http://salmon-protocol.org/ns/salmon-replies",
href: salmonUrl
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "http://salmon-protocol.org/ns/salmon-mention",
href: salmonUrl
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "license",
href: contentOwner.license
}), contentOwner.license ? /*#__PURE__*/_react.default.createElement("rights", null, contentOwner.license === 'http://purl.org/atompub/license#unspecified' ? `Copyright ${new Date().getFullYear()} by ${contentOwner.name}` : `${LICENSES[contentOwner.license]?.['name']}: ${contentOwner.license}`) : null, updatedAt ? /*#__PURE__*/_react.default.createElement("updated", null, new Date(updatedAt).toISOString()) : null, /*#__PURE__*/_react.default.createElement(Author, {
contentOwner: contentOwner
}), contentOwner.logo ? /*#__PURE__*/_react.default.createElement("logo", null, (0, _url_factory.buildUrl)({
req,
pathname: contentOwner.logo
})) : null, /*#__PURE__*/_react.default.createElement("icon", null, contentOwner.favicon ? (0, _url_factory.buildUrl)({
req,
pathname: contentOwner.favicon
}) : (0, _url_factory.buildUrl)({
req,
pathname: '/favicon.ico'
})), children);
}
const Author = ({
contentOwner
}) => /*#__PURE__*/_react.default.createElement("author", null, /*#__PURE__*/(0, _react.createElement)('activity:object-type', {}, `http://activitystrea.ms/schema/1.0/person`), /*#__PURE__*/_react.default.createElement("name", null, contentOwner.name), /*#__PURE__*/_react.default.createElement("uri", null, contentOwner.url), /*#__PURE__*/_react.default.createElement("email", null, contentOwner.email), /*#__PURE__*/(0, _react.createElement)('poco:preferredusername', {}, contentOwner.username), /*#__PURE__*/(0, _react.createElement)('poco:displayname', {}, contentOwner.name), /*#__PURE__*/(0, _react.createElement)('poco:emails', {}, [/*#__PURE__*/(0, _react.createElement)('poco:value', {
key: 'value'
}, contentOwner.email), /*#__PURE__*/(0, _react.createElement)('poco:type', {
key: 'type'
}, 'home'), /*#__PURE__*/(0, _react.createElement)('poco:primary', {
key: 'primary'
}, 'true')]), /*#__PURE__*/(0, _react.createElement)('poco:urls', {}, [/*#__PURE__*/(0, _react.createElement)('poco:value', {
key: 'value'
}, contentOwner.url), /*#__PURE__*/(0, _react.createElement)('poco:type', {
key: 'type'
}, 'profile'), /*#__PURE__*/(0, _react.createElement)('poco:primary', {
key: 'primary'
}, 'true')]));
function Entry({
content,
req
}) {
const statsImgSrc = (0, _url_factory.buildUrl)({
req,
pathname: '/api/stats',
searchParams: {
resource: content.url
}
});
const statsImg = `<img src="${statsImgSrc}" />`;
const absoluteUrlReplacement = (0, _url_factory.buildUrl)({
req,
pathname: '/resource'
}); // TODO(mime): this replacement is nite-lite specific...
const html = '<![CDATA[' + content.view.replace(/(['"])\/resource/gm, `$1${absoluteUrlReplacement}`) + statsImg + ']]>';
const repliesUrl = (0, _url_factory.buildUrl)({
pathname: '/api/social/comments',
searchParams: {
resource: content.url
}
});
const repliesAttribs = {
'thr:count': content.comments_count,
'thr:updated': new Date(content.comments_updated).toISOString()
};
return /*#__PURE__*/_react.default.createElement("entry", null, /*#__PURE__*/_react.default.createElement("title", null, content.title), /*#__PURE__*/_react.default.createElement("link", {
href: content.url
}), /*#__PURE__*/_react.default.createElement("id", null, content.url), /*#__PURE__*/_react.default.createElement("content", {
type: "html",
dangerouslySetInnerHTML: {
__html: html
}
}), /*#__PURE__*/_react.default.createElement("published", null, new Date(content.createdAt).toISOString()), /*#__PURE__*/_react.default.createElement("updated", null, new Date(content.updatedAt).toISOString()), /*#__PURE__*/(0, _react.createElement)('activity:verb', {}, `http://activitystrea.ms/schema/1.0/post`), content.section === 'comments' ?
/*#__PURE__*/
/* XXX(mime): we'll never get here currently because we never render main sections in our feed */
_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/(0, _react.createElement)('activity:object-type', {}, `http://activitystrea.ms/schema/1.0/comment`), content.thread ? /*#__PURE__*/(0, _react.createElement)('thr:in-reply-to', {
refXXX: content.thread
}) : null, content.thread_user ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("link", {
rel: "ostatus:attention",
href: content.thread_user
}), /*#__PURE__*/_react.default.createElement("link", {
rel: "mentioned",
href: content.thread_user
})) : null) : /*#__PURE__*/(0, _react.createElement)('activity:object-type', {}, `http://activitystrea.ms/schema/1.0/article`), content.comments_count ? /*#__PURE__*/_react.default.createElement("link", _extends({
rel: "replies",
type: "application/atom+xml",
href: repliesUrl
}, repliesAttribs)) : null);
}