X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Ftemplate%2Ftemplate-helper.js;h=2da05dfb928007fa1f080bb35c7ab4770262d9f2;hb=e23bda592175ae5ed772f366069ccfd2f60e1f70;hp=0ff90772ec7ebd2479344979b08e7d4c075fdb01;hpb=4807a77eca2858e8dc23d9ec2247a778814988d7;p=websub-hub
diff --git a/src/template/template-helper.js b/src/template/template-helper.js
index 0ff9077..2da05df 100644
--- a/src/template/template-helper.js
+++ b/src/template/template-helper.js
@@ -1,64 +1,14 @@
'use strict';
-/**
- * A bunch of shorthand to put together common parts of an HTML page.
- */
-
-/**
- * Some fields may have values outside normal dates, handle them here.
- * @param {Date} date
- * @param {String} otherwise
- */
-const dateOrNot = (date, otherwise) => {
- if (!date) {
- return otherwise;
- }
- if (typeof date === 'number') {
- date = new Date(date);
- }
- const dateMs = date.getTime();
- if (!Number.isFinite(dateMs)
- || dateMs == 0) {
- return otherwise;
- }
- return date.toString();
-};
-
-
-/**
- * Render a duration.
- * @param {Number} seconds
- * @returns {String}
- */
-const secondsToPeriod = (seconds) => {
- let value = seconds;
- const result = [];
-
- const nextResult = (factor, label) => {
- const r = factor ? value % factor : value;
- if (r) {
- result.push(`${r} ${label}${r != 1 ? 's' : ''}`);
- }
- value = factor ? Math.floor(value / factor) : value;
- }
-
- nextResult(60, 'second');
- nextResult(60, 'minute');
- nextResult(24, 'hour');
- nextResult(30, 'day');
- nextResult(undefined, 'month');
-
- result.reverse();
- return result.join(' ');
-};
-
+const { TemplateHelper } = require('@squeep/html-template-helper');
+const { Message } = require('../enum');
/**
* Render a topic as a row of details.
- * @param {Object} topic
- * @param {Object[]} subscribers
- * @param {Boolean} detailsLink
- * @returns {String}
+ * @param {object} topic topic
+ * @param {object[]} subscribers subscribers
+ * @param {boolean} detailsLink link to details
+ * @returns {string} html
*/
function renderTopicRow(topic, subscribers, detailsLink = true) {
if (!topic) {
@@ -69,17 +19,17 @@ function renderTopicRow(topic, subscribers, detailsLink = true) {
return `
${detailsLink ? '' : ''}${topic.url}${detailsLink ? '' : ''} |
${subscribers.length} |
- ${dateOrNot(topic.created, 'Unknown')} |
- ${secondsToPeriod(topic.leaseSecondsPreferred)} |
- ${secondsToPeriod(topic.leaseSecondsMin)} |
- ${secondsToPeriod(topic.leaseSecondsMax)} |
+ ${TemplateHelper.dateFormat(topic.created, Message.EndOfTime, Message.BeginningOfTime, Message.Unknown)} |
+ ${TemplateHelper.secondsToPeriod(topic.leaseSecondsPreferred)} |
+ ${TemplateHelper.secondsToPeriod(topic.leaseSecondsMin)} |
+ ${TemplateHelper.secondsToPeriod(topic.leaseSecondsMax)} |
${topic.publisherValidationUrl ? topic.publisherValidationUrl : 'None'} |
${topic.isActive} |
${topic.isDeleted} |
- ${dateOrNot(topic.lastPublish, 'Never')} |
- ${dateOrNot(topic.contentFetchNextAttempt, 'Next Publish')} |
+ ${TemplateHelper.dateFormat(topic.lastPublish, Message.EndOfTime, Message.Never, Message.Never)} |
+ ${TemplateHelper.dateFormat(topic.contentFetchNextAttempt, Message.NextPublish, Message.Pending, Message.NextPublish)} |
${topic.contentFetchAttemptsSinceSuccess} |
- ${dateOrNot(topic.contentUpdated, 'Never')} |
+ ${TemplateHelper.dateFormat(topic.contentUpdated, Message.EndOfTime, Message.Never, Message.Never)} |
${topic.contentType} |
${topic.id} |
`;
@@ -88,7 +38,7 @@ function renderTopicRow(topic, subscribers, detailsLink = true) {
/**
* Render the header row for topic details.
- * @returns {String}
+ * @returns {string} html
*/
function renderTopicRowHeader() {
return `
@@ -106,15 +56,15 @@ function renderTopicRowHeader() {
Content Fetch Failures |
Content Updated |
Content Type |
- ID |
+ Internal Id |
`;
}
/**
* Render a subscription as a row of details.
- * @param {Object} subscription
- * @returns {String}
+ * @param {object} subscription subscription
+ * @returns {string} html
*/
function renderSubscriptionRow(subscription) {
if (!subscription) {
@@ -123,17 +73,17 @@ function renderSubscriptionRow(subscription) {
`;
}
return `
- ${subscription.callback} |
- ${dateOrNot(subscription.created, 'Unknown')} |
- ${dateOrNot(subscription.verified, 'Never')} |
- ${dateOrNot(subscription.expires, 'Never')} |
+ ${subscription.callback} |
+ ${TemplateHelper.dateFormat(subscription.created, Message.EndOfTime, Message.BeginningOfTime, Message.Unknown)} |
+ ${TemplateHelper.dateFormat(subscription.verified, Message.EndOfTime, Message.Never, Message.Never)} |
+ ${TemplateHelper.dateFormat(subscription.expires, Message.Never, Message.BeginningOfTime, Message.Never)} |
${!!subscription.secret} |
${subscription.signatureAlgorithm} |
${subscription.httpRemoteAddr} |
${subscription.httpFrom} |
- ${dateOrNot(subscription.contentDelivered, 'Never')} |
+ ${TemplateHelper.dateFormat(subscription.contentDelivered, Message.EndOfTime, Message.Never, Message.Never)} |
${subscription.deliveryAttemptsSinceSuccess} |
- ${dateOrNot(subscription.deliveryNextAttempt, 'Next Publish')} |
+ ${TemplateHelper.dateFormat(subscription.deliveryNextAttempt, Message.EndOfTime, Message.NextPublish, Message.NextPublish)} |
${subscription.id} |
`;
}
@@ -141,7 +91,7 @@ function renderSubscriptionRow(subscription) {
/**
* Render a row of headers for subscription details.
- * @returns {String}
+ * @returns {string} html
*/
function renderSubscriptionRowHeader() {
return `
@@ -156,141 +106,61 @@ function renderSubscriptionRowHeader() {
Content Delivered |
Content Delivery Failures |
Next Delivery |
- ID |
+ Internal Id |
`;
}
/**
- * Render the preamble for an HTML page, up through body.
- * @param {Number} pagePathLevel number of paths below root this page is
- * @param {String} pageTitle
- * @param {String[]} headElements
- * @returns
+ * Escape some xml things in strings.
+ * @param {string} string string to escape
+ * @returns {string} escaped
*/
-function htmlHead(pagePathLevel, pageTitle, headElements = []) {
- const rootPathPfx = '../'.repeat(pagePathLevel);
- return `
-
-
- ` +
- headElements.map((e) => `${' '.repeat(2)}${e}`).join('\n') + `
- ${pageTitle}
-
-
- `;
-}
-
-
-/**
- * Closes remainder of HTML page body.
- * @returns {String}
- */
-function htmlTail() {
- return `
-`;
-}
-
-
-/**
- * Render a navigation link for the header section.
- * @param {Object} nav
- * @param {String} nav.href
- * @param {String} nav.class
- * @param {String} nav.text
- * @returns {String}
- */
-function renderNavLink(nav) {
- return `
- ${nav.text}
-`;
-}
-
-
-/**
- * Render the navigation header, and open the main section.
- * @param {String} pageTitle
- * @param {Object[]} navLinks
- * @returns {String}
- */
-function htmlHeader(pageTitle, navLinks = []) {
- return `
- ${pageTitle}
-
-
- `;
+function xmlEscape(string) {
+ if (typeof string === 'number') {
+ return string;
+ }
+ if (typeof string !== 'string') {
+ return undefined;
+ }
+ // eslint-disable-next-line security/detect-object-injection
+ return string.replace(/[<>&'"]/, (c) => ({
+ '<': '<',
+ '>': '>',
+ '&': '&',
+ '\'': ''',
+ '"': '"',
+ }[c]));
}
/**
- * Close the main section and finish off with boilerplate.
- * @param {String[]} footerEntries
- * @returns {String}
+ * Add common site links to navigation header.
+ * @param {number} pagePathLevel depth from root
+ * @param {object} ctx context
+ * @param {object} options options
*/
-function htmlFooter(footerEntries = []) {
- return `
- `;
-}
-
+function navLinks(pagePathLevel, ctx, options) {
+ if (!options.navLinks) {
+ options.navLinks = [];
+ }
+ const rootPath = '../'.repeat(pagePathLevel);
-/**
- * Render all parts of an HTML page. Adds user logout nav link automatically.
- * @param {Object} ctx
- * @param {Number} pagePathLevel
- * @param {String} pageTitle
- * @param {String[]} headElements
- * @param {Object[]} navLinks
- * @param {String[]} main
- * @param {String[]} footerEntries
- * @returns {String}
- */
-function htmlTemplate(ctx, pagePathLevel, pageTitle, headElements = [], navLinks = [], main = [], footerEntries = []) {
- const user = (ctx && ctx.session && ctx.session.authenticatedProfile) || (ctx && ctx.session && ctx.session.authenticatedIdentifier);
- if (user) {
- let logoutPath;
- if (pagePathLevel > 0) {
- logoutPath = `${'../'.repeat(pagePathLevel - 1)}`;
- } else {
- logoutPath = 'admin/';
- }
- navLinks.push({
- text: `Logout (${user})`,
- href: `${logoutPath}logout`,
+ if (options.pageIdentifier !== 'admin') {
+ options.navLinks.push({
+ text: 'Admin',
+ href: `${rootPath}admin/`,
});
}
- return [
- htmlHead(pagePathLevel, pageTitle, headElements),
- htmlHeader(pageTitle, navLinks),
- ...main,
- htmlFooter(footerEntries),
- htmlTail(),
- ].join('\n');
}
-module.exports = {
- dateOrNot,
- secondsToPeriod,
- htmlHeader,
- htmlFooter,
- htmlHead,
- htmlTail,
- renderNavLink,
+module.exports = Object.assign(Object.create(TemplateHelper), {
+ navLinks,
+ xmlEscape,
renderTopicRowHeader,
renderTopicRow,
renderSubscriptionRowHeader,
renderSubscriptionRow,
- htmlTemplate,
-};
\ No newline at end of file
+});