@localazy/strapi-plugin 0.1.10 → 0.1.11-rc.1

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 (59) hide show
  1. package/.eslintrc +6 -2
  2. package/admin/src/modules/@common/models/supported-content-type-fields.js +8 -0
  3. package/admin/src/modules/plugin-settings/components/ContentTransferSetup/index.js +5 -0
  4. package/admin/src/modules/plugin-settings/components/Tree/index.js +22 -5
  5. package/admin/src/modules/plugin-settings/functions/build-content-transfer-setup-schema.js +1 -1
  6. package/admin/src/modules/plugin-settings/functions/has-model-changed.js +1 -1
  7. package/admin/src/modules/plugin-settings/locale/en.js +1 -1
  8. package/admin/src/modules/plugin-settings/utils/get-filtered-models-schemas.js +1 -7
  9. package/admin/src/modules/plugin-settings/utils/get-models-tree.js +21 -3
  10. package/package.json +4 -4
  11. package/server/bootstrap.js +15 -1
  12. package/server/controllers/localazy-transfer-controller.js +67 -52
  13. package/server/functions/should-set-downloaded-property.js +61 -0
  14. package/server/models/supported-content-type-fields.js +8 -0
  15. package/server/services/index.js +2 -0
  16. package/server/services/strapi-i18n-service.js +5 -4
  17. package/server/services/strapi-localazy-i18n-service.js +104 -0
  18. package/server/tests/fixtures/parsed-localazy-entry-to-create-entry-cookbook.js +5761 -0
  19. package/server/tests/fixtures/parsed-localazy-entry-to-create-entry-lesson-dz.js +392 -0
  20. package/server/tests/fixtures/parsed-localazy-entry-to-create-entry-restaurant-simple-menu.js +536 -0
  21. package/server/tests/fixtures/parsed-localazy-entry-to-create-entry-sample-json-dz.js +4675 -0
  22. package/server/tests/fixtures/parsed-localazy-entry-to-update-entry.js +35157 -0
  23. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-cookbook-empty-recipes.js +202 -0
  24. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-cookbook.js +2700 -0
  25. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-lesson-dz.js +309 -0
  26. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-restaurant-simple-flat-simple.js +47 -0
  27. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-restaurant-simple-flat-with-media.js +169 -0
  28. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-restaurant-simple-menu-empty.js +3003 -0
  29. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-restaurant-simple-menu-with-media.js +2057 -0
  30. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-sample-json-dz.js +884 -0
  31. package/server/tests/fixtures/populate-create-update-entry-with-base-entry-sample-json.js +46 -0
  32. package/server/tests/fixtures/strapi-plugin-all-models.js +2048 -0
  33. package/server/utils/__tests__/get-models-tree.test.js +1 -1
  34. package/server/utils/__tests__/parsed-localazy-entry-to-create-entry.test.js +237 -91
  35. package/server/utils/__tests__/parsed-localazy-entry-to-update-entry.test.js +417 -101
  36. package/server/utils/__tests__/pick-entries.test.js +936 -56
  37. package/server/utils/__tests__/populate-create-update-entry-with-base-entry.test.js +1139 -0
  38. package/server/utils/build-populate.js +5 -0
  39. package/server/utils/get-full-populate-object.js +56 -0
  40. package/server/utils/get-models-tree.js +3 -1
  41. package/server/utils/model-utils.js +43 -0
  42. package/server/utils/omit-deep.js +7 -0
  43. package/server/utils/parsed-localazy-entry-to-create-entry.js +58 -21
  44. package/server/utils/parsed-localazy-entry-to-update-entry.js +44 -4
  45. package/server/utils/pick-deep.js +22 -0
  46. package/server/utils/pick-entries.js +90 -5
  47. package/server/utils/populate-create-update-entry-with-base-entry.js +270 -0
  48. package/server/utils/transfer-setup-utils.js +14 -0
  49. package/server/tests/fixtures/all-models-with-multimedia.js +0 -1064
  50. package/server/tests/fixtures/collection-flattened.js +0 -76
  51. package/server/tests/fixtures/restaurant-flattened.js +0 -46
  52. package/server/tests/fixtures/restaurant-model.js +0 -230
  53. package/server/tests/fixtures/restaurants-entries.js +0 -152
  54. package/server/tests/fixtures/restaurants-pick-paths.js +0 -15
  55. package/server/tests/fixtures/strapi-book-with-multimedia-components-cs.js +0 -31
  56. package/server/tests/fixtures/stringified-book-cs.js +0 -3
  57. package/server/tests/fixtures/stringified-book-with-multimedia-components-cs.js +0 -3
  58. package/server/tests/fixtures/stringified-restaurant-cs.js +0 -3
  59. package/server/tests/fixtures/stringified-restaurant-de.js +0 -5
