UNPKG

social-butterfly

Version:

Incorporate federated social network protocols easily. Used with Hello, world federated blog.

236 lines (215 loc) 11.1 kB
"use strict"; 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); }