strapi-plugin-navigation 2.3.1 → 2.4.0

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.
Files changed (75) hide show
  1. package/README.md +47 -6
  2. package/admin/src/components/AdditionalFieldInput/index.d.ts +2 -2
  3. package/admin/src/components/AdditionalFieldInput/index.js +36 -8
  4. package/admin/src/components/AdditionalFieldInput/types.d.ts +1 -1
  5. package/admin/src/components/DragButton/index.d.ts +3 -1
  6. package/admin/src/components/DragButton/index.js +2 -1
  7. package/admin/src/components/Item/ItemCardHeader/index.d.ts +1 -0
  8. package/admin/src/components/Item/ItemCardHeader/index.js +10 -5
  9. package/admin/src/components/Item/index.js +24 -4
  10. package/admin/src/components/NavigationItemList/index.js +1 -1
  11. package/admin/src/components/Search/index.d.ts +10 -4
  12. package/admin/src/components/Search/index.js +45 -6
  13. package/admin/src/components/TextArrayInput/index.d.ts +2 -1
  14. package/admin/src/hooks/useAllContentTypes.d.ts +1 -1
  15. package/admin/src/hooks/useNavigationConfig.d.ts +3 -3
  16. package/admin/src/index.d.ts +3 -1
  17. package/admin/src/pages/SettingsPage/common/const.d.ts +2 -0
  18. package/admin/src/pages/SettingsPage/common/const.js +5 -0
  19. package/admin/src/pages/SettingsPage/common/index.d.ts +2 -0
  20. package/admin/src/pages/SettingsPage/common/index.js +18 -0
  21. package/admin/src/pages/SettingsPage/components/CustomFieldForm/index.js +27 -12
  22. package/admin/src/pages/SettingsPage/components/CustomFieldTable/index.js +1 -1
  23. package/admin/src/pages/SettingsPage/components/DisableI18nModal/index.d.ts +2 -3
  24. package/admin/src/pages/SettingsPage/components/DisableI18nModal/index.js +12 -14
  25. package/admin/src/pages/SettingsPage/index.js +3 -2
  26. package/admin/src/pages/SettingsPage/utils/form.js +2 -1
  27. package/admin/src/pages/View/components/NavigationItemForm/index.js +49 -19
  28. package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +2 -1
  29. package/admin/src/pages/View/components/NavigationItemForm/utils/form.js +2 -0
  30. package/admin/src/pages/View/index.js +20 -10
  31. package/admin/src/pages/View/utils/form.d.ts +1 -1
  32. package/admin/src/pages/View/utils/types.d.ts +3 -0
  33. package/admin/src/pages/View/utils/types.js +3 -0
  34. package/admin/src/translations/ca.json +1 -0
  35. package/admin/src/translations/en.json +3 -0
  36. package/admin/src/translations/fr.json +1 -0
  37. package/admin/src/utils/api.d.ts +4 -4
  38. package/admin/src/utils/api.js +1 -1
  39. package/package.json +8 -3
  40. package/server/content-types/index.d.ts +2 -0
  41. package/server/content-types/navigation/index.d.ts +1 -0
  42. package/server/content-types/navigation/index.js +3 -1
  43. package/server/content-types/navigation/lifecycles.d.ts +3 -0
  44. package/server/content-types/navigation/lifecycles.js +7 -0
  45. package/server/content-types/navigation-item/index.d.ts +1 -0
  46. package/server/content-types/navigation-item/index.js +3 -1
  47. package/server/content-types/navigation-item/lifecycles.d.ts +3 -0
  48. package/server/content-types/navigation-item/lifecycles.js +7 -0
  49. package/server/controllers/admin.js +19 -16
  50. package/server/controllers/client.js +6 -4
  51. package/server/graphql/queries/render-navigation-child.d.ts +1 -1
  52. package/server/graphql/queries/render-navigation.d.ts +1 -1
  53. package/server/graphql/types/index.js +1 -0
  54. package/server/graphql/types/navigation-item-additional-field-media.d.ts +5 -0
  55. package/server/graphql/types/navigation-item-additional-field-media.js +13 -0
  56. package/server/graphql/types/navigation-item.js +3 -0
  57. package/server/i18n/utils.d.ts +1 -0
  58. package/server/i18n/utils.js +4 -0
  59. package/server/index.d.ts +2 -0
  60. package/server/services/admin.js +18 -8
  61. package/server/services/client.js +42 -11
  62. package/server/services/common.js +17 -5
  63. package/server/utils/constant.d.ts +3 -0
  64. package/server/utils/constant.js +21 -1
  65. package/server/utils/functions.d.ts +16 -4
  66. package/server/utils/functions.js +54 -8
  67. package/strapi-server.d.ts +2 -0
  68. package/tsconfig.tsbuildinfo +1 -1
  69. package/types/contentTypes.d.ts +7 -2
  70. package/types/controllers.d.ts +4 -3
  71. package/types/index.d.ts +1 -0
  72. package/types/index.js +1 -0
  73. package/types/lifecycle.d.ts +22 -0
  74. package/types/lifecycle.js +3 -0
  75. package/types/services.d.ts +13 -1
