184 lines
4.9 KiB
JavaScript
184 lines
4.9 KiB
JavaScript
|
/**
|
||
|
* @typedef {Object} ReferrerData
|
||
|
* @prop {string|null} [refSource]
|
||
|
* @prop {string|null} [refMedium]
|
||
|
* @prop {URL|null} [refUrl]
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Translates referrer info into Source and Medium
|
||
|
*/
|
||
|
class ReferrerTranslator {
|
||
|
/**
|
||
|
*
|
||
|
* @param {Object} deps
|
||
|
* @param {string} deps.siteUrl
|
||
|
* @param {string} deps.adminUrl
|
||
|
*/
|
||
|
constructor({adminUrl, siteUrl}) {
|
||
|
this.adminUrl = this.getUrlFromStr(adminUrl);
|
||
|
this.siteUrl = this.getUrlFromStr(siteUrl);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Calculate referrer details from history
|
||
|
* @param {import('./history').UrlHistoryArray} history
|
||
|
* @returns {ReferrerData|null}
|
||
|
*/
|
||
|
getReferrerDetails(history) {
|
||
|
if (history.length === 0) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
for (const item of history) {
|
||
|
const refUrl = this.getUrlFromStr(item.refUrl);
|
||
|
const refSource = item.refSource;
|
||
|
const refMedium = item.refMedium;
|
||
|
|
||
|
// If referrer is Ghost Explore
|
||
|
if (this.isGhostExploreRef({refUrl, refSource})) {
|
||
|
return {
|
||
|
refSource: 'Ghost Explore',
|
||
|
refMedium: 'Ghost Network',
|
||
|
refUrl: refUrl
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// If referrer is Ghost.org
|
||
|
if (this.isGhostOrgUrl(refUrl)) {
|
||
|
return {
|
||
|
refSource: 'Ghost.org',
|
||
|
refMedium: 'Ghost Network',
|
||
|
refUrl: refUrl
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// If referrer is Ghost Newsletter
|
||
|
if (this.isGhostNewsletter({refSource})) {
|
||
|
return {
|
||
|
refSource: refSource.replace(/-/g, ' '),
|
||
|
refMedium: 'Email',
|
||
|
refUrl: refUrl
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// If referrer is from query params
|
||
|
if (refSource) {
|
||
|
const urlData = this.getDataFromUrl() || {};
|
||
|
return {
|
||
|
refSource: refSource,
|
||
|
refMedium: refMedium || urlData?.medium || null,
|
||
|
refUrl: refUrl
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// If referrer is known external URL
|
||
|
// TODO: Use list of known external urls to fetch source/medium
|
||
|
if (refUrl && !this.isSiteDomain(refUrl)) {
|
||
|
const urlData = this.getDataFromUrl();
|
||
|
|
||
|
if (urlData) {
|
||
|
return {
|
||
|
refSource: urlData?.source,
|
||
|
refMedium: urlData?.medium,
|
||
|
refUrl: refUrl
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// Fetches referrer data from known external URLs
|
||
|
//TODO: Use list of known external urls to fetch source/medium
|
||
|
getDataFromUrl() {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Return URL object for provided URL string
|
||
|
* @param {string} url
|
||
|
* @returns {URL|null}
|
||
|
*/
|
||
|
getUrlFromStr(url) {
|
||
|
try {
|
||
|
return new URL(url);
|
||
|
} catch (e) {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Return whether the provided URL is a link to the site
|
||
|
* @param {URL} url
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
isSiteDomain(url) {
|
||
|
try {
|
||
|
if (this.siteUrl && this.siteUrl?.hostname === url?.hostname) {
|
||
|
if (url?.pathname?.startsWith(this.siteUrl?.pathname)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
} catch (e) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Return whether provided ref is a Ghost newsletter
|
||
|
* @param {Object} deps
|
||
|
* @param {string|null} deps.refSource
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
isGhostNewsletter({refSource}) {
|
||
|
// if refferer source ends with -newsletter
|
||
|
return refSource?.endsWith('-newsletter');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Return whether provided ref is a Ghost.org URL
|
||
|
* @param {URL|null} refUrl
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
isGhostOrgUrl(refUrl) {
|
||
|
return refUrl?.hostname === 'ghost.org';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Return whether provided ref is Ghost Explore
|
||
|
* @param {Object} deps
|
||
|
* @param {URL|null} deps.refUrl
|
||
|
* @param {string|null} deps.refSource
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
isGhostExploreRef({refUrl, refSource}) {
|
||
|
if (refSource === 'ghost-explore') {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (refUrl?.hostname
|
||
|
&& this.adminUrl?.hostname === refUrl?.hostname
|
||
|
&& refUrl?.pathname?.startsWith(this.adminUrl?.pathname)
|
||
|
) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (refUrl?.hostname === 'ghost.org' && refUrl?.pathname?.startsWith('/explore')) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = ReferrerTranslator;
|