Source: controllers/Feeds.js

/**
 * API controller for feed support.
 * @module controllers/feeds
 * @license MIT
 * @author Kai KRETSCHMANN <kai@kretschmann.consulting>
 */

const PackagesService = require('../service/PackagesService');

const log4js = require('log4js');
const logger = log4js.getLogger();
logger.level = process.env.LOGLEVEL || /* istanbul ignore next */ 'warn'; // LCOV_EXCL_LINE

const Feed = require('feed').Feed;
const maxFeedItems = 25;
const maxFeedAge = 30;
const sortItemFeed = 'tsupdated';
const sortDirectionFeed = 'down';

const API_BASE_URL = 'https://api.binarytransparency.net/v1/';
const WEB_URL = 'https://bintra.directory/';
const MY_NAME = 'Kai KRETSCHMANN';
const MY_EMAIL = 'kai@kretschmann.consulting';
const MY_WEB_URL = 'https://kai.kretschmann.consulting';

/**
 * generate common meta data object..
 * @function getInitialFeed
 * @private
 */
function getInitialFeed () {
  const myfeed = new Feed({
    title: 'Binary Transparency Directory',
    description: 'Feed for hash code monitoring',
    id: WEB_URL,
    link: WEB_URL,
    language: 'en', // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
    image: WEB_URL + 'image.png',
    favicon: WEB_URL + 'favicon.ico',
    copyright: 'All rights reserved 2021, ' + MY_NAME,
    updated: new Date(),
    generator: 'Feed for bintra', // optional, default = 'Feed for Node.js'
    feedLinks: {
      json: API_BASE_URL + 'feed.json',
      rss: API_BASE_URL + 'feed.rss',
      atom: API_BASE_URL + 'feed.atom'
    },
    author: {
      name: MY_NAME,
      email: MY_EMAIL,
      link: MY_WEB_URL
    }
  });

  myfeed.addCategory('Technology');
  myfeed.addContributor({
    name: MY_NAME,
    email: MY_EMAIL,
    link: MY_WEB_URL
  });

  return myfeed;
}

/**
 * Show single entry data.
 * @function createContent
 * @private
 */
function createContent (entry) {
  return `Archive ${entry.name}, version ${entry.version} for ${entry.arch}, ${entry.family} with hash ${entry.hash}`;
}

/**
 * Reply on error.
 * @function replyWithError
 * @private
 */
function replyWithError (res, payload) {
  res.writeHead(500, { 'Content-Type': 'text/plain' });
  return res.end('error ' + payload);
}

/**
 * Show feed data in wanted format.
 * @function feedRss
 * @private
 */
function feedRss (res) {
  const rssfeed = getInitialFeed();

  PackagesService.listPackages(0, maxFeedItems, sortItemFeed, sortDirectionFeed, maxFeedAge)
    .then(function (items) {
      items.forEach(function (entry) {
        const myid = entry._id;
        rssfeed.addItem({
          title: entry.name,
          id: API_BASE_URL + 'package/' + myid,
          link: WEB_URL + 'details/?id=' + myid,
          description: entry.name,
          date: entry.tsupdated || new Date(),
          content: createContent(entry)
        });
      });
      res.writeHead(200, {
        'Content-Type': 'application/rss+xml'
      });
      return res.end(rssfeed.rss2());
    })
    .catch(function (payload) {
      return replyWithError(res, payload); // LCOV_EXCL_LINE
    });
}

/**
 * Show feed data in wanted format.
 * @function feedAtom
 * @private
 */
function feedAtom (res) {
  const atomfeed = getInitialFeed();

  PackagesService.listPackages(0, maxFeedItems, sortItemFeed, sortDirectionFeed, maxFeedAge)
    .then(function (items) {
      items.forEach(function (entry) {
        const myid = entry._id;
        atomfeed.addItem({
          title: entry.name,
          link: API_BASE_URL + 'package/' + myid,
          description: entry.name,
          date: entry.tsupdated || new Date(),
          content: createContent(entry)
        });
      });
      res.writeHead(200, {
        'Content-Type': 'application/rss+xml'
      });
      return res.end(atomfeed.atom1());
    })
    .catch(function (payload) {
      return replyWithError(res, payload); // LCOV_EXCL_LINE
    });
}

/**
 * Show feed data in wanted format.
 * @function feedJson
 * @private
 */
function feedJson (res) {
  const jsonfeed = getInitialFeed();

  PackagesService.listPackages(0, maxFeedItems, sortItemFeed, sortDirectionFeed, maxFeedAge)
    .then(function (items) {
      items.forEach(function (entry) {
        const myid = entry._id;
        jsonfeed.addItem({
          title: entry.name,
          id: entry._id,
          link: API_BASE_URL + 'package/' + myid,
          description: entry.name,
          date: entry.tsupdated || new Date(),
          content: createContent(entry)
        });
      });
      res.writeHead(200, {
        'Content-Type': 'application/json'
      });
      return res.end(jsonfeed.json1());
    })
    .catch(function (payload) {
      return replyWithError(res, payload); // LCOV_EXCL_LINE
    });
}

/**
 * Show feed data in wanted format.
 * @function bintraFeed
 * @public
 */
module.exports.bintraFeed = function bintraFeed (_req, res, _next, type) {
  switch (type) {
    case 'rss':
      feedRss(res);
      break;
    case 'atom':
      feedAtom(res);
      break;
    case 'json':
      feedJson(res);
      break;
    default:
      logger.error('Wrong type ' + type);
      replyWithError(res, 'Wrong type');
      break;
  }
};