UNPKG

@x3m-group/strapi-plugin-auto-links

Version:

Auto generate links for resources (self, canonical, alternates, ...)

146 lines (119 loc) 4.58 kB
import { ContentTypeConfig, PluginConfig } from './settings-service'; import { Event } from '@strapi/database/lib/lifecycles'; import { Schema } from '@strapi/strapi/lib/types/core/schemas'; import { Strapi } from '@strapi/strapi'; import { getPluginService } from '../utils/getPluginService'; import { join } from 'path'; export default ({ strapi }: { strapi: Strapi }) => { const settingsService = getPluginService(strapi, 'settingsService'); return { updateQueryFindOne(queryRequest: Event) { const buildConfig = settingsService.buildConfig() as PluginConfig; const contentType = buildConfig.contentTypes[queryRequest.model.uid] as ContentTypeConfig; if (!contentType) { return; } }, updateQueryFindMany(queryRequest: Event) { const buildConfig = settingsService.buildConfig() as PluginConfig; const contentType = buildConfig.contentTypes[queryRequest.model.uid] as ContentTypeConfig; if (!contentType) { return; } }, addLinksFindOne(event: Event & { result: any }) { const buildConfig = settingsService.buildConfig() as PluginConfig; const contentType = buildConfig.contentTypes[event.model.uid] as ContentTypeConfig; if (!contentType) { return; } addLinks(buildConfig, contentType, event.result); }, addLinksFindMany(event: Event & { result: any[] }) { const buildConfig = settingsService.buildConfig() as PluginConfig; const contentType = buildConfig.contentTypes[event.model.uid] as ContentTypeConfig; if (!contentType) { return; } event.result.map((item) => { addLinks(buildConfig, contentType, item); }); }, }; }; function addLinks(buildConfig: PluginConfig, contentType: Partial<ContentTypeConfig>, item: any) { if (!item) { return } const links: any = {}; if (contentType.self?.enabled || buildConfig.self.enabled) { links['self'] = buildSelfURL(buildConfig, contentType, item); } if (contentType.canonical?.enabled || buildConfig.canonical.enabled) { links['canonical'] = buildCanonicalURL(buildConfig, contentType, item); } if ((contentType.alternates?.enabled || buildConfig.alternates.enabled) && item.localizations?.length > 0) { const alternates: {}[] = []; item.localizations?.forEach((localization) => { const a = { locale: localization.locale, }; if (contentType.self?.enabled || buildConfig.self.enabled) { a['self'] = buildSelfURL(buildConfig, contentType, localization); } if (contentType.canonical?.enabled || buildConfig.canonical.enabled) { a['canonical'] = buildCanonicalURL(buildConfig, contentType, localization); } alternates.push(a); }); if (Object.keys(alternates).length > 0) { links['alternates'] = alternates; } } if (Object.keys(links).length > 0) { item.links = links; } } function buildSelfURL( buildConfig: PluginConfig, contentType: Partial<ContentTypeConfig>, item: any ) { const host = contentType.self?.host || buildConfig.self?.host || ''; const path = contentType.self?.path || buildConfig.self?.path || ''; return buildUrl(join(host, path), contentType.model, item); } function buildCanonicalURL( buildConfig: PluginConfig, contentType: Partial<ContentTypeConfig>, item: any ) { const host = contentType.canonical?.host || buildConfig.canonical?.host || ''; const path = contentType.canonical?.path || buildConfig.canonical?.path || ''; return buildUrl(join(host, path), contentType.model, item); } function buildUrl(url: string, model: Schema, item: any): string { // Helper function to retrieve deeply nested properties. const deepValue = (obj: any, path: string) => { return path.split('.').reduce((res, key) => (res || {})[key], obj); }; // Regex to find placeholders in curly braces. const regex = /\{([^\}]+)\}/g; // Replace each placeholder with the respective value from contentType or item. const finalUrl = url.replace(regex, (match, placeholder) => { // Check if the placeholder has a prefix "model." or "item." let replacement; if (placeholder.startsWith('model.')) { const modelPath = placeholder.slice(6); // Extract path without "model." prefix. replacement = deepValue(model, modelPath); } else if (placeholder.startsWith('item.')) { const itemPath = placeholder.slice(5); // Extract path without "item." prefix. replacement = deepValue(item, itemPath); } else { return match; // If no prefix, leave the placeholder unchanged. } // If the replacement is undefined, leave the placeholder unchanged. return replacement !== undefined ? replacement : match; }); return finalUrl; }