UNPKG

apostrophe

Version:
107 lines (100 loc) 2.96 kB
// Implements "soft redirects." When a 404 is about to occur, Apostrophe will // look for a page or piece that has been associated with that URL in the past, // and redirect if there is one. This only comes into play if a 404 is about to // occur. // // ## Options // // ### `enable` // // Set this option explicitly to `false` to shut off this feature. // // ### `statusCode` // // Set this option to return another HTTP status code when redirecting. You may // use e.g. HTTP 301 for permanent redirects. Defaults to HTTP 302. // // For example in your `app.js` module configuration: // // ```javascript // '@apostrophecms/soft-redirect': { // statusCode: 301 // } // ``` const parseurl = require('parseurl'); module.exports = { async init(self) { self.options.statusCode = self.options.statusCode || 302; if (self.options.enable === false) { return; } if (self.options.enable === false) { return; } await self.createIndexes(); }, handlers(self) { return { '@apostrophecms/page:notFound': { async notFoundRedirect(req) { // Save the raw, encoded path, no change here, only the var name const rawPathname = parseurl.original(req).pathname; // URL decode the pathname for matching historic URLs // so that e.g. accents, Cyrillic, and other non-ASCII characters // are properly handled. const urlPathname = decodeURI(rawPathname); const doc = await self.apos.doc .find(req, { historicUrls: { $in: [ urlPathname ] } }) .sort({ updatedAt: -1 }) .toObject(); if (!(doc && doc._url)) { return; } if (self.local(doc._url) !== urlPathname) { req.statusCode = self.options.statusCode; req.redirect = doc._url; } } }, '@apostrophecms/page:beforeSend': { async updateHistoricUrls(req) { let docs = []; if (req.data.page) { docs.push(req.data.page); } if (req.data.piece) { docs.push(req.data.piece); } docs = docs.filter(function (doc) { if (doc._url) { return !(doc.historicUrls || []).includes(self.local(doc._url)); } else { return false; } }); for (const doc of docs) { await self.apos.doc.db.updateOne( { _id: doc._id }, { $addToSet: { historicUrls: self.local(doc._url) } } ); } } } }; }, methods(self) { return { async createIndexes() { return self.apos.doc.db.createIndex({ historicUrls: 1 }); }, // Remove any protocol, `//` and host/port/auth from URL local(url) { return url.replace(/^(https?:)?\/\/[^/]+/, ''); } }; } };