@@ -0,0 +1,270 @@
1
+ "use strict";
2
+
3
+ const cloneDeep = require("lodash/cloneDeep");
4
+ const set = require("lodash/set");
5
+ const get = require("lodash/get");
6
+ const isEmpty = require("lodash/isEmpty");
7
+ const {
8
+ getAttribute,
9
+ isComponent,
10
+ isRepeatable,
11
+ isDynamicZone,
12
+ isRelation,
13
+ findModel
14
+ } = require("./model-utils");
15
+
16
+ const doesExistInPopulatedLocalizedEntry = (val) => {
17
+ if (Array.isArray(val)) {
18
+ // is array
19
+ return !!val.length;
20
+ }
21
+
22
+ if (typeof val === "object") {
23
+ // is object
24
+ return !isEmpty(val);
25
+ }
26
+
27
+ if (val !== Object(val)) {
28
+ // is primitive
29
+ return !!val;
30
+ }
31
+ }
32
+
33
+ const getNewPrefix = (objectKey, prefix) => {
34
+ return prefix ? `${prefix}.${objectKey}` : objectKey;
35
+ };
36
+
37
+ const populateCreateUpdateEntryWithBaseEntry = async (
38
+ models,
39
+ createUpdateEntry,
40
+ baseEntry,
41
+ populatedLocalizedEntry,
42
+ uid,
43
+ locale
44
+ ) => {
45
+ const populatedEntry = cloneDeep(createUpdateEntry);
46
+
47
+ const populateEntry = async (
48
+ partialBaseEntry,
49
+ model,
50
+ objectKey = "",
51
+ prefix = "",
52
+ component = "",
53
+ isRepeatableComponent = false,
54
+ isDZ = false,
55
+ ) => {
56
+ if (Array.isArray(partialBaseEntry)) {
57
+ // is array
58
+ const attribute = getAttribute(model, objectKey);
59
+
60
+ if (typeof attribute !== 'undefined') {
61
+ const newPrefix = getNewPrefix(objectKey, prefix);
62
+ const inCreateUpdateEntry = get(createUpdateEntry, newPrefix);
63
+ // TODO: decide whether add || inCreateUpdateEntry === null to the condition
64
+ const isMissingInCreateUpdateEntry = !!(typeof inCreateUpdateEntry === 'undefined');
65
+ if (isMissingInCreateUpdateEntry) {
66
+ const populatedLocalizedEntryVal = get(populatedLocalizedEntry, newPrefix);
67
+ if (doesExistInPopulatedLocalizedEntry(populatedLocalizedEntryVal)) {
68
+ set(populatedEntry, newPrefix, populatedLocalizedEntryVal);
69
+ } else {
70
+ set(populatedEntry, newPrefix, partialBaseEntry);
71
+ }
72
+ } else {
73
+ for (const [objectKey, value] of Object.entries(entry)) {
74
+ await populateEntry(
75
+ value,
76
+ model,
77
+ objectKey,
78
+ newPrefix
79
+ );
80
+ }
81
+ }
82
+ } else if (!component && isRepeatableComponent && isDZ) {
83
+ Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
84
+ const component = partialBaseEntryItem.__component;
85
+ const model = findModel(models, component);
86
+ const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
87
+ await populateEntry(
88
+ partialBaseEntryItem,
89
+ model,
90
+ partialBaseEntryItemIndex,
91
+ newPrefix,
92
+ );
93
+ });
94
+ } else if (component && isRepeatableComponent) {
95
+ Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
96
+ const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
97
+ await populateEntry(
98
+ partialBaseEntryItem,
99
+ model,
100
+ partialBaseEntryItemIndex,
101
+ newPrefix,
102
+ );
103
+ });
104
+ }
105
+
106
+ } else if (typeof partialBaseEntry === "object") {
107
+ // is object
108
+ if (partialBaseEntry === null) {
109
+ partialBaseEntry = {};
110
+ }
111
+
112
+ for (const [objectKey, value] of Object.entries(partialBaseEntry)) {
113
+ const attribute = getAttribute(model, objectKey);
114
+ if (typeof attribute === 'undefined' && objectKey === '__component') {
115
+ const newPrefix = getNewPrefix(objectKey, prefix);
116
+ set(populatedEntry, newPrefix, value);
117
+ } else if (typeof attribute === 'undefined') {
118
+ // skip...
119
+ continue;
120
+ } else if (isComponent(attribute)) {
121
+ // is component
122
+ const component = attribute.component;
123
+ const componentModel = findModel(models, component);
124
+
125
+ const newPrefix = getNewPrefix(objectKey, prefix);
126
+ const inCreateUpdateEntry = get(createUpdateEntry, newPrefix);
127
+ let isMissingInCreateUpdateEntry;
128
+ if (isRepeatable(attribute)) {
129
+ isMissingInCreateUpdateEntry = !!((typeof inCreateUpdateEntry === 'undefined') || (inCreateUpdateEntry && !inCreateUpdateEntry.length));
130
+ } else {
131
+ isMissingInCreateUpdateEntry = !!(typeof inCreateUpdateEntry === 'undefined' || inCreateUpdateEntry === null);
132
+ }
133
+
134
+ if (isMissingInCreateUpdateEntry) {
135
+ const populatedLocalizedEntryVal = get(populatedLocalizedEntry, newPrefix);
136
+ let valueToSet = value;
137
+ if (doesExistInPopulatedLocalizedEntry(populatedLocalizedEntryVal)) {
138
+ valueToSet = populatedLocalizedEntryVal;
139
+ }
140
+ if (isRepeatable(attribute)) {
141
+ valueToSet = value.map((item) => {
142
+ delete item.id;
143
+ return {
144
+ __component: component,
145
+ ...item,
146
+ };
147
+ });
148
+ } else {
149
+ if (!isEmpty(valueToSet)) {
150
+ delete valueToSet.id;
151
+ valueToSet.__component = component;
152
+ }
153
+ }
154
+ set(populatedEntry, newPrefix, valueToSet);
155
+ }
156
+ await populateEntry(
157
+ value,
158
+ componentModel,
159
+ objectKey,
160
+ newPrefix,
161
+ component,
162
+ isRepeatable(attribute),
163
+ );
164
+ } else if (isDynamicZone(attribute)) {
165
+ // is dynamic zone
166
+ const newPrefix = getNewPrefix(objectKey, prefix);
167
+ const inCreateUpdateEntry = get(createUpdateEntry, newPrefix);
168
+ const isMissingInCreateUpdateEntry = !!((typeof inCreateUpdateEntry === 'undefined') || (inCreateUpdateEntry && !inCreateUpdateEntry.length));
169
+
170
+ if (isMissingInCreateUpdateEntry) {
171
+ const populatedLocalizedEntryVal = get(populatedLocalizedEntry, newPrefix);
172
+ let valueToSet = value;
173
+ if (doesExistInPopulatedLocalizedEntry(populatedLocalizedEntryVal)) {
174
+ valueToSet = populatedLocalizedEntryVal;
175
+ }
176
+ valueToSet = value.map((item) => {
177
+ delete item.id;
178
+ return {
179
+ __component: component,
180
+ ...item,
181
+ };
182
+ });
183
+ set(populatedEntry, newPrefix, valueToSet);
184
+ }
185
+ await populateEntry(
186
+ value,
187
+ "", // model is evaluated later as it's dynamic (DZ)
188
+ objectKey,
189
+ newPrefix,
190
+ "", // component is computed later as it's dynamic (DZ)
191
+ true,
192
+ true,
193
+ );
194
+ // }
195
+ } else if (isRelation(attribute)) {
196
+ const newPrefix = getNewPrefix(objectKey, prefix);
197
+ const populatedLocalizedEntryVal = get(populatedLocalizedEntry, newPrefix);
198
+ if (doesExistInPopulatedLocalizedEntry(populatedLocalizedEntryVal)) {
199
+ // skip...
200
+ continue;
201
+ }
202
+
203
+ const isArray = Array.isArray(value);
204
+ let arraiedValue = value;
205
+ if (!isArray) {
206
+ arraiedValue = [value];
207
+ }
208
+ for (const [index, item] of Object.entries(arraiedValue)) {
209
+ if (!isEmpty(item)) {
210
+ const entityId = item.id;
211
+ if (!!entityId) {
212
+ const entryWithLocalizations = await strapi.entityService.findOne(attribute.target, entityId, {
213
+ populate: ['localizations'],
214
+ });
215
+
216
+ const localizedEntry = entryWithLocalizations.localizations.find((item) => item.locale === locale);
217
+ if (!!localizedEntry && localizedEntry.id) {
218
+ if (!isArray) {
219
+ set(populatedEntry, newPrefix, { id: localizedEntry.id });
220
+ } else {
221
+ set(populatedEntry, `${newPrefix}.${index}`, { id: localizedEntry.id });
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ } else {
228
+ const newPrefix = getNewPrefix(objectKey, prefix);
229
+ const inCreateUpdateEntry = get(createUpdateEntry, newPrefix);
230
+ const isMissingInCreateUpdateEntry = !!(typeof inCreateUpdateEntry === 'undefined' || inCreateUpdateEntry === null);
231
+ if (isMissingInCreateUpdateEntry) {
232
+ const populatedLocalizedEntryVal = get(populatedLocalizedEntry, newPrefix);
233
+ if (doesExistInPopulatedLocalizedEntry(populatedLocalizedEntryVal)) {
234
+ set(populatedEntry, newPrefix, populatedLocalizedEntryVal);
235
+ } else {
236
+ set(populatedEntry, newPrefix, value);
237
+ }
238
+ } else {
239
+ await populateEntry(
240
+ value,
241
+ model,
242
+ objectKey,
243
+ newPrefix
244
+ );
245
+ }
246
+ }
247
+ }
248
+ } else if (partialBaseEntry !== Object(partialBaseEntry)) {
249
+ // is primitive/literal
250
+ const attribute = getAttribute(model, objectKey);
251
+ if (typeof attribute !== 'undefined') {
252
+ const inCreateUpdateEntry = get(createUpdateEntry, prefix);
253
+ const isMissingInCreateUpdateEntry = !!(typeof inCreateUpdateEntry === 'undefined' || inCreateUpdateEntry === null);
254
+ if (isMissingInCreateUpdateEntry) {
255
+ set(populatedEntry, prefix, partialBaseEntry);
256
+ }
257
+ }
258
+ } else {
259
+ // ? TODO: something unknown
260
+ console.info(`Unknown type processed: ${partialBaseEntry}`);
261
+ }
262
+ }
263
+
264
+ const model = findModel(models, uid);
265
+ await populateEntry(baseEntry, model);
266
+
267
+ return populatedEntry;
268
+ };
269
+
270
+ module.exports = populateCreateUpdateEntryWithBaseEntry;
@@ -5,6 +5,19 @@ const findSetupModelByCollectionName = (models, collectionName) => {
5
5
  return models.find((model) => Object.keys(model)[0] === collectionName);
6
6
  };
7
7
 
8
+ const findSetupModelByCollectionUid = (
9
+ contentTransferSetup,
10
+ strapiContentTypesModels,
11
+ collectionUid
12
+ ) => {
13
+ const currentModel = strapiContentTypesModels.find(
14
+ (model) => model.uid === collectionUid
15
+ );
16
+ const modelContentTransferSetup = contentTransferSetup.setup
17
+ .find((model) => Object.keys(model)[0] === currentModel.collectionName);
18
+ return modelContentTransferSetup[currentModel.collectionName];
19
+ }
20
+
8
21
  const getCollectionsNames = (setup) => {
9
22
  return getMainKeysOfNestedArrayObjects(setup);
10
23
  };
@@ -33,6 +46,7 @@ const getPickPaths = (transferSetupModelProps) => {
33
46
 
34
47
  module.exports = {
35
48
  findSetupModelByCollectionName,
49
+ findSetupModelByCollectionUid,
36
50
  getCollectionsNames,
37
51
  isCollectionTransferEnabled,
38
52
  getPickPaths,