@akemona-org/strapi-plugin-i18n 3.7.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 (147) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/assets/images/logo.svg +1 -0
  4. package/admin/src/components/CMEditViewCopyLocale/index.js +183 -0
  5. package/admin/src/components/CMEditViewCopyLocale/utils/cleanData.js +36 -0
  6. package/admin/src/components/CMEditViewCopyLocale/utils/generateOptions.js +22 -0
  7. package/admin/src/components/CMEditViewCopyLocale/utils/index.js +2 -0
  8. package/admin/src/components/CMEditViewCopyLocale/utils/removePasswordAndRelationsFieldFromData.js +54 -0
  9. package/admin/src/components/CMEditViewCopyLocale/utils/tests/cleanData.test.js +83 -0
  10. package/admin/src/components/CMEditViewCopyLocale/utils/tests/data.js +219 -0
  11. package/admin/src/components/CMEditViewCopyLocale/utils/tests/generateOptions.test.js +79 -0
  12. package/admin/src/components/CMEditViewCopyLocale/utils/tests/removePasswordAndRelationsFieldFromData.test.js +40 -0
  13. package/admin/src/components/CMEditViewInjectedComponents/index.js +58 -0
  14. package/admin/src/components/CMEditViewLocalePicker/Option.js +66 -0
  15. package/admin/src/components/CMEditViewLocalePicker/Wrapper.js +8 -0
  16. package/admin/src/components/CMEditViewLocalePicker/index.js +160 -0
  17. package/admin/src/components/CMEditViewLocalePicker/utils/addStatusColorToLocale.js +24 -0
  18. package/admin/src/components/CMEditViewLocalePicker/utils/createLocalesOption.js +20 -0
  19. package/admin/src/components/CMEditViewLocalePicker/utils/index.js +2 -0
  20. package/admin/src/components/CheckboxConfirmation/Wrapper.js +12 -0
  21. package/admin/src/components/CheckboxConfirmation/index.js +70 -0
  22. package/admin/src/components/DeleteModalAdditionalInfos/index.js +25 -0
  23. package/admin/src/components/LocaleList/index.js +101 -0
  24. package/admin/src/components/LocaleListCell/LocaleListCell.js +90 -0
  25. package/admin/src/components/LocaleListCell/tests/LocaleListCell.test.js +128 -0
  26. package/admin/src/components/LocalePicker/index.js +126 -0
  27. package/admin/src/components/LocaleRow/index.js +77 -0
  28. package/admin/src/components/ModalCreate/AdvancedForm.js +45 -0
  29. package/admin/src/components/ModalCreate/BaseForm.js +103 -0
  30. package/admin/src/components/ModalCreate/index.js +136 -0
  31. package/admin/src/components/ModalDelete/index.js +49 -0
  32. package/admin/src/components/ModalEdit/AdvancedForm.js +51 -0
  33. package/admin/src/components/ModalEdit/BaseForm.js +91 -0
  34. package/admin/src/components/ModalEdit/index.js +122 -0
  35. package/admin/src/components/SettingsModal.js +66 -0
  36. package/admin/src/components/index.js +2 -0
  37. package/admin/src/containers/Initializer.js +31 -0
  38. package/admin/src/containers/SettingsPage/LocaleSettingsPage.js +69 -0
  39. package/admin/src/containers/SettingsPage/index.js +33 -0
  40. package/admin/src/containers/SettingsPage/tests/SettingsPage.test.js +744 -0
  41. package/admin/src/containers/SettingsPage/tests/__snapshots__/SettingsPage.test.js.snap +241 -0
  42. package/admin/src/hooks/constants.js +6 -0
  43. package/admin/src/hooks/reducers.js +63 -0
  44. package/admin/src/hooks/tests/reducers.test.js +203 -0
  45. package/admin/src/hooks/useAddLocale/index.js +60 -0
  46. package/admin/src/hooks/useContentTypePermissions/index.js +16 -0
  47. package/admin/src/hooks/useDefaultLocales/index.js +27 -0
  48. package/admin/src/hooks/useDeleteLocale/index.js +45 -0
  49. package/admin/src/hooks/useEditLocale/index.js +46 -0
  50. package/admin/src/hooks/useHasI18n/index.js +13 -0
  51. package/admin/src/hooks/useLocales/index.js +35 -0
  52. package/admin/src/index.js +169 -0
  53. package/admin/src/middlewares/addCommonFieldsToInitialDataMiddleware.js +83 -0
  54. package/admin/src/middlewares/addLocaleColumnToListViewMiddleware.js +32 -0
  55. package/admin/src/middlewares/addLocaleToCollectionTypesMiddleware.js +25 -0
  56. package/admin/src/middlewares/addLocaleToSingleTypesMiddleware.js +25 -0
  57. package/admin/src/middlewares/extendCMEditViewLayoutMiddleware.js +159 -0
  58. package/admin/src/middlewares/extendCTBAttributeInitialDataMiddleware.js +58 -0
  59. package/admin/src/middlewares/extendCTBInitialDataMiddleware.js +33 -0
  60. package/admin/src/middlewares/index.js +21 -0
  61. package/admin/src/middlewares/localePermissionMiddleware.js +39 -0
  62. package/admin/src/middlewares/tests/addCommonFieldsToInitialDataMiddleware.test.js +97 -0
  63. package/admin/src/middlewares/tests/addLocaleColumnToListViewMiddleware.test.js +68 -0
  64. package/admin/src/middlewares/tests/addLocaleToCollectionTypesMiddleware.test.js +200 -0
  65. package/admin/src/middlewares/tests/addLocaleToSingleTypesMiddleware.test.js +193 -0
  66. package/admin/src/middlewares/tests/extendCMEditViewLayoutMiddleware.test.js +556 -0
  67. package/admin/src/middlewares/tests/extendCTBAttrributeInitialDataMiddleware.test.js +124 -0
  68. package/admin/src/middlewares/tests/extendCTBInitialDataMiddleware.test.js +92 -0
  69. package/admin/src/middlewares/tests/localePermissionMiddleware.test.js +150 -0
  70. package/admin/src/middlewares/utils/addLocaleToLinksSearch.js +56 -0
  71. package/admin/src/middlewares/utils/tests/addLocaleToLinksSearch.test.js +137 -0
  72. package/admin/src/permissions.js +9 -0
  73. package/admin/src/pluginId.js +5 -0
  74. package/admin/src/schemas.js +7 -0
  75. package/admin/src/selectors/selectCollectionTypesRelatedPermissions.js +4 -0
  76. package/admin/src/selectors/selectI18nLocales.js +3 -0
  77. package/admin/src/translations/en.json +60 -0
  78. package/admin/src/translations/fr.json +9 -0
  79. package/admin/src/translations/index.js +11 -0
  80. package/admin/src/translations/zh-Hans.json +60 -0
  81. package/admin/src/utils/getDefaultLocale.js +60 -0
  82. package/admin/src/utils/getInitialLocale.js +14 -0
  83. package/admin/src/utils/getLocaleFromQuery.js +7 -0
  84. package/admin/src/utils/getTrad.js +5 -0
  85. package/admin/src/utils/index.js +2 -0
  86. package/admin/src/utils/localizedFields.js +23 -0
  87. package/admin/src/utils/mutateCTBContentTypeSchema.js +66 -0
  88. package/admin/src/utils/tests/getDefaultLocale.test.js +337 -0
  89. package/admin/src/utils/tests/getInitialLocale.test.js +106 -0
  90. package/admin/src/utils/tests/mutateCTBContentTypeSchema.test.js +205 -0
  91. package/config/functions/bootstrap.js +57 -0
  92. package/config/functions/migrations/__tests__/content-type.test.js +255 -0
  93. package/config/functions/migrations/__tests__/field.test.js +150 -0
  94. package/config/functions/migrations/content-type/disable/index.js +34 -0
  95. package/config/functions/migrations/content-type/disable/migrate-for-bookshelf.js +58 -0
  96. package/config/functions/migrations/content-type/disable/migrate-for-mongoose.js +39 -0
  97. package/config/functions/migrations/content-type/enable/index.js +40 -0
  98. package/config/functions/migrations/content-type/utils/index.js +27 -0
  99. package/config/functions/migrations/field/__tests__/utils.test.js +53 -0
  100. package/config/functions/migrations/field/index.js +37 -0
  101. package/config/functions/migrations/field/migrate-for-bookshelf.js +72 -0
  102. package/config/functions/migrations/field/migrate-for-mongoose.js +24 -0
  103. package/config/functions/migrations/field/migrate.js +55 -0
  104. package/config/functions/migrations/field/utils.js +58 -0
  105. package/config/functions/register.js +46 -0
  106. package/config/policies/validateLocaleCreation.js +68 -0
  107. package/config/routes.json +64 -0
  108. package/constants/__tests__/index.test.js +27 -0
  109. package/constants/index.js +36 -0
  110. package/constants/iso-locales.json +2002 -0
  111. package/controllers/__tests__/content-types.test.js +113 -0
  112. package/controllers/__tests__/iso-locales.test.js +26 -0
  113. package/controllers/__tests__/locales.test.js +308 -0
  114. package/controllers/content-types.js +64 -0
  115. package/controllers/iso-locales.js +11 -0
  116. package/controllers/locales.js +104 -0
  117. package/domain/locale.js +10 -0
  118. package/middlewares/i18n/defaults.json +5 -0
  119. package/middlewares/i18n/index.js +28 -0
  120. package/models/Locale.settings.json +31 -0
  121. package/oas.yml +195 -0
  122. package/package.json +31 -0
  123. package/services/__tests__/__snapshots__/iso-locales.test.js.snap +2006 -0
  124. package/services/__tests__/content-types.test.js +545 -0
  125. package/services/__tests__/core-api.test.js +106 -0
  126. package/services/__tests__/entity-service-decorator.test.js +280 -0
  127. package/services/__tests__/iso-locales.test.js +11 -0
  128. package/services/__tests__/locales.test.js +237 -0
  129. package/services/__tests__/localizations.test.js +187 -0
  130. package/services/__tests__/metrics.test.js +90 -0
  131. package/services/content-types.js +200 -0
  132. package/services/core-api.js +296 -0
  133. package/services/entity-service-decorator.js +155 -0
  134. package/services/iso-locales.js +9 -0
  135. package/services/locales.js +97 -0
  136. package/services/localizations.js +65 -0
  137. package/services/metrics.js +24 -0
  138. package/services/permissions/actions.js +124 -0
  139. package/services/permissions/engine.js +63 -0
  140. package/services/permissions/sections-builder.js +48 -0
  141. package/services/permissions.js +11 -0
  142. package/tests/content-manager/list-relation.test.e2e.js +122 -0
  143. package/tests/graphql.test.e2e.js +120 -0
  144. package/tests/locales.test.e2e.js +414 -0
  145. package/utils/index.js +20 -0
  146. package/validation/content-types.js +30 -0
  147. package/validation/locales.js +39 -0