@@ -7,29 +7,32 @@ const utils_3 = require("../utils");
7
7
  const InvalidParamNavigationError_1 = require("../../utils/InvalidParamNavigationError");
8
8
  const NavigationError_1 = require("../../utils/NavigationError");
9
9
  const adminControllers = {
10
- getService(name = "admin") {
11
- return (0, utils_2.getPluginService)(name);
10
+ getAdminService() {
11
+ return (0, utils_2.getPluginService)("admin");
12
+ },
13
+ getCommonService() {
14
+ return (0, utils_2.getPluginService)("common");
12
15
  },
13
16
  async get() {
14
- return await this.getService().get();
17
+ return await this.getAdminService().get();
15
18
  },
16
19
  post(ctx) {
17
20
  const { auditLog } = ctx;
18
21
  const { body = {} } = ctx.request;
19
- return this.getService().post(body, auditLog);
22
+ return this.getAdminService().post(body, auditLog);
20
23
  },
21
24
  put(ctx) {
22
25
  const { params, auditLog } = ctx;
23
26
  const { id } = (0, utils_2.parseParams)(params);
24
27
  const { body = {} } = ctx.request;
25
- return this.getService().put(id, body, auditLog).catch((0, utils_3.errorHandler)(ctx));
28
+ return this.getAdminService().put(id, body, auditLog).catch((0, utils_3.errorHandler)(ctx));
26
29
  },
27
30
  async delete(ctx) {
28
31
  const { params, auditLog } = ctx;
29
32
  const { id } = (0, utils_2.parseParams)(params);
30
33
  try {
31
34
  (0, types_1.assertNotEmpty)(id, new InvalidParamNavigationError_1.InvalidParamNavigationError("Navigation's id is not a id"));
32
- await this.getService().delete(id, auditLog);
35
+ await this.getAdminService().delete(id, auditLog);
33
36
  return {};
34
37
  }
35
38
  catch (error) {
@@ -41,11 +44,11 @@ const adminControllers = {
41
44
  }
42
45
  },
43
46
  async config() {
44
- return this.getService().config();
47
+ return this.getAdminService().config();
45
48
  },
46
49
  async updateConfig(ctx) {
47
50
  try {
48
- await this.getService().updateConfig(ctx.request.body);
51
+ await this.getAdminService().updateConfig(ctx.request.body);
49
52
  }
50
53
  catch (e) {
51
54
  (0, utils_3.errorHandler)(ctx)(e);
@@ -54,7 +57,7 @@ const adminControllers = {
54
57
  },
55
58
  async restoreConfig(ctx) {
56
59
  try {
57
- await this.getService().restoreConfig();
60
+ await this.getAdminService().restoreConfig();
58
61
  }
59
62
  catch (e) {
60
63
  (0, utils_3.errorHandler)(ctx)(e);
@@ -62,11 +65,11 @@ const adminControllers = {
62
65
  return ctx.send({ status: 200 });
63
66
  },
64
67
  async settingsConfig() {
65
- return this.getService().config(true);
68
+ return this.getAdminService().config(true);
66
69
  },
67
70
  async settingsRestart(ctx) {
68
71
  try {
69
- await this.getService().restart();
72
+ await this.getAdminService().restart();
70
73
  return ctx.send({ status: 200 });
71
74
  }
72
75
  catch (e) {
@@ -76,19 +79,19 @@ const adminControllers = {
76
79
  async getById(ctx) {
77
80
  const { params } = ctx;
78
81
  const { id } = (0, utils_2.parseParams)(params);
79
- return this.getService().getById(id);
82
+ return this.getAdminService().getById(id);
80
83
  },
81
84
  async getContentTypeItems(ctx) {
82
85
  const { params, query = {} } = ctx;
83
86
  const { model } = (0, utils_2.parseParams)(params);
84
- return this.getService("common").getContentTypeItems(model, query);
87
+ return this.getCommonService().getContentTypeItems(model, query);
85
88
  },
86
89
  fillFromOtherLocale(ctx) {
87
90
  const { params, auditLog } = ctx;
88
91
  const { source, target } = (0, utils_2.parseParams)(params);
89
92
  try {
90
93
  assertCopyParams(source, target);
91
- return this.getService().fillFromOtherLocale({ source, target, auditLog });
94
+ return this.getAdminService().fillFromOtherLocale({ source, target, auditLog });
92
95
  }
93
96
  catch (error) {
94
97
  if (error instanceof Error) {
@@ -103,7 +106,7 @@ const adminControllers = {
103
106
  try {
104
107
  assertCopyParams(source, target);
105
108
  (0, types_1.assertNotEmpty)(path, new InvalidParamNavigationError_1.InvalidParamNavigationError("Path is missing"));
106
- return await this.getService().readNavigationItemFromLocale({
109
+ return await this.getAdminService().readNavigationItemFromLocale({
107
110
  path,
108
111
  source,
109
112
  target,
@@ -125,7 +128,7 @@ const adminControllers = {
125
128
  const { query: { q } } = ctx;
126
129
  try {
127
130
  (0, types_1.assertNotEmpty)(q);
128
- return this.getService("common").getSlug(q).then((slug) => ({ slug }));
131
+ return this.getCommonService().getSlug(q).then((slug) => ({ slug }));
129
132
  }
130
133
  catch (error) {
131
134
  if (error instanceof Error) {
@@ -3,15 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const utils_1 = require("@strapi/utils");
4
4
  const utils_2 = require("../utils");
5
5
  const clientControllers = {
6
- getService(name = "client") {
7
- return (0, utils_2.getPluginService)(name);
6
+ getService() {
7
+ return (0, utils_2.getPluginService)("client");
8
8
  },
9
9
  async readAll(ctx) {
10
10
  const { query = {} } = ctx;
11
11
  const { locale, orderBy, orderDirection } = query;
12
12
  try {
13
13
  return await this.getService().readAll({
14
- locale, orderBy, orderDirection
14
+ locale,
15
+ orderBy,
16
+ orderDirection,
15
17
  });
16
18
  }
17
19
  catch (error) {
@@ -32,7 +34,7 @@ const clientControllers = {
32
34
  menuOnly,
33
35
  rootPath,
34
36
  locale,
35
- populate
37
+ populate: (0, utils_2.sanitizePopulateField)(populate),
36
38
  });
37
39
  }
38
40
  catch (error) {
@@ -9,7 +9,7 @@ declare function _exports({ strapi, nexus }: {
9
9
  type: string;
10
10
  menuOnly: any;
11
11
  };
12
- resolve(obj: any, args: any): any;
12
+ resolve(obj: any, args: any): Promise<any>;
13
13
  };
14
14
  export = _exports;
15
15
  //# sourceMappingURL=render-navigation-child.d.ts.map
@@ -15,7 +15,7 @@ declare function _exports({ strapi, nexus }: {
15
15
  menuOnly: any;
16
16
  path: any;
17
17
  locale: any;
18
- }): any;
18
+ }): Promise<any>;
19
19
  };
20
20
  export = _exports;
21
21
  //# sourceMappingURL=render-navigation.d.ts.map
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  const typesFactories = [
3
+ require('./navigation-item-additional-field-media'),
3
4
  require('./navigation-item-related'),
4
5
  require('./navigation-item-related-data'),
5
6
  require('./navigation-item'),
@@ -0,0 +1,5 @@
1
+ declare function _exports({ nexus }: {
2
+ nexus: any;
3
+ }): any;
4
+ export = _exports;
5
+ //# sourceMappingURL=navigation-item-additional-field-media.d.ts.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ module.exports = ({ nexus }) => nexus.objectType({
3
+ name: "NavigationItemAdditionalFieldMedia",
4
+ definition(t) {
5
+ t.nonNull.string("name");
6
+ t.nonNull.string("url");
7
+ t.nonNull.string("mime");
8
+ t.nonNull.int("width");
9
+ t.nonNull.int("height");
10
+ t.string("previewUrl");
11
+ }
12
+ });
13
+ //# sourceMappingURL=navigation-item-additional-field-media.js.map
@@ -26,6 +26,9 @@ module.exports = ({ nexus, config }) => nexus.objectType({
26
26
  if (field !== 'audience') {
27
27
  if (field.enabled) {
28
28
  switch (field.type) {
29
+ case 'media':
30
+ t.field(field.name, { type: "NavigationItemAdditionalFieldMedia" });
31
+ break;
29
32
  case 'string':
30
33
  t.string(field.name);
31
34
  break;
@@ -6,6 +6,7 @@ type I18NStatus = {
6
6
  hasI18NPlugin: boolean;
7
7
  enabled: boolean;
8
8
  defaultLocale?: string | null;
9
+ locales?: string[] | undefined;
9
10
  };
10
11
  export declare const getI18nStatus: ({ strapi, }: GetI18nStatusInput) => Promise<I18NStatus>;
11
12
  export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getI18nStatus = void 0;
4
+ const fp_1 = require("lodash/fp");
4
5
  const getI18nStatus = async ({ strapi, }) => {
5
6
  const i18nPlugin = strapi.plugin("i18n");
6
7
  const hasI18NPlugin = !!i18nPlugin;
@@ -13,16 +14,19 @@ const getI18nStatus = async ({ strapi, }) => {
13
14
  });
14
15
  const localeService = i18nPlugin ? i18nPlugin.service("locales") : null;
15
16
  const defaultLocale = await localeService?.getDefaultLocale();
17
+ const locales = (await localeService?.find({}))?.map((0, fp_1.prop)("code"));
16
18
  return hasI18NPlugin
17
19
  ? {
18
20
  hasI18NPlugin,
19
21
  enabled: config.i18nEnabled,
20
22
  defaultLocale,
23
+ locales,
21
24
  }
22
25
  : {
23
26
  hasI18NPlugin,
24
27
  enabled: false,
25
28
  defaultLocale: undefined,
29
+ locales: undefined
26
30
  };
27
31
  };
28
32
  exports.getI18nStatus = getI18nStatus;
package/server/index.d.ts CHANGED
@@ -82,6 +82,7 @@ declare const _default: {
82
82
  };
83
83
  };
84
84
  };
85
+ lifecycles: Record<import("../types").LifeCycleHookName, import("../types").Effect<import("../types").LifeCycleEvent<import("../types").LifeCycleHookName, unknown, Record<string, unknown>>>>;
85
86
  };
86
87
  "navigation-item": {
87
88
  schema: {
@@ -185,6 +186,7 @@ declare const _default: {
185
186
  };
186
187
  };
187
188
  };
189
+ lifecycles: Record<import("../types").LifeCycleHookName, import("../types").Effect<import("../types").LifeCycleEvent<import("../types").LifeCycleHookName, unknown, Record<string, unknown>>>>;
188
190
  };
189
191
  "navigations-items-related": {
190
192
  schema: {
@@ -69,17 +69,27 @@ const adminService = ({ strapi, }) => ({
69
69
  },
70
70
  async get(ids) {
71
71
  const { masterModel } = (0, utils_2.getPluginModels)();
72
- const entities = await strapi.query(masterModel.uid).findMany({
72
+ const { enabled: i18nEnabled, locales } = await (0, i18n_1.getI18nStatus)({ strapi });
73
+ const whereClause = {};
74
+ if (ids) {
75
+ whereClause.id = { $in: ids };
76
+ }
77
+ let entities = await strapi.query(masterModel.uid).findMany({
73
78
  limit: Number.MAX_SAFE_INTEGER,
74
79
  populate: utils_2.DEFAULT_POPULATE,
75
- where: ids
76
- ? {
77
- id: {
78
- $in: ids,
79
- },
80
- }
81
- : undefined,
80
+ where: whereClause,
82
81
  });
82
+ if (i18nEnabled) {
83
+ entities = entities.reduce((acc, entity) => {
84
+ if (entity.localeCode && locales?.includes(entity.localeCode)) {
85
+ acc.push({
86
+ ...entity,
87
+ localizations: entity.localizations?.filter(({ localeCode }) => localeCode && locales?.includes(localeCode)),
88
+ });
89
+ }
90
+ return acc;
91
+ }, []);
92
+ }
83
93
  return entities;
84
94
  },
85
95
  async getById(id) {
@@ -7,10 +7,12 @@ const utils_1 = require("../utils");
7
7
  const utils_2 = require("@strapi/utils");
8
8
  const i18n_1 = require("../i18n");
9
9
  const NavigationError_1 = require("../../utils/NavigationError");
10
+ const fp_1 = require("lodash/fp");
10
11
  const clientService = ({ strapi }) => ({
11
12
  async readAll({ locale, orderBy = 'createdAt', orderDirection = "DESC" }) {
12
13
  const { masterModel } = (0, utils_1.getPluginModels)();
13
- const navigations = await strapi
14
+ const { enabled: i18nEnabled, locales } = await (0, i18n_1.getI18nStatus)({ strapi });
15
+ let navigations = await strapi
14
16
  .query(masterModel.uid)
15
17
  .findMany({
16
18
  where: locale
@@ -22,6 +24,17 @@ const clientService = ({ strapi }) => ({
22
24
  limit: Number.MAX_SAFE_INTEGER,
23
25
  populate: false
24
26
  });
27
+ if (i18nEnabled) {
28
+ navigations = navigations.reduce((acc, navigation) => {
29
+ if (navigation.localeCode && locales?.includes(navigation.localeCode)) {
30
+ acc.push({
31
+ ...navigation,
32
+ localizations: navigation.localizations?.filter(({ localeCode }) => localeCode && locales?.includes(localeCode)),
33
+ });
34
+ }
35
+ return acc;
36
+ }, []);
37
+ }
25
38
  return navigations;
26
39
  },
27
40
  async render({ idOrSlug, type = utils_1.RENDER_TYPES.FLAT, menuOnly = false, rootPath = null, wrapRelated = false, locale, populate, }) {
@@ -223,6 +236,8 @@ const clientService = ({ strapi }) => ({
223
236
  id: itemContentType.id,
224
237
  attributes: { ...itemContentType }
225
238
  } : itemContentType;
239
+ const pickMediaFields = (0, fp_1.pick)(["name", "url", "mime", "width", "height", "previewUrl"]);
240
+ const customFieldsDefinitions = additionalFields.filter(_ => typeof _ !== "string");
226
241
  switch (type) {
227
242
  case utils_1.RENDER_TYPES.TREE:
228
243
  case utils_1.RENDER_TYPES.RFR:
@@ -235,6 +250,13 @@ const clientService = ({ strapi }) => ({
235
250
  const slug = (0, lodash_1.isString)(parentPath) ? await commonService.getSlug(((0, lodash_1.first)(parentPath) === '/' ? parentPath.substring(1) : parentPath).replace(/\//g, '-')) : undefined;
236
251
  const lastRelated = (0, lodash_1.isArray)(item.related) ? (0, lodash_1.last)(item.related) : item.related;
237
252
  const relatedContentType = wrapContentType(lastRelated);
253
+ const customFields = enabledCustomFieldsNames.reduce((acc, field) => {
254
+ const mapper = customFieldsDefinitions.find(({ name }) => name === field)?.type === "media"
255
+ ? (_) => pickMediaFields(JSON.parse(_))
256
+ : fp_1.identity;
257
+ const content = (0, lodash_1.get)(item, `additionalFields.${field}`);
258
+ return { ...acc, [field]: content ? mapper(content) : content };
259
+ }, {});
238
260
  return {
239
261
  id: item.id,
240
262
  title: (0, utils_1.composeItemTitle)(item, contentTypesNameFields, contentTypes),
@@ -251,11 +273,11 @@ const clientService = ({ strapi }) => ({
251
273
  },
252
274
  audience: !(0, lodash_1.isEmpty)(item.audience) ? item.audience.map(({ key }) => key) : undefined,
253
275
  items: isExternal ? undefined : await clientService.renderTree(items, item.id, field, parentPath, itemParser),
254
- ...enabledCustomFieldsNames.reduce((acc, field) => ({ ...acc, [field]: (0, lodash_1.get)(item, `additionalFields.${field}`) }), {}),
276
+ ...customFields
255
277
  };
256
278
  };
257
279
  const { items: itemsFilteredByPath, root: rootElement, } = (0, utils_1.filterByPath)(items, rootPath);
258
- const treeStructure = await clientService.renderTree((0, lodash_1.isNil)(rootPath) ? items : itemsFilteredByPath, (0, lodash_1.get)(rootElement, 'parent.id'), 'parent', (0, lodash_1.get)(rootElement, 'parent.path'), itemParser);
280
+ const treeStructure = await clientService.renderTree((0, lodash_1.isNil)(rootPath) ? items : itemsFilteredByPath, (0, lodash_1.get)(rootElement, 'parent.id') ?? null, 'parent', (0, lodash_1.get)(rootElement, 'parent.path'), itemParser);
259
281
  const filteredStructure = filter
260
282
  ? treeStructure.filter((item) => item.uiRouterKey === filter)
261
283
  : treeStructure;
@@ -286,14 +308,23 @@ const clientService = ({ strapi }) => ({
286
308
  return nestedOrders;
287
309
  };
288
310
  return result
289
- .map(({ additionalFields, ...item }) => ({
290
- ...item,
291
- audience: item.audience?.map(_ => (_).key),
292
- title: (0, utils_1.composeItemTitle)({ ...item, additionalFields }, contentTypesNameFields, contentTypes) || '',
293
- related: wrapContentType(item.related),
294
- items: null,
295
- ...enabledCustomFieldsNames.reduce((acc, name) => ({ ...acc, [name]: (0, lodash_1.get)(additionalFields, name, undefined) }), {}),
296
- }))
311
+ .map(({ additionalFields, ...item }) => {
312
+ const customFields = enabledCustomFieldsNames.reduce((acc, field) => {
313
+ const mapper = customFieldsDefinitions.find(({ name }) => name === field)?.type === "media"
314
+ ? (_) => pickMediaFields(JSON.parse(_.toString()))
315
+ : fp_1.identity;
316
+ const content = (0, lodash_1.get)(additionalFields, field);
317
+ return { ...acc, [field]: content ? mapper(content) : content };
318
+ }, {});
319
+ return ({
320
+ ...item,
321
+ audience: item.audience?.map(_ => (_).key),
322
+ title: (0, utils_1.composeItemTitle)({ ...item, additionalFields }, contentTypesNameFields, contentTypes) || '',
323
+ related: wrapContentType(item.related),
324
+ items: null,
325
+ ...customFields,
326
+ });
327
+ })
297
328
  .sort((a, b) => (0, utils_1.compareArraysOfNumbers)(getNestedOrders(a.id), getNestedOrders(b.id)));
298
329
  }
299
330
  }
@@ -10,6 +10,10 @@ const config_1 = require("../config");
10
10
  const i18n_1 = require("../i18n");
11
11
  const utils_2 = require("../utils");
12
12
  const slugify_1 = __importDefault(require("@sindresorhus/slugify"));
13
+ const lifecycleHookListeners = {
14
+ navigation: {},
15
+ "navigation-item": {}
16
+ };
13
17
  const commonService = ({ strapi }) => ({
14
18
  analyzeBranch(items = [], masterEntity = null, parentItem = null, prevOperations = {}) {
15
19
  const commonService = (0, utils_2.getPluginService)('common');
@@ -241,11 +245,7 @@ const commonService = ({ strapi }) => ({
241
245
  const relatedData = data.get(item.id);
242
246
  if (relatedData) {
243
247
  return Object.assign(item, {
244
- related: {
245
- ...relatedData,
246
- createdBy: (0, utils_2.purgeSensitiveData)(relatedData.createdBy),
247
- updatedBy: (0, utils_2.purgeSensitiveData)(relatedData.updatedBy),
248
- }
248
+ related: (0, utils_2.purgeSensitiveData)(relatedData),
249
249
  });
250
250
  }
251
251
  return { ...item, related: null };
@@ -368,6 +368,18 @@ const commonService = ({ strapi }) => ({
368
368
  }
369
369
  return slug.toLowerCase();
370
370
  },
371
+ registerLifecycleHook({ callback, contentTypeName, hookName }) {
372
+ if (!lifecycleHookListeners[contentTypeName][hookName]) {
373
+ lifecycleHookListeners[contentTypeName][hookName] = [];
374
+ }
375
+ lifecycleHookListeners[contentTypeName][hookName]?.push(callback);
376
+ },
377
+ async runLifecycleHook({ contentTypeName, event, hookName }) {
378
+ const hookListeners = lifecycleHookListeners[contentTypeName][hookName] ?? [];
379
+ for (const listener of hookListeners) {
380
+ await listener(event);
381
+ }
382
+ },
371
383
  });
372
384
  exports.default = commonService;
373
385
  //# sourceMappingURL=common.js.map
@@ -1,3 +1,4 @@
1
+ import { LifeCycleHookName } from "../../types";
1
2
  export declare const TEMPLATE_DEFAULT: "Generic";
2
3
  export declare const MODEL_TYPES: {
3
4
  readonly CONTENT_TYPE: "contentType";
@@ -21,4 +22,6 @@ export declare const RENDER_TYPES: Readonly<{
21
22
  TREE: "TREE";
22
23
  RFR: "RFR";
23
24
  }>;
25
+ export type ContentType = "navigation" | "navigation-item";
26
+ export declare const allLifecycleHooks: ReadonlyArray<LifeCycleHookName>;
24
27
  //# sourceMappingURL=constant.d.ts.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RENDER_TYPES = exports.DEFAULT_NAVIGATION_ITEM = exports.DEFAULT_POPULATE = exports.CONTENT_TYPES_NAME_FIELDS_DEFAULTS = exports.EXCLUDED_CONTENT_TYPES = exports.RESTRICTED_CONTENT_TYPES = exports.ALLOWED_CONTENT_TYPES = exports.KIND_TYPES = exports.MODEL_TYPES = exports.TEMPLATE_DEFAULT = void 0;
3
+ exports.allLifecycleHooks = exports.RENDER_TYPES = exports.DEFAULT_NAVIGATION_ITEM = exports.DEFAULT_POPULATE = exports.CONTENT_TYPES_NAME_FIELDS_DEFAULTS = exports.EXCLUDED_CONTENT_TYPES = exports.RESTRICTED_CONTENT_TYPES = exports.ALLOWED_CONTENT_TYPES = exports.KIND_TYPES = exports.MODEL_TYPES = exports.TEMPLATE_DEFAULT = void 0;
4
4
  const i18n_1 = require("../i18n");
5
5
  exports.TEMPLATE_DEFAULT = 'Generic';
6
6
  exports.MODEL_TYPES = { CONTENT_TYPE: 'contentType' };
@@ -20,4 +20,24 @@ exports.RENDER_TYPES = {
20
20
  TREE: 'TREE',
21
21
  RFR: 'RFR'
22
22
  };
23
+ exports.allLifecycleHooks = [
24
+ "beforeCreate",
25
+ "beforeCreateMany",
26
+ "afterCreate",
27
+ "afterCreateMany",
28
+ "beforeUpdate",
29
+ "beforeUpdateMany",
30
+ "afterUpdate",
31
+ "afterUpdateMany",
32
+ "beforeDelete",
33
+ "beforeDeleteMany",
34
+ "afterDelete",
35
+ "afterDeleteMany",
36
+ "beforeCount",
37
+ "afterCount",
38
+ "beforeFindOne",
39
+ "afterFindOne",
40
+ "beforeFindMany",
41
+ "afterFindMany",
42
+ ];
23
43
  //# sourceMappingURL=constant.js.map
@@ -1,8 +1,15 @@
1
- import { PopulateClause } from 'strapi-typed';
1
+ import { PopulateClause, StrapiContext } from 'strapi-typed';
2
2
  import { Id, IStrapi, Primitive, StrapiContentType, StringMap, StrapiContentTypeFullSchema } from "strapi-typed";
3
- import { AuditLogContext, AuditLogParams, ContentTypeEntity, NavigationActions, NavigationItem, NavigationItemAdditionalField, NavigationItemCustomField, NavigationItemEntity, NavigationService, NavigationServiceName, NestedPath, NestedStructure, PluginConfigNameFields, PopulateQueryParam, ToBeFixed } from "../../types";
3
+ import { AuditLogContext, AuditLogParams, ContentTypeEntity, Effect, IAdminService, IClientService, ICommonService, LifeCycleEvent, LifeCycleHookName, NavigationActions, NavigationItem, NavigationItemAdditionalField, NavigationItemCustomField, NavigationItemEntity, NavigationServiceName, NestedPath, NestedStructure, PluginConfigNameFields, PopulateQueryParam, ToBeFixed } from "../../types";
4
4
  import { NavigationError } from '../../utils/NavigationError';
5
- export declare const getPluginService: <T extends NavigationService>(name: NavigationServiceName) => T;
5
+ import { ContentType } from './constant';
6
+ type Populate = string | undefined | boolean | Array<Populate> | Record<string, string | boolean | undefined>;
7
+ type TypeMap = {
8
+ client: IClientService;
9
+ admin: IAdminService;
10
+ common: ICommonService;
11
+ };
12
+ export declare function getPluginService<T extends NavigationServiceName>(name: T): T extends infer R extends NavigationServiceName ? TypeMap[R] : never;
6
13
  export declare const errorHandler: (ctx: ToBeFixed) => (error: NavigationError | string) => any;
7
14
  export declare const getCustomFields: (additionalFields: NavigationItemAdditionalField[]) => NavigationItemCustomField[];
8
15
  export declare const parseParams: <TParams extends StringMap<string> = StringMap<string>, TResult extends StringMap<Primitive> = StringMap<Primitive>>(params: TParams) => TResult;
@@ -136,6 +143,11 @@ export declare const compareArraysOfNumbers: (arrA: number[], arrB: number[]) =>
136
143
  export declare const getPluginModels: () => Record<'masterModel' | 'itemModel' | 'relatedModel' | 'audienceModel', StrapiContentTypeFullSchema>;
137
144
  export declare const validateAdditionalFields: (additionalFields: NavigationItemAdditionalField[]) => void;
138
145
  export declare const parsePopulateQuery: (populate: PopulateQueryParam) => PopulateClause;
139
- export declare const purgeSensitiveData: (data?: any) => {} | undefined;
146
+ export declare const purgeSensitiveData: (data: ToBeFixed) => ToBeFixed;
147
+ export declare const purgeSensitiveDataFromUser: (data?: any) => {} | undefined;
140
148
  export declare const resolveGlobalLikeId: (uid?: string) => string;
149
+ export declare const sanitizePopulateField: (populate: Populate) => Populate;
150
+ export declare const buildHookListener: (contentTypeName: ContentType, { strapi }: StrapiContext) => (hookName: LifeCycleHookName) => [LifeCycleHookName, Effect<LifeCycleEvent>];
151
+ export declare const buildAllHookListeners: (contentTypeName: ContentType, context: StrapiContext) => Record<LifeCycleHookName, Effect<LifeCycleEvent>>;
152
+ export {};
141
153
  //# sourceMappingURL=functions.d.ts.map
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveGlobalLikeId = exports.purgeSensitiveData = exports.parsePopulateQuery = exports.validateAdditionalFields = exports.getPluginModels = exports.compareArraysOfNumbers = exports.intercalate = exports.isContentTypeEligible = exports.filterByPath = exports.buildNestedPaths = exports.buildNestedStructure = exports.singularize = exports.checkDuplicatePath = exports.filterOutUnpublished = exports.extractItemRelationTitle = exports.composeItemTitle = exports.sendAuditLog = exports.prepareAuditLog = exports.getTemplateComponentFromTemplate = exports.templateNameFactory = exports.parseParams = exports.getCustomFields = exports.errorHandler = exports.getPluginService = void 0;
3
+ exports.buildAllHookListeners = exports.buildHookListener = exports.sanitizePopulateField = exports.resolveGlobalLikeId = exports.purgeSensitiveDataFromUser = exports.purgeSensitiveData = exports.parsePopulateQuery = exports.validateAdditionalFields = exports.getPluginModels = exports.compareArraysOfNumbers = exports.intercalate = exports.isContentTypeEligible = exports.filterByPath = exports.buildNestedPaths = exports.buildNestedStructure = exports.singularize = exports.checkDuplicatePath = exports.filterOutUnpublished = exports.extractItemRelationTitle = exports.composeItemTitle = exports.sendAuditLog = exports.prepareAuditLog = exports.getTemplateComponentFromTemplate = exports.templateNameFactory = exports.parseParams = exports.getCustomFields = exports.errorHandler = exports.getPluginService = void 0;
4
4
  const lodash_1 = require("lodash");
5
5
  const types_1 = require("../../types");
6
6
  const NavigationError_1 = require("../../utils/NavigationError");
7
7
  const constant_1 = require("./constant");
8
8
  const UID_REGEX = /^(?<type>[a-z0-9-]+)\:{2}(?<api>[a-z0-9-]+)\.{1}(?<contentType>[a-z0-9-]+)$/i;
9
- const getPluginService = (name) => strapi.plugin("navigation").service(name);
9
+ function getPluginService(name) {
10
+ return strapi.plugin("navigation").service(name);
11
+ }
10
12
  exports.getPluginService = getPluginService;
11
13
  const errorHandler = (ctx) => (error) => {
12
14
  if (error instanceof NavigationError_1.NavigationError) {
@@ -184,7 +186,7 @@ const buildNestedPaths = (items, id = null, parentPath = null) => {
184
186
  {
185
187
  id: entity.id,
186
188
  parent: parentPath ? {
187
- id: (0, lodash_1.get)(entity, 'parent.id'),
189
+ id: (0, lodash_1.get)(entity, ['parent', 'id']),
188
190
  path: parentPath,
189
191
  } : undefined,
190
192
  path,
@@ -262,20 +264,34 @@ const parsePopulateQuery = (populate) => {
262
264
  }
263
265
  };
264
266
  exports.parsePopulateQuery = parsePopulateQuery;
265
- const purgeSensitiveData = (data = {}) => {
267
+ const purgeSensitiveData = (data) => {
268
+ if (!data || !(typeof data === "object") || !Object.keys(data).length) {
269
+ return data;
270
+ }
271
+ const { createdBy = undefined, updatedBy = undefined, ...rest } = data;
272
+ if (!createdBy && !updatedBy) {
273
+ return data;
274
+ }
275
+ return {
276
+ ...Object.fromEntries(Object.entries(rest).map(([key, value]) => [key, (0, exports.purgeSensitiveData)(value)])),
277
+ ...(createdBy ? { createdBy: (0, exports.purgeSensitiveDataFromUser)(createdBy) } : {}),
278
+ ...(updatedBy ? { updatedBy: (0, exports.purgeSensitiveDataFromUser)(updatedBy) } : {}),
279
+ };
280
+ };
281
+ exports.purgeSensitiveData = purgeSensitiveData;
282
+ const purgeSensitiveDataFromUser = (data = {}) => {
266
283
  if (!data) {
267
284
  return undefined;
268
285
  }
269
- const forbiddenFields = ['password', 'token', 'secret'];
286
+ const allowedFields = ['username', 'firstname', 'lastname', 'email'];
270
287
  return Object.keys(data)
271
- .filter((key) => !forbiddenFields.includes(key.toLowerCase()) &&
272
- (0, lodash_1.isEmpty)(forbiddenFields.filter(_ => key.toLowerCase().includes(_))))
288
+ .filter((key) => allowedFields.includes(key.toLowerCase()))
273
289
  .reduce((prev, curr) => ({
274
290
  ...prev,
275
291
  [curr]: data[curr],
276
292
  }), {});
277
293
  };
278
- exports.purgeSensitiveData = purgeSensitiveData;
294
+ exports.purgeSensitiveDataFromUser = purgeSensitiveDataFromUser;
279
295
  const resolveGlobalLikeId = (uid = '') => {
280
296
  const parse = (str) => str.split('-')
281
297
  .map(_ => (0, lodash_1.capitalize)(_))
@@ -290,4 +306,34 @@ exports.resolveGlobalLikeId = resolveGlobalLikeId;
290
306
  const splitTypeUid = (uid = '') => {
291
307
  return uid.split(UID_REGEX).filter((s) => s && s.length > 0);
292
308
  };
309
+ const sanitizePopulateField = (populate) => {
310
+ if (!populate || populate === true || populate === "*") {
311
+ return undefined;
312
+ }
313
+ if (Array.isArray(populate)) {
314
+ return populate
315
+ .map((item) => (0, exports.sanitizePopulateField)(item));
316
+ }
317
+ if ("object" === typeof populate) {
318
+ return Object.fromEntries(Object.entries(populate).map(([key, value]) => [key, (0, exports.sanitizePopulateField)(value)]));
319
+ }
320
+ return populate;
321
+ };
322
+ exports.sanitizePopulateField = sanitizePopulateField;
323
+ const buildHookListener = (contentTypeName, { strapi }) => (hookName) => [
324
+ hookName,
325
+ async (event) => {
326
+ const commonService = strapi
327
+ .plugin("navigation")
328
+ .service("common");
329
+ await commonService.runLifecycleHook({
330
+ contentTypeName,
331
+ hookName,
332
+ event,
333
+ });
334
+ },
335
+ ];
336
+ exports.buildHookListener = buildHookListener;
337
+ const buildAllHookListeners = (contentTypeName, context) => Object.fromEntries(constant_1.allLifecycleHooks.map((0, exports.buildHookListener)(contentTypeName, context)));
338
+ exports.buildAllHookListeners = buildAllHookListeners;
293
339
  //# sourceMappingURL=functions.js.map
@@ -82,6 +82,7 @@ declare const _default: () => {
82
82
  };
83
83
  };
84
84
  };
85
+ lifecycles: Record<import("./types").LifeCycleHookName, import("./types").Effect<import("./types").LifeCycleEvent<import("./types").LifeCycleHookName, unknown, Record<string, unknown>>>>;
85
86
  };
86
87
  "navigation-item": {
87
88
  schema: {
@@ -185,6 +186,7 @@ declare const _default: () => {
185
186
  };
186
187
  };
187
188
  };
189
+ lifecycles: Record<import("./types").LifeCycleHookName, import("./types").Effect<import("./types").LifeCycleEvent<import("./types").LifeCycleHookName, unknown, Record<string, unknown>>>>;
188
190
  };
189
191
  "navigations-items-related": {
190
192
  schema: {