mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 09:52:06 +03:00
abda6e6338
closes #10773 - The refactoring is a substitute for `urlService.utils` used previously throughout the codebase and now extracted into the separate module in Ghost-SDK - Added url-utils stubbing utility for test suites - Some tests had to be refactored to avoid double mocks (when url's are being reset inside of rested 'describe' groups)
140 lines
3.6 KiB
JavaScript
140 lines
3.6 KiB
JavaScript
const _ = require('lodash');
|
|
const debug = require('ghost-ignition').debug('services:url:urls');
|
|
const localUtils = require('../../lib/url-utils');
|
|
const common = require('../../lib/common');
|
|
|
|
/**
|
|
* This class keeps track of all urls in the system.
|
|
* Each resource has exactly one url. Each url is owned by exactly one url generator id.
|
|
* This is a connector for url generator and resources.
|
|
* Stores relative urls by default.
|
|
*
|
|
* We have to have a centralised place where we keep track of all urls, otherwise
|
|
* we will never know if we generate the same url twice. Furthermore, it's easier
|
|
* to ask a centralised class instance if you want a url for a resource than
|
|
* iterating over all url generators and asking for it.
|
|
* You can easily ask `this.urls[resourceId]`.
|
|
*/
|
|
class Urls {
|
|
constructor() {
|
|
this.urls = {};
|
|
}
|
|
|
|
/**
|
|
* @description Add a url to the system.
|
|
* @param {Object} options
|
|
*/
|
|
add(options) {
|
|
const url = options.url;
|
|
const generatorId = options.generatorId;
|
|
const resource = options.resource;
|
|
|
|
debug('cache', url);
|
|
|
|
if (this.urls[resource.data.id]) {
|
|
common.logging.error(new common.errors.InternalServerError({
|
|
message: 'This should not happen.',
|
|
code: 'URLSERVICE_RESOURCE_DUPLICATE'
|
|
}));
|
|
|
|
this.removeResourceId(resource.data.id);
|
|
}
|
|
|
|
this.urls[resource.data.id] = {
|
|
url: url,
|
|
generatorId: generatorId,
|
|
resource: resource
|
|
};
|
|
|
|
// @NOTE: Notify the whole system. Currently used for sitemaps service.
|
|
common.events.emit('url.added', {
|
|
url: {
|
|
relative: url,
|
|
absolute: localUtils.createUrl(url, true)
|
|
},
|
|
resource: resource
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @description Get url by resource id.
|
|
* @param {String} id
|
|
* @returns {Object}
|
|
*/
|
|
getByResourceId(id) {
|
|
return this.urls[id];
|
|
}
|
|
|
|
/**
|
|
* @description Get all urls by generator id.
|
|
* @param {String} generatorId
|
|
* @returns {Array}
|
|
*/
|
|
getByGeneratorId(generatorId) {
|
|
return _.reduce(Object.keys(this.urls), (toReturn, resourceId) => {
|
|
if (this.urls[resourceId].generatorId === generatorId) {
|
|
toReturn.push(this.urls[resourceId]);
|
|
}
|
|
|
|
return toReturn;
|
|
}, []);
|
|
}
|
|
|
|
/**
|
|
* @description Get by url.
|
|
*
|
|
* @NOTE:
|
|
* It's is in theory possible that:
|
|
*
|
|
* - resource1 -> /welcome/
|
|
* - resource2 -> /welcome/
|
|
*
|
|
* But depending on the routing registration, you will always serve e.g. resource1,
|
|
* because the router it belongs to was registered first.
|
|
*/
|
|
getByUrl(url) {
|
|
return _.reduce(Object.keys(this.urls), (toReturn, resourceId) => {
|
|
if (this.urls[resourceId].url === url) {
|
|
toReturn.push(this.urls[resourceId]);
|
|
}
|
|
|
|
return toReturn;
|
|
}, []);
|
|
}
|
|
|
|
/**
|
|
* @description Remove url.
|
|
* @param id
|
|
*/
|
|
removeResourceId(id) {
|
|
if (!this.urls[id]) {
|
|
return;
|
|
}
|
|
|
|
debug('removed', this.urls[id].url, this.urls[id].generatorId);
|
|
|
|
common.events.emit('url.removed', {
|
|
url: this.urls[id].url,
|
|
resource: this.urls[id].resource
|
|
});
|
|
|
|
delete this.urls[id];
|
|
}
|
|
|
|
/**
|
|
* @description Reset instance.
|
|
*/
|
|
reset() {
|
|
this.urls = {};
|
|
}
|
|
|
|
/**
|
|
* @description Soft reset instance.
|
|
*/
|
|
softReset() {
|
|
this.urls = {};
|
|
}
|
|
}
|
|
|
|
module.exports = Urls;
|