@@ -0,0 +1,545 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ isLocalizedContentType,
5
+ getValidLocale,
6
+ getNewLocalizationsFrom,
7
+ getAndValidateRelatedEntity,
8
+ getNonLocalizedAttributes,
9
+ copyNonLocalizedAttributes,
10
+ fillNonLocalizedAttributes,
11
+ } = require('../content-types');
12
+
13
+ describe('content-types service', () => {
14
+ describe('isLocalizedContentType', () => {
15
+ test('Checks for the i18N option', () => {
16
+ expect(isLocalizedContentType({ pluginOptions: { i18n: { localized: false } } })).toBe(false);
17
+ expect(isLocalizedContentType({ pluginOptions: { i18n: { localized: true } } })).toBe(true);
18
+ });
19
+
20
+ test('Defaults to false', () => {
21
+ expect(isLocalizedContentType({})).toBe(false);
22
+ expect(isLocalizedContentType({ pluginOptions: {} })).toBe(false);
23
+ expect(isLocalizedContentType({ pluginOptions: { i18n: {} } })).toBe(false);
24
+ });
25
+ });
26
+
27
+ describe('getNonLocalizedAttributes', () => {
28
+ test('Uses the pluginOptions to detect non localized fields', () => {
29
+ expect(
30
+ getNonLocalizedAttributes({
31
+ uid: 'test-model',
32
+ attributes: {
33
+ title: {
34
+ type: 'string',
35
+ pluginOptions: {
36
+ i18n: {
37
+ localized: true,
38
+ },
39
+ },
40
+ },
41
+ stars: {
42
+ type: 'integer',
43
+ },
44
+ price: {
45
+ type: 'integer',
46
+ },
47
+ },
48
+ })
49
+ ).toEqual(['stars', 'price']);
50
+ });
51
+
52
+ test('Consider relations to be always localized', () => {
53
+ expect(
54
+ getNonLocalizedAttributes({
55
+ uid: 'test-model',
56
+ attributes: {
57
+ title: {
58
+ type: 'string',
59
+ pluginOptions: {
60
+ i18n: {
61
+ localized: true,
62
+ },
63
+ },
64
+ },
65
+ stars: {
66
+ type: 'integer',
67
+ },
68
+ price: {
69
+ type: 'integer',
70
+ },
71
+ relation: {
72
+ model: 'user',
73
+ },
74
+ secondRelation: {
75
+ collection: 'user',
76
+ },
77
+ },
78
+ })
79
+ ).toEqual(['stars', 'price']);
80
+ });
81
+
82
+ test('Consider locale, localizations & published_at as localized', () => {
83
+ expect(
84
+ getNonLocalizedAttributes({
85
+ uid: 'test-model',
86
+ attributes: {
87
+ title: {
88
+ type: 'string',
89
+ pluginOptions: {
90
+ i18n: {
91
+ localized: true,
92
+ },
93
+ },
94
+ },
95
+ stars: {
96
+ type: 'integer',
97
+ },
98
+ price: {
99
+ type: 'integer',
100
+ },
101
+ locale: {
102
+ type: 'string',
103
+ visible: false,
104
+ },
105
+ localizations: {
106
+ collection: 'test-model',
107
+ visible: false,
108
+ },
109
+ published_at: {
110
+ type: 'datetime',
111
+ visible: false,
112
+ },
113
+ },
114
+ })
115
+ ).toEqual(['stars', 'price']);
116
+ });
117
+
118
+ test('Consider uid to always be localized', () => {
119
+ expect(
120
+ getNonLocalizedAttributes({
121
+ attributes: {
122
+ price: {
123
+ type: 'integer',
124
+ },
125
+ slug: {
126
+ type: 'uid',
127
+ },
128
+ },
129
+ })
130
+ ).toEqual(['price']);
131
+ });
132
+ });
133
+
134
+ describe('getValidLocale', () => {
135
+ test('set default locale if the provided one is nil', async () => {
136
+ const getDefaultLocale = jest.fn(() => Promise.resolve('en'));
137
+ global.strapi = {
138
+ plugins: {
139
+ i18n: {
140
+ services: {
141
+ locales: {
142
+ getDefaultLocale,
143
+ },
144
+ },
145
+ },
146
+ },
147
+ };
148
+ const locale = await getValidLocale(null);
149
+
150
+ expect(locale).toBe('en');
151
+ });
152
+
153
+ test('set locale to the provided one if it exists', async () => {
154
+ const findByCode = jest.fn(() => Promise.resolve('en'));
155
+ global.strapi = {
156
+ plugins: {
157
+ i18n: {
158
+ services: {
159
+ locales: {
160
+ findByCode,
161
+ },
162
+ },
163
+ },
164
+ },
165
+ };
166
+ const locale = await getValidLocale('en');
167
+
168
+ expect(locale).toBe('en');
169
+ });
170
+
171
+ test("throw if provided locale doesn't exist", async () => {
172
+ const findByCode = jest.fn(() => Promise.resolve(undefined));
173
+ global.strapi = {
174
+ plugins: {
175
+ i18n: {
176
+ services: {
177
+ locales: {
178
+ findByCode,
179
+ },
180
+ },
181
+ },
182
+ },
183
+ };
184
+ try {
185
+ await getValidLocale('en');
186
+ } catch (e) {
187
+ expect(e.message).toBe('Locale not found');
188
+ }
189
+
190
+ expect(findByCode).toHaveBeenCalledWith('en');
191
+ expect.assertions(2);
192
+ });
193
+ });
194
+
195
+ describe.each([['singleType'], ['collectionType']])('getAndValidateRelatedEntity - %s', kind => {
196
+ test("Throw if relatedEntity is provided but doesn't exist", async () => {
197
+ const findOne = jest.fn(() => Promise.resolve(undefined));
198
+ const relatedEntityId = 1;
199
+ const model = 'application::country.country';
200
+ const locale = 'fr';
201
+
202
+ global.strapi = {
203
+ query: () => ({
204
+ findOne,
205
+ }),
206
+ getModel: () => ({ kind }),
207
+ };
208
+
209
+ try {
210
+ await getAndValidateRelatedEntity(relatedEntityId, model, locale);
211
+ } catch (e) {
212
+ expect(e.message).toBe("The related entity doesn't exist");
213
+ }
214
+
215
+ expect(findOne).toHaveBeenCalledWith(kind === 'singleType' ? {} : { id: relatedEntityId });
216
+ expect.assertions(2);
217
+ });
218
+
219
+ test('Throw if locale already exists (1/2)', async () => {
220
+ const relatedEntityId = 1;
221
+ const relatedEntity = {
222
+ id: relatedEntityId,
223
+ locale: 'en',
224
+ localizations: [],
225
+ };
226
+ const findOne = jest.fn(() => Promise.resolve(relatedEntity));
227
+ const model = 'application::country.country';
228
+ const locale = 'en';
229
+
230
+ global.strapi = {
231
+ query: () => ({
232
+ findOne,
233
+ }),
234
+ getModel: () => ({ kind }),
235
+ };
236
+
237
+ try {
238
+ await getAndValidateRelatedEntity(relatedEntityId, model, locale);
239
+ } catch (e) {
240
+ expect(e.message).toBe('The entity already exists in this locale');
241
+ }
242
+
243
+ expect(findOne).toHaveBeenCalledWith(kind === 'singleType' ? {} : { id: relatedEntityId });
244
+ expect.assertions(2);
245
+ });
246
+
247
+ test('Throw if locale already exists (2/2)', async () => {
248
+ const relatedEntityId = 1;
249
+ const relatedEntity = {
250
+ id: relatedEntityId,
251
+ locale: 'fr',
252
+ localizations: [
253
+ {
254
+ id: 2,
255
+ locale: 'en',
256
+ },
257
+ ],
258
+ };
259
+ const findOne = jest.fn(() => Promise.resolve(relatedEntity));
260
+ const model = 'application::country.country';
261
+ const locale = 'en';
262
+
263
+ global.strapi = {
264
+ query: () => ({
265
+ findOne,
266
+ }),
267
+ getModel: () => ({ kind }),
268
+ };
269
+
270
+ try {
271
+ await getAndValidateRelatedEntity(relatedEntityId, model, locale);
272
+ } catch (e) {
273
+ expect(e.message).toBe('The entity already exists in this locale');
274
+ }
275
+
276
+ expect(findOne).toHaveBeenCalledWith(kind === 'singleType' ? {} : { id: relatedEntityId });
277
+ expect.assertions(2);
278
+ });
279
+
280
+ test('get related entity', async () => {
281
+ const relatedEntityId = 1;
282
+ const relatedEntity = {
283
+ id: relatedEntityId,
284
+ locale: 'fr',
285
+ localizations: [
286
+ {
287
+ id: 2,
288
+ locale: 'en',
289
+ },
290
+ ],
291
+ };
292
+ const findOne = jest.fn(() => Promise.resolve(relatedEntity));
293
+ const model = 'application::country.country';
294
+ const locale = 'it';
295
+
296
+ global.strapi = {
297
+ query: () => ({
298
+ findOne,
299
+ }),
300
+ getModel: () => ({ kind }),
301
+ };
302
+
303
+ const foundEntity = await getAndValidateRelatedEntity(relatedEntityId, model, locale);
304
+
305
+ expect(foundEntity).toEqual(relatedEntity);
306
+ expect(findOne).toHaveBeenCalledWith(kind === 'singleType' ? {} : { id: relatedEntityId });
307
+ expect.assertions(2);
308
+ });
309
+ });
310
+
311
+ describe('getNewLocalizationsFrom', () => {
312
+ test('Can get localizations', async () => {
313
+ const relatedEntity = {
314
+ id: 1,
315
+ locale: 'fr',
316
+ localizations: [
317
+ {
318
+ id: 2,
319
+ locale: 'en',
320
+ },
321
+ {
322
+ id: 3,
323
+ locale: 'it',
324
+ },
325
+ ],
326
+ };
327
+
328
+ const localizations = await getNewLocalizationsFrom(relatedEntity);
329
+
330
+ expect(localizations).toEqual([1, 2, 3]);
331
+ });
332
+
333
+ test('Add empty localizations if none exist (CT)', async () => {
334
+ const localizations = await getNewLocalizationsFrom(undefined);
335
+
336
+ expect(localizations).toEqual([]);
337
+ });
338
+ });
339
+
340
+ describe('copyNonLocalizedAttributes', () => {
341
+ test('Does not copy locale, localizations & published_at', () => {
342
+ const model = {
343
+ attributes: {
344
+ title: {
345
+ type: 'string',
346
+ pluginOptions: {
347
+ i18n: { localized: true },
348
+ },
349
+ },
350
+ price: {
351
+ type: 'integer',
352
+ },
353
+ relation: {
354
+ model: 'user',
355
+ },
356
+ description: {
357
+ type: 'string',
358
+ },
359
+ locale: {
360
+ type: 'string',
361
+ visible: false,
362
+ },
363
+ localizations: {
364
+ collection: 'test-model',
365
+ visible: false,
366
+ },
367
+ published_at: {
368
+ type: 'datetime',
369
+ visible: false,
370
+ },
371
+ },
372
+ };
373
+
374
+ const input = {
375
+ id: 1,
376
+ title: 'My custom title',
377
+ price: 25,
378
+ relation: 1,
379
+ description: 'My super description',
380
+ locale: 'en',
381
+ localizations: [1, 2, 3],
382
+ published_at: '2021-03-18T09:47:37.557Z',
383
+ };
384
+
385
+ const result = copyNonLocalizedAttributes(model, input);
386
+ expect(result).toStrictEqual({
387
+ price: input.price,
388
+ description: input.description,
389
+ });
390
+ });
391
+
392
+ test('picks only non localized attributes', () => {
393
+ const model = {
394
+ attributes: {
395
+ title: {
396
+ type: 'string',
397
+ pluginOptions: {
398
+ i18n: { localized: true },
399
+ },
400
+ },
401
+ price: {
402
+ type: 'integer',
403
+ },
404
+ relation: {
405
+ model: 'user',
406
+ },
407
+ description: {
408
+ type: 'string',
409
+ },
410
+ },
411
+ };
412
+
413
+ const input = {
414
+ id: 1,
415
+ title: 'My custom title',
416
+ price: 25,
417
+ relation: 1,
418
+ description: 'My super description',
419
+ };
420
+
421
+ const result = copyNonLocalizedAttributes(model, input);
422
+ expect(result).toStrictEqual({
423
+ price: input.price,
424
+ description: input.description,
425
+ });
426
+ });
427
+
428
+ test('Removes ids', () => {
429
+ const compoModel = {
430
+ attributes: {
431
+ name: { type: 'string' },
432
+ },
433
+ };
434
+
435
+ global.strapi = {
436
+ db: {
437
+ getModelsByAttribute: jest.fn(() => [compoModel]),
438
+ },
439
+ };
440
+
441
+ const model = {
442
+ attributes: {
443
+ title: {
444
+ type: 'string',
445
+ pluginOptions: {
446
+ i18n: { localized: true },
447
+ },
448
+ },
449
+ price: {
450
+ type: 'integer',
451
+ },
452
+ relation: {
453
+ model: 'user',
454
+ },
455
+ component: {
456
+ type: 'component',
457
+ component: 'compo',
458
+ },
459
+ },
460
+ };
461
+
462
+ const input = {
463
+ id: 1,
464
+ title: 'My custom title',
465
+ price: 25,
466
+ relation: 1,
467
+ component: {
468
+ id: 2,
469
+ name: 'Hello',
470
+ },
471
+ };
472
+
473
+ const result = copyNonLocalizedAttributes(model, input);
474
+ expect(result).toEqual({
475
+ price: 25,
476
+ component: {
477
+ name: 'Hello',
478
+ },
479
+ });
480
+ });
481
+ });
482
+
483
+ describe('fillNonLocalizedAttributes', () => {
484
+ test('fill non localized attributes', () => {
485
+ const entry = {
486
+ a: 'a',
487
+ b: undefined,
488
+ c: null,
489
+ d: 1,
490
+ e: {},
491
+ la: 'a',
492
+ lb: undefined,
493
+ lc: null,
494
+ ld: 1,
495
+ le: {},
496
+ };
497
+
498
+ const relatedEntry = {
499
+ a: 'a',
500
+ b: 'b',
501
+ c: 'c',
502
+ d: 'd',
503
+ e: 'e',
504
+ la: 'la',
505
+ lb: 'lb',
506
+ lc: 'lc',
507
+ ld: 'ld',
508
+ le: 'le',
509
+ };
510
+
511
+ const modelDef = {
512
+ attributes: {
513
+ a: {},
514
+ b: {},
515
+ c: {},
516
+ d: {},
517
+ e: {},
518
+ la: { pluginOptions: { i18n: { localized: true } } },
519
+ lb: { pluginOptions: { i18n: { localized: true } } },
520
+ lc: { pluginOptions: { i18n: { localized: true } } },
521
+ ld: { pluginOptions: { i18n: { localized: true } } },
522
+ le: { pluginOptions: { i18n: { localized: true } } },
523
+ },
524
+ };
525
+
526
+ const getModel = jest.fn(() => modelDef);
527
+ global.strapi = { getModel };
528
+
529
+ fillNonLocalizedAttributes(entry, relatedEntry, { model: 'model' });
530
+
531
+ expect(entry).toEqual({
532
+ a: 'a',
533
+ b: 'b',
534
+ c: 'c',
535
+ d: 1,
536
+ e: {},
537
+ la: 'a',
538
+ lb: undefined,
539
+ lc: null,
540
+ ld: 1,
541
+ le: {},
542
+ });
543
+ });
544
+ });
545
+ });
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+ const { createSanitizer } = require('../core-api');
3
+
4
+ describe('Core API', () => {
5
+ describe('sanitizer', () => {
6
+ test('sanitizeInput keeps only writable fields', () => {
7
+ const contentType = {
8
+ attributes: {
9
+ title: {
10
+ type: 'string',
11
+ },
12
+ nonWritables: {
13
+ type: 'string',
14
+ writable: false,
15
+ },
16
+ },
17
+ };
18
+
19
+ const { sanitizeInput } = createSanitizer(contentType);
20
+
21
+ const input = {
22
+ title: 'test',
23
+ nonWritables: 'test',
24
+ };
25
+
26
+ const output = sanitizeInput(input);
27
+
28
+ expect(output).toStrictEqual({
29
+ title: 'test',
30
+ });
31
+ });
32
+
33
+ test('sanitizeInput excludes locale & localizations', () => {
34
+ const contentType = {
35
+ attributes: {
36
+ title: {
37
+ type: 'string',
38
+ },
39
+ nonWritables: {
40
+ type: 'string',
41
+ writable: false,
42
+ },
43
+ locale: {
44
+ type: 'string',
45
+ writable: true,
46
+ },
47
+ localizations: {
48
+ type: 'string',
49
+ writable: true,
50
+ },
51
+ },
52
+ };
53
+
54
+ const { sanitizeInput } = createSanitizer(contentType);
55
+
56
+ const input = {
57
+ title: 'test',
58
+ nonWritables: 'test',
59
+ locale: 'FR',
60
+ localizations: [1, 2],
61
+ };
62
+
63
+ const output = sanitizeInput(input);
64
+
65
+ expect(output).toStrictEqual({
66
+ title: 'test',
67
+ });
68
+ });
69
+
70
+ test('sanitizeInputFiles keeps only writable fields', () => {
71
+ const contentType = {
72
+ attributes: {
73
+ title: {
74
+ type: 'string',
75
+ },
76
+ nonWritableCompo: {
77
+ type: 'component',
78
+ writable: false,
79
+ },
80
+ writableCompo: {
81
+ type: 'component',
82
+ writable: true,
83
+ },
84
+ image: {
85
+ model: 'file',
86
+ plugin: 'upload',
87
+ writable: false,
88
+ },
89
+ },
90
+ };
91
+
92
+ const { sanitizeInputFiles } = createSanitizer(contentType);
93
+
94
+ const input = {
95
+ 'writableCompo.image': {},
96
+ 'nonWritableCompo.image': {},
97
+ };
98
+
99
+ const output = sanitizeInputFiles(input);
100
+
101
+ expect(output).toStrictEqual({
102
+ 'writableCompo.image': {},
103
+ });
104
+ });
105
+ });
106
+ });