@webbycrown/strapi-advanced-sitemap 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ const PLUGIN_ID = 'strapi-advanced-sitemap';
4
+
5
+ const getManualSitemapService = () => strapi.plugin(PLUGIN_ID).service('service');
6
+
7
+ const getRequestOrigin = (ctx) => {
8
+ if (ctx.origin) {
9
+ return ctx.origin;
10
+ }
11
+
12
+ const protocol = ctx.request.protocol || 'http';
13
+ const host =
14
+ ctx.request.header['x-forwarded-host'] ||
15
+ ctx.request.header.host ||
16
+ (ctx.request.hostname ? `${ctx.request.hostname}` : 'localhost');
17
+
18
+ return `${protocol}://${host}`;
19
+ };
20
+
21
+ module.exports = {
22
+ async getOptions(ctx) {
23
+ const data = await strapi.entityService.findMany(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-option`);
24
+ const single = Array.isArray(data) ? data[0] : data;
25
+ ctx.body = single || {};
26
+ },
27
+
28
+ async putOptions(ctx) {
29
+ const body = ctx.request.body || {};
30
+ const data = await strapi.entityService.findMany(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-option`);
31
+ const single = Array.isArray(data) ? data[0] : data;
32
+ if (single && single.id) {
33
+ await strapi.entityService.update(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-option`, single.id, { data: body });
34
+ } else {
35
+ await strapi.entityService.create(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-option`, { data: body });
36
+ }
37
+ ctx.body = { ok: true };
38
+ },
39
+
40
+ async getManualSitemaps(ctx) {
41
+ const sitemaps = await getManualSitemapService().getManualSitemaps();
42
+ ctx.body = { sitemaps };
43
+ },
44
+
45
+ async putManualSitemaps(ctx) {
46
+ const payload = ctx.request.body || {};
47
+ const { sitemaps } = payload;
48
+
49
+ if (!Array.isArray(sitemaps)) {
50
+ ctx.throw(400, 'Invalid payload. Expected "sitemaps" to be an array.');
51
+ }
52
+
53
+ await getManualSitemapService().setManualSitemaps(sitemaps);
54
+
55
+ ctx.body = { ok: true };
56
+ },
57
+
58
+ async serveRootSitemap(ctx) {
59
+ const service = getManualSitemapService();
60
+ const [manualSitemaps, collectionConfigs, configuredBaseUrl] = await Promise.all([
61
+ service.getManualSitemaps(),
62
+ service.getCollectionConfigs(),
63
+ service.getConfiguredBaseUrl(),
64
+ ]);
65
+
66
+ const origin = getRequestOrigin(ctx);
67
+ const apiBaseUrl = `${origin}/api/${PLUGIN_ID}`;
68
+ const publicBaseUrl = service.resolveBaseUrl(configuredBaseUrl, origin);
69
+ const xml = service.buildRootSitemap(manualSitemaps, collectionConfigs, {
70
+ apiBaseUrl,
71
+ publicBaseUrl,
72
+ });
73
+
74
+ ctx.set('Content-Type', 'application/xml; charset=utf-8');
75
+ ctx.set('Cache-Control', 'no-store');
76
+ ctx.body = xml;
77
+ },
78
+
79
+ async serveManualSitemapIndex(ctx) {
80
+ const service = getManualSitemapService();
81
+ const [sitemaps, configuredBaseUrl] = await Promise.all([
82
+ service.getManualSitemaps(),
83
+ service.getConfiguredBaseUrl(),
84
+ ]);
85
+ const origin = getRequestOrigin(ctx);
86
+ const publicBaseUrl = service.resolveBaseUrl(configuredBaseUrl, origin);
87
+ const xml = service.buildManualSitemapIndex(sitemaps, publicBaseUrl);
88
+
89
+ ctx.set('Content-Type', 'application/xml; charset=utf-8');
90
+ ctx.set('Cache-Control', 'no-store');
91
+ ctx.body = xml;
92
+ },
93
+
94
+ async serveManualSitemapFile(ctx) {
95
+ const filenameParam = ctx.params.filename;
96
+ const filename = filenameParam ? decodeURIComponent(filenameParam) : '';
97
+ const service = getManualSitemapService();
98
+ const sitemaps = await service.getManualSitemaps();
99
+ const target = sitemaps.find((item) => item.filename === filename);
100
+
101
+ if (!target) {
102
+ return ctx.notFound('Sitemap not found');
103
+ }
104
+
105
+ const configuredBaseUrl = await service.getConfiguredBaseUrl();
106
+ const origin = getRequestOrigin(ctx);
107
+ const baseUrl = service.resolveBaseUrl(configuredBaseUrl, origin);
108
+ const xml = service.buildManualSitemapFile(target, baseUrl);
109
+ ctx.set('Content-Type', 'application/xml; charset=utf-8');
110
+ ctx.set('Cache-Control', 'no-store');
111
+ ctx.body = xml;
112
+ },
113
+
114
+ async serveCollectionSitemapFile(ctx) {
115
+ const filenameParam = ctx.params.filename;
116
+ const filename = filenameParam ? decodeURIComponent(filenameParam) : '';
117
+ const normalizedId = filename.replace(/\.xml$/i, '');
118
+ const service = getManualSitemapService();
119
+ const [configs, configuredBaseUrl] = await Promise.all([
120
+ service.getCollectionConfigs(),
121
+ service.getConfiguredBaseUrl(),
122
+ ]);
123
+ const target = configs.find((item) => String(item.id) === normalizedId);
124
+
125
+ if (!target) {
126
+ return ctx.notFound('Sitemap not found');
127
+ }
128
+
129
+ const origin = getRequestOrigin(ctx);
130
+ const baseUrl = service.resolveBaseUrl(configuredBaseUrl, origin);
131
+ const xml = await service.buildCollectionSitemapFile(target, baseUrl);
132
+
133
+ ctx.set('Content-Type', 'application/xml; charset=utf-8');
134
+ ctx.set('Cache-Control', 'no-store');
135
+ ctx.body = xml;
136
+ },
137
+
138
+ async listCollectionTypes(ctx) {
139
+ const results = await strapi.entityService.findMany(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-content-type`, { sort: { id: 'desc' } });
140
+ ctx.body = { results };
141
+ },
142
+
143
+ async createOrUpdateCollectionType(ctx) {
144
+ const { id, ...payload } = ctx.request.body || {};
145
+ if (id) {
146
+ await strapi.entityService.update(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-content-type`, id, { data: payload });
147
+ } else {
148
+ await strapi.entityService.create(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-content-type`, { data: payload });
149
+ }
150
+ ctx.body = { ok: true };
151
+ },
152
+
153
+ async deleteCollectionType(ctx) {
154
+ const { id } = ctx.request.query;
155
+ if (id) {
156
+ await strapi.entityService.delete(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-content-type`, id);
157
+ }
158
+ ctx.body = { ok: true };
159
+ },
160
+
161
+ async listCustomUrls(ctx) {
162
+ const results = await strapi.entityService.findMany(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-single-url`, { sort: { id: 'desc' } });
163
+ ctx.body = { results };
164
+ },
165
+
166
+ async createOrUpdateCustomUrl(ctx) {
167
+ const { id, ...payload } = ctx.request.body || {};
168
+ if (id) {
169
+ await strapi.entityService.update(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-single-url`, id, { data: payload });
170
+ } else {
171
+ await strapi.entityService.create(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-single-url`, { data: payload });
172
+ }
173
+ ctx.body = { ok: true };
174
+ },
175
+
176
+ async deleteCustomUrl(ctx) {
177
+ const { id } = ctx.request.query;
178
+ if (id) {
179
+ await strapi.entityService.delete(`plugin::${PLUGIN_ID}.strapi-advanced-sitemap-single-url`, id);
180
+ }
181
+ ctx.body = { ok: true };
182
+ },
183
+
184
+ async listContentTypes(ctx) {
185
+ const apiTypes = Object.values(strapi.contentTypes)
186
+ .filter((t) => t.uid?.startsWith('api::'))
187
+ .map((t) => ({
188
+ uid: t.uid,
189
+ singularName: t.info?.singularName || t.uid,
190
+ displayName: t.info?.displayName || t.uid,
191
+ kind: t.kind || null,
192
+ }));
193
+
194
+ const collectionTypes = apiTypes.filter((t) => t.kind === 'collectionType');
195
+ const singleTypes = apiTypes.filter((t) => t.kind === 'singleType');
196
+
197
+ ctx.body = { collectionTypes, singleTypes };
198
+ },
199
+
200
+ async listLocales(ctx) {
201
+ try {
202
+ const service = strapi.plugin('i18n')?.service('locales');
203
+ const locales = service ? await service.list() : [];
204
+ ctx.body = locales;
205
+ } catch (e) {
206
+ ctx.body = [];
207
+ }
208
+ },
209
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ controller: require('./controller'),
5
+ };
6
+
7
+
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = ({ strapi }) => {
4
+ strapi.log.info('Destroying strapi-advanced-sitemap plugin...');
5
+ };
6
+
7
+
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ const register = require('./register');
4
+ const bootstrap = require('./bootstrap');
5
+ const destroy = require('./destroy');
6
+ const config = require('./config');
7
+ const contentTypes = require('./content-types');
8
+ const controllers = require('./controllers');
9
+ const routes = require('./routes');
10
+ const services = require('./services');
11
+ const middlewares = require('./middlewares');
12
+ const policies = require('./policies');
13
+
14
+ module.exports = {
15
+ register,
16
+ bootstrap,
17
+ destroy,
18
+ config,
19
+ controllers,
20
+ contentTypes,
21
+ policies,
22
+ middlewares,
23
+ routes,
24
+ services,
25
+ };
26
+
27
+
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ 'permission-check': require('./permission-check'),
5
+ };
6
+
7
+
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const { ensureSitemapPermission } = require('../utils/check-sitemap-permission');
4
+
5
+ module.exports = () => {
6
+ return async (ctx, next) => {
7
+ const actionKey = ctx?.state?.route?.info?.permissionAction;
8
+
9
+ if (!actionKey) {
10
+ return next();
11
+ }
12
+
13
+ const allowed = await ensureSitemapPermission(ctx, actionKey);
14
+
15
+ if (allowed) {
16
+ return next();
17
+ }
18
+ };
19
+ };
20
+
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ module.exports = {};
4
+
5
+
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ module.exports = async ({ strapi }) => {
4
+ strapi.log.info('Registering strapi-advanced-sitemap plugin...');
5
+ };
6
+
7
+
8
+
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ admin: {
5
+ routes: [
6
+ { method: 'GET', path: '/admin-get-options', handler: 'controller.getOptions', config: { policies: [] } },
7
+ { method: 'PUT', path: '/admin-put-options', handler: 'controller.putOptions', config: { policies: [] } },
8
+
9
+ { method: 'GET', path: '/manual-sitemaps', handler: 'controller.getManualSitemaps', config: { policies: [] } },
10
+ { method: 'PUT', path: '/manual-sitemaps', handler: 'controller.putManualSitemaps', config: { policies: [] } },
11
+
12
+ { method: 'GET', path: '/admin', handler: 'controller.listCollectionTypes', config: { policies: [] } },
13
+ { method: 'POST', path: '/admin', handler: 'controller.createOrUpdateCollectionType', config: { policies: [] } },
14
+ { method: 'DELETE', path: '/admin', handler: 'controller.deleteCollectionType', config: { policies: [] } },
15
+
16
+ { method: 'GET', path: '/admin-custom-urls', handler: 'controller.listCustomUrls', config: { policies: [] } },
17
+ { method: 'POST', path: '/admin-custom-urls', handler: 'controller.createOrUpdateCustomUrl', config: { policies: [] } },
18
+ { method: 'DELETE', path: '/admin-custom-urls', handler: 'controller.deleteCustomUrl', config: { policies: [] } },
19
+
20
+ { method: 'GET', path: '/admin-get-content-types', handler: 'controller.listContentTypes', config: { policies: [] } },
21
+ { method: 'GET', path: '/admin-get-locales', handler: 'controller.listLocales', config: { policies: [] } },
22
+ ],
23
+ },
24
+ 'content-api': {
25
+ routes: [
26
+ {
27
+ method: 'GET',
28
+ path: '/sitemap.xml',
29
+ handler: 'controller.serveRootSitemap',
30
+ info: { type: 'content-api', pluginName: 'strapi-advanced-sitemap', permissionAction: 'root' },
31
+ config: {
32
+ auth: false,
33
+ middlewares: ['plugin::strapi-advanced-sitemap.permission-check'],
34
+ policies: [],
35
+ },
36
+ },
37
+ {
38
+ method: 'GET',
39
+ path: '/manual-sitemaps',
40
+ handler: 'controller.serveManualSitemapIndex',
41
+ info: { type: 'content-api', pluginName: 'strapi-advanced-sitemap', permissionAction: 'manualIndex' },
42
+ config: {
43
+ auth: false,
44
+ middlewares: ['plugin::strapi-advanced-sitemap.permission-check'],
45
+ policies: [],
46
+ },
47
+ },
48
+ {
49
+ method: 'GET',
50
+ path: '/manual-sitemaps/:filename',
51
+ handler: 'controller.serveManualSitemapFile',
52
+ info: { type: 'content-api', pluginName: 'strapi-advanced-sitemap', permissionAction: 'manualFile' },
53
+ config: {
54
+ auth: false,
55
+ middlewares: ['plugin::strapi-advanced-sitemap.permission-check'],
56
+ policies: [],
57
+ },
58
+ },
59
+ {
60
+ method: 'GET',
61
+ path: '/collection-sitemaps/:filename',
62
+ handler: 'controller.serveCollectionSitemapFile',
63
+ info: { type: 'content-api', pluginName: 'strapi-advanced-sitemap', permissionAction: 'collectionFile' },
64
+ config: {
65
+ auth: false,
66
+ middlewares: ['plugin::strapi-advanced-sitemap.permission-check'],
67
+ policies: [],
68
+ },
69
+ },
70
+ ],
71
+ },
72
+ };
73
+
74
+
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ service: require('./service'),
5
+ };
6
+
7
+