@contentstack/cli-cm-import 1.5.11 → 1.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.
- package/README.md +6 -14
- package/bin/dev +17 -0
- package/bin/dev.cmd +3 -0
- package/bin/run +6 -0
- package/bin/run.cmd +3 -0
- package/lib/commands/cm/stacks/import.d.ts +10 -0
- package/lib/commands/cm/stacks/import.js +111 -0
- package/lib/config/index.d.ts +3 -0
- package/lib/config/index.js +395 -0
- package/lib/import/index.d.ts +1 -0
- package/lib/import/index.js +8 -0
- package/lib/import/module-importer.d.ts +13 -0
- package/lib/import/module-importer.js +70 -0
- package/lib/import/modules/assets.d.ts +63 -0
- package/lib/import/modules/assets.js +265 -0
- package/lib/import/modules/base-class.d.ts +70 -0
- package/lib/import/modules/base-class.js +218 -0
- package/lib/import/modules/content-types.d.ts +56 -0
- package/lib/import/modules/content-types.js +186 -0
- package/lib/import/modules/custom-roles.d.ts +37 -0
- package/lib/import/modules/custom-roles.js +171 -0
- package/lib/import/modules/environments.d.ts +27 -0
- package/lib/import/modules/environments.js +106 -0
- package/lib/import/modules/extensions.d.ts +27 -0
- package/lib/import/modules/extensions.js +106 -0
- package/lib/import/modules/global-fields.d.ts +34 -0
- package/lib/import/modules/global-fields.js +99 -0
- package/lib/import/modules/index.d.ts +2 -0
- package/lib/import/modules/index.js +19 -0
- package/lib/import/modules/labels.d.ts +34 -0
- package/lib/import/modules/labels.js +171 -0
- package/lib/import/modules/locales.d.ts +31 -0
- package/lib/import/modules/locales.js +144 -0
- package/lib/import/modules/marketplace-apps.d.ts +51 -0
- package/lib/import/modules/marketplace-apps.js +297 -0
- package/lib/import/modules/webhooks.d.ts +27 -0
- package/lib/import/modules/webhooks.js +110 -0
- package/lib/import/modules-js/assets.d.ts +33 -0
- package/lib/import/modules-js/assets.js +415 -0
- package/lib/import/modules-js/content-types.d.ts +33 -0
- package/lib/import/modules-js/content-types.js +176 -0
- package/lib/import/modules-js/custom-roles.d.ts +15 -0
- package/lib/import/modules-js/custom-roles.js +143 -0
- package/lib/import/modules-js/entries.d.ts +54 -0
- package/lib/import/modules-js/entries.js +1260 -0
- package/lib/import/modules-js/environments.d.ts +13 -0
- package/lib/import/modules-js/environments.js +85 -0
- package/lib/import/modules-js/extensions.d.ts +18 -0
- package/lib/import/modules-js/extensions.js +86 -0
- package/lib/import/modules-js/global-fields.d.ts +13 -0
- package/lib/import/modules-js/global-fields.js +109 -0
- package/lib/import/modules-js/index.d.ts +1 -0
- package/lib/import/modules-js/index.js +33 -0
- package/lib/import/modules-js/labels.d.ts +20 -0
- package/lib/import/modules-js/labels.js +148 -0
- package/lib/import/modules-js/locales.d.ts +24 -0
- package/lib/import/modules-js/locales.js +196 -0
- package/lib/import/modules-js/marketplace-apps.d.ts +60 -0
- package/lib/import/modules-js/marketplace-apps.js +409 -0
- package/lib/import/modules-js/webhooks.d.ts +17 -0
- package/lib/import/modules-js/webhooks.js +85 -0
- package/lib/import/modules-js/workflows.d.ts +18 -0
- package/lib/import/modules-js/workflows.js +132 -0
- package/lib/types/default-config.d.ts +143 -0
- package/lib/types/default-config.js +2 -0
- package/lib/types/import-config.d.ts +52 -0
- package/lib/types/import-config.js +2 -0
- package/lib/types/index.d.ts +63 -0
- package/lib/types/index.js +4 -0
- package/lib/utils/asset-helper.d.ts +4 -0
- package/lib/utils/asset-helper.js +387 -0
- package/lib/utils/backup-handler.d.ts +2 -0
- package/lib/utils/backup-handler.js +31 -0
- package/lib/utils/common-helper.d.ts +20 -0
- package/lib/utils/common-helper.js +244 -0
- package/lib/utils/content-type-helper.d.ts +51 -0
- package/lib/utils/content-type-helper.js +145 -0
- package/lib/utils/entries-helper.d.ts +4 -0
- package/lib/utils/entries-helper.js +252 -0
- package/lib/utils/extension-helper.d.ts +5 -0
- package/lib/utils/extension-helper.js +84 -0
- package/lib/utils/file-helper.d.ts +14 -0
- package/lib/utils/file-helper.js +140 -0
- package/lib/utils/import-config-handler.d.ts +3 -0
- package/lib/utils/import-config-handler.js +73 -0
- package/lib/utils/index.d.ts +12 -0
- package/lib/utils/index.js +39 -0
- package/lib/utils/interactive.d.ts +7 -0
- package/lib/utils/interactive.js +88 -0
- package/lib/utils/logger.d.ts +8 -0
- package/lib/utils/logger.js +154 -0
- package/lib/utils/login-handler.d.ts +8 -0
- package/lib/utils/login-handler.js +53 -0
- package/lib/utils/marketplace-app-helper.d.ts +16 -0
- package/lib/utils/marketplace-app-helper.js +143 -0
- package/messages/index.json +1 -7
- package/oclif.manifest.json +2 -2
- package/package.json +46 -20
- package/src/app.js +0 -217
- package/src/commands/cm/stacks/import.js +0 -161
- package/src/config/default.js +0 -352
- package/src/lib/import/assets.js +0 -495
- package/src/lib/import/content-types.js +0 -201
- package/src/lib/import/custom-roles.js +0 -169
- package/src/lib/import/entries.js +0 -1495
- package/src/lib/import/environments.js +0 -106
- package/src/lib/import/extensions.js +0 -108
- package/src/lib/import/global-fields.js +0 -135
- package/src/lib/import/labels.js +0 -175
- package/src/lib/import/locales.js +0 -216
- package/src/lib/import/marketplace-apps.js +0 -542
- package/src/lib/import/webhooks.js +0 -113
- package/src/lib/import/workflows.js +0 -166
- package/src/lib/util/extensionsUidReplace.js +0 -67
- package/src/lib/util/fs.js +0 -124
- package/src/lib/util/import-flags.js +0 -187
- package/src/lib/util/index.js +0 -222
- package/src/lib/util/log.js +0 -144
- package/src/lib/util/login.js +0 -58
- package/src/lib/util/lookupReplaceAssets.js +0 -366
- package/src/lib/util/lookupReplaceEntries.js +0 -250
- package/src/lib/util/marketplace-app-helper.js +0 -31
- package/src/lib/util/removeReferenceFields.js +0 -59
- package/src/lib/util/schemaTemplate.js +0 -38
- package/src/lib/util/supress-mandatory-fields.js +0 -34
- package/src/lib/util/upload.js +0 -56
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
|
|
5
|
+
const last_1 = tslib_1.__importDefault(require("lodash/last"));
|
|
6
|
+
const chunk_1 = tslib_1.__importDefault(require("lodash/chunk"));
|
|
7
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
8
|
+
const entries_1 = tslib_1.__importDefault(require("lodash/entries"));
|
|
9
|
+
const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
|
|
10
|
+
const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
|
|
11
|
+
const utils_1 = require("../../utils");
|
|
12
|
+
class BaseClass {
|
|
13
|
+
constructor({ importConfig, stackAPIClient }) {
|
|
14
|
+
this.client = stackAPIClient;
|
|
15
|
+
this.importConfig = importConfig;
|
|
16
|
+
this.modulesConfig = importConfig.modules;
|
|
17
|
+
}
|
|
18
|
+
get stack() {
|
|
19
|
+
return this.client;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @method delay
|
|
23
|
+
* @param {number} ms number
|
|
24
|
+
* @returns {Promise} Promise<void>
|
|
25
|
+
*/
|
|
26
|
+
delay(ms) {
|
|
27
|
+
/* eslint-disable no-promise-executor-return */
|
|
28
|
+
return new Promise((resolve) => setTimeout(resolve, ms <= 0 ? 0 : ms));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @method makeConcurrentCall
|
|
32
|
+
* @param {Record<string, any>} env EnvType
|
|
33
|
+
* @param {CustomPromiseHandler} promisifyHandler CustomPromiseHandler
|
|
34
|
+
* @param {boolean} logBatchCompletionMsg boolean
|
|
35
|
+
* @returns {Promise} Promise<void>
|
|
36
|
+
*/
|
|
37
|
+
makeConcurrentCall(env, promisifyHandler, logBatchCompletionMsg = true) {
|
|
38
|
+
const { apiParams, apiContent, processName, indexerCount, currentIndexer, concurrencyLimit = this.importConfig.modules.apiConcurrency, } = env;
|
|
39
|
+
/* eslint-disable no-async-promise-executor */
|
|
40
|
+
return new Promise(async (resolve) => {
|
|
41
|
+
let batchNo = 0;
|
|
42
|
+
let isLastRequest = false;
|
|
43
|
+
const batches = (0, chunk_1.default)(apiContent, concurrencyLimit);
|
|
44
|
+
/* eslint-disable no-promise-executor-return */
|
|
45
|
+
if ((0, isEmpty_1.default)(batches))
|
|
46
|
+
return resolve();
|
|
47
|
+
for (const [batchIndex, batch] of (0, entries_1.default)(batches)) {
|
|
48
|
+
batchNo += 1;
|
|
49
|
+
const allPromise = [];
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
for (const [index, element] of (0, entries_1.default)(batch)) {
|
|
52
|
+
let promise = Promise.resolve();
|
|
53
|
+
isLastRequest = (0, isEqual_1.default)((0, last_1.default)(batch), element) && (0, isEqual_1.default)((0, last_1.default)(batches), batch);
|
|
54
|
+
if (promisifyHandler instanceof Function) {
|
|
55
|
+
promise = promisifyHandler({
|
|
56
|
+
apiParams,
|
|
57
|
+
isLastRequest,
|
|
58
|
+
element,
|
|
59
|
+
index: Number(index),
|
|
60
|
+
batchIndex: Number(batchIndex),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else if (apiParams) {
|
|
64
|
+
apiParams.apiData = element;
|
|
65
|
+
promise = this.makeAPICall(apiParams, isLastRequest);
|
|
66
|
+
}
|
|
67
|
+
allPromise.push(promise);
|
|
68
|
+
}
|
|
69
|
+
/* eslint-disable no-await-in-loop */
|
|
70
|
+
await Promise.allSettled(allPromise);
|
|
71
|
+
/* eslint-disable no-await-in-loop */
|
|
72
|
+
await this.logMsgAndWaitIfRequired(processName, start, batches.length, batchNo, logBatchCompletionMsg, indexerCount, currentIndexer);
|
|
73
|
+
if (isLastRequest)
|
|
74
|
+
resolve();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @method logMsgAndWaitIfRequired
|
|
80
|
+
* @param {string} processName string
|
|
81
|
+
* @param {number} start number
|
|
82
|
+
* @param {number} batchNo - number
|
|
83
|
+
* @returns {Promise} Promise<void>
|
|
84
|
+
*/
|
|
85
|
+
async logMsgAndWaitIfRequired(processName, start, totelBatches, batchNo, logBatchCompletionMsg = true, indexerCount, currentIndexer) {
|
|
86
|
+
const end = Date.now();
|
|
87
|
+
const exeTime = end - start;
|
|
88
|
+
if (logBatchCompletionMsg) {
|
|
89
|
+
let batchMsg = '';
|
|
90
|
+
// info: Batch No. 20 of import assets is complete
|
|
91
|
+
if (currentIndexer)
|
|
92
|
+
batchMsg += `Current chunk processing is (${currentIndexer}/${indexerCount})`;
|
|
93
|
+
(0, utils_1.log)(this.importConfig, `Batch No. (${batchNo}/${totelBatches}) of ${processName} is complete. ${batchMsg}`, 'success');
|
|
94
|
+
}
|
|
95
|
+
if (this.importConfig.modules.assets.displayExecutionTime) {
|
|
96
|
+
console.log(`Time taken to execute: ${exeTime} milliseconds; wait time: ${exeTime < 1000 ? 1000 - exeTime : 0} milliseconds`);
|
|
97
|
+
}
|
|
98
|
+
if (exeTime < 1000)
|
|
99
|
+
await this.delay(1000 - exeTime);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* @method makeAPICall
|
|
103
|
+
* @param {Record<string, any>} apiOptions - Api related params
|
|
104
|
+
* @param {Record<string, any>} isLastRequest - Boolean
|
|
105
|
+
* @return {Promise} Promise<void>
|
|
106
|
+
*/
|
|
107
|
+
makeAPICall(apiOptions, isLastRequest = false) {
|
|
108
|
+
if (apiOptions.serializeData instanceof Function) {
|
|
109
|
+
apiOptions = apiOptions.serializeData(apiOptions);
|
|
110
|
+
}
|
|
111
|
+
const { uid, entity, reject, resolve, apiData, additionalInfo, includeParamOnCompletion } = apiOptions;
|
|
112
|
+
const onSuccess = (response) => resolve({
|
|
113
|
+
response,
|
|
114
|
+
isLastRequest,
|
|
115
|
+
additionalInfo,
|
|
116
|
+
apiData: includeParamOnCompletion ? apiData : undefined,
|
|
117
|
+
});
|
|
118
|
+
const onReject = (error) => reject({
|
|
119
|
+
error,
|
|
120
|
+
isLastRequest,
|
|
121
|
+
additionalInfo,
|
|
122
|
+
apiData: includeParamOnCompletion ? apiData : undefined,
|
|
123
|
+
});
|
|
124
|
+
switch (entity) {
|
|
125
|
+
case 'create-assets-folder':
|
|
126
|
+
return this.stack
|
|
127
|
+
.asset()
|
|
128
|
+
.folder()
|
|
129
|
+
.create({ asset: (0, pick_1.default)(apiData, this.modulesConfig.assets.folderValidKeys) })
|
|
130
|
+
.then(onSuccess)
|
|
131
|
+
.catch(onReject);
|
|
132
|
+
case 'create-assets':
|
|
133
|
+
return this.stack
|
|
134
|
+
.asset()
|
|
135
|
+
.create((0, pick_1.default)(apiData, [...this.modulesConfig.assets.validKeys, 'upload']))
|
|
136
|
+
.then(onSuccess)
|
|
137
|
+
.catch(onReject);
|
|
138
|
+
case 'replace-assets':
|
|
139
|
+
return this.stack
|
|
140
|
+
.asset(uid)
|
|
141
|
+
.replace((0, pick_1.default)(apiData, [...this.modulesConfig.assets.validKeys, 'upload']))
|
|
142
|
+
.then(onSuccess)
|
|
143
|
+
.catch(onReject);
|
|
144
|
+
case 'publish-assets':
|
|
145
|
+
return this.stack
|
|
146
|
+
.asset(uid)
|
|
147
|
+
.publish((0, pick_1.default)(apiData, ['publishDetails']))
|
|
148
|
+
.then(onSuccess)
|
|
149
|
+
.catch(onReject);
|
|
150
|
+
case 'create-extensions':
|
|
151
|
+
return this.stack
|
|
152
|
+
.extension()
|
|
153
|
+
.create({ extension: (0, omit_1.default)(apiData, ['uid']) })
|
|
154
|
+
.then(onSuccess)
|
|
155
|
+
.catch(onReject);
|
|
156
|
+
case 'create-locale':
|
|
157
|
+
return this.stack
|
|
158
|
+
.locale()
|
|
159
|
+
.create({ locale: (0, pick_1.default)(apiData, ['name', 'code']) })
|
|
160
|
+
.then(onSuccess)
|
|
161
|
+
.catch(onReject);
|
|
162
|
+
case 'update-locale':
|
|
163
|
+
return this.stack
|
|
164
|
+
.locale(apiData.code)
|
|
165
|
+
.update({ locale: (0, pick_1.default)(apiData, [...this.modulesConfig.locales.requiredKeys]) })
|
|
166
|
+
.then(onSuccess)
|
|
167
|
+
.catch(onReject);
|
|
168
|
+
case 'create-cts':
|
|
169
|
+
return this.stack.contentType().create(apiData).then(onSuccess).catch(onReject);
|
|
170
|
+
case 'update-cts':
|
|
171
|
+
return apiData.update().then(onSuccess).catch(onReject);
|
|
172
|
+
case 'update-gfs':
|
|
173
|
+
return apiData.update().then(onSuccess).catch(onReject);
|
|
174
|
+
case 'create-environments':
|
|
175
|
+
// return this.stack
|
|
176
|
+
// .environment()
|
|
177
|
+
// .create({ environment: omit(apiData, ['uid']) as EnvironmentData })
|
|
178
|
+
// .then(onSuccess)
|
|
179
|
+
// .catch(onReject);
|
|
180
|
+
case 'create-labels':
|
|
181
|
+
return this.stack
|
|
182
|
+
.label()
|
|
183
|
+
.create({ label: (0, omit_1.default)(apiData, ['uid']) })
|
|
184
|
+
.then(onSuccess)
|
|
185
|
+
.catch(onReject);
|
|
186
|
+
case 'update-labels':
|
|
187
|
+
return this.stack
|
|
188
|
+
.label(apiData.uid)
|
|
189
|
+
.fetch()
|
|
190
|
+
.then(async (response) => {
|
|
191
|
+
response.parent = apiData.parent;
|
|
192
|
+
await response.update().then(onSuccess).catch(onReject);
|
|
193
|
+
})
|
|
194
|
+
.catch(onReject);
|
|
195
|
+
case 'create-webhooks':
|
|
196
|
+
return this.stack
|
|
197
|
+
.webhook()
|
|
198
|
+
.create({ webhook: (0, omit_1.default)(apiData, ['uid']) })
|
|
199
|
+
.then(onSuccess)
|
|
200
|
+
.catch(onReject);
|
|
201
|
+
case 'create-workflows':
|
|
202
|
+
return this.stack
|
|
203
|
+
.workflow()
|
|
204
|
+
.create({ workflow: apiData })
|
|
205
|
+
.then(onSuccess)
|
|
206
|
+
.catch(onReject);
|
|
207
|
+
case 'create-custom-role':
|
|
208
|
+
return this.stack
|
|
209
|
+
.role()
|
|
210
|
+
.create({ role: apiData })
|
|
211
|
+
.then(onSuccess)
|
|
212
|
+
.catch(onReject);
|
|
213
|
+
default:
|
|
214
|
+
return Promise.resolve();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.default = BaseClass;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Contentstack Import
|
|
3
|
+
* Copyright (c) 2019 Contentstack LLC
|
|
4
|
+
* MIT Licensed
|
|
5
|
+
*/
|
|
6
|
+
import { ModuleClassParams } from '../../types';
|
|
7
|
+
import BaseClass, { ApiOptions } from './base-class';
|
|
8
|
+
export default class ContentTypesImport extends BaseClass {
|
|
9
|
+
private cTsMapperPath;
|
|
10
|
+
private cTsFolderPath;
|
|
11
|
+
private cTsFailsPath;
|
|
12
|
+
private cTsSuccessPath;
|
|
13
|
+
private gFsPendingPath;
|
|
14
|
+
private pendingGFs;
|
|
15
|
+
private createdGFs;
|
|
16
|
+
private gFsFolderPath;
|
|
17
|
+
private gFsMapperFolderPath;
|
|
18
|
+
private gFs;
|
|
19
|
+
private failedCTs;
|
|
20
|
+
private createdCTs;
|
|
21
|
+
private cTs;
|
|
22
|
+
private cTsUidMapper;
|
|
23
|
+
private config;
|
|
24
|
+
private stackAPIClient;
|
|
25
|
+
private marketplaceAppMapperPath;
|
|
26
|
+
private reqConcurrency;
|
|
27
|
+
private ignoredFilesInContentTypesFolder;
|
|
28
|
+
private titleToUIdMap;
|
|
29
|
+
private fieldRules;
|
|
30
|
+
private installedExtensions;
|
|
31
|
+
private cTsConfig;
|
|
32
|
+
private gFsConfig;
|
|
33
|
+
constructor({ importConfig, stackAPIClient }: ModuleClassParams);
|
|
34
|
+
start(): Promise<any>;
|
|
35
|
+
seedCTs(): Promise<any>;
|
|
36
|
+
/**
|
|
37
|
+
* @method serializeCTs
|
|
38
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
39
|
+
* @returns {ApiOptions} ApiOptions
|
|
40
|
+
*/
|
|
41
|
+
serializeCTs(apiOptions: ApiOptions): ApiOptions;
|
|
42
|
+
updateCTs(): Promise<any>;
|
|
43
|
+
/**
|
|
44
|
+
* @method serializeUpdateCTs
|
|
45
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
46
|
+
* @returns {ApiOptions} ApiOptions
|
|
47
|
+
*/
|
|
48
|
+
serializeUpdateCTs(apiOptions: ApiOptions): ApiOptions;
|
|
49
|
+
updatePendingGFs(): Promise<any>;
|
|
50
|
+
/**
|
|
51
|
+
* @method serializeUpdateGFs
|
|
52
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
53
|
+
* @returns {ApiOptions} ApiOptions
|
|
54
|
+
*/
|
|
55
|
+
serializeUpdateGFs(apiOptions: ApiOptions): ApiOptions;
|
|
56
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-prototype-builtins */
|
|
3
|
+
/*!
|
|
4
|
+
* Contentstack Import
|
|
5
|
+
* Copyright (c) 2019 Contentstack LLC
|
|
6
|
+
* MIT Licensed
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const path = tslib_1.__importStar(require("path"));
|
|
11
|
+
const lodash_1 = require("lodash");
|
|
12
|
+
const utils_1 = require("../../utils");
|
|
13
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
14
|
+
class ContentTypesImport extends base_class_1.default {
|
|
15
|
+
constructor({ importConfig, stackAPIClient }) {
|
|
16
|
+
super({ importConfig, stackAPIClient });
|
|
17
|
+
this.cTsConfig = importConfig.modules['content-types'];
|
|
18
|
+
this.gFsConfig = importConfig.modules['global-fields'];
|
|
19
|
+
this.reqConcurrency = this.cTsConfig.writeConcurrency || this.importConfig.writeConcurrency;
|
|
20
|
+
this.cTsFolderPath = path.join(this.importConfig.data, this.cTsConfig.dirName);
|
|
21
|
+
this.cTsMapperPath = path.join(this.importConfig.data, 'mapper', 'content_types');
|
|
22
|
+
this.cTsSuccessPath = path.join(this.cTsMapperPath, 'success.json');
|
|
23
|
+
this.gFsFolderPath = path.resolve(this.importConfig.data, this.gFsConfig.dirName);
|
|
24
|
+
this.gFsMapperFolderPath = path.join(importConfig.data, 'mapper', 'global_fields', 'success.json');
|
|
25
|
+
this.gFsPendingPath = path.join(importConfig.data, 'mapper', 'global_fields', 'pending_global_fields.js');
|
|
26
|
+
this.marketplaceAppMapperPath = path.join(this.importConfig.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
|
|
27
|
+
this.ignoredFilesInContentTypesFolder = new Map([
|
|
28
|
+
['__master.json', 'true'],
|
|
29
|
+
['__priority.json', 'true'],
|
|
30
|
+
['schema.json', 'true'],
|
|
31
|
+
['.DS_Store', 'true'],
|
|
32
|
+
]);
|
|
33
|
+
this.cTs = [];
|
|
34
|
+
this.createdCTs = [];
|
|
35
|
+
this.titleToUIdMap = new Map();
|
|
36
|
+
this.fieldRules = [];
|
|
37
|
+
this.gFs = [];
|
|
38
|
+
this.createdGFs = [];
|
|
39
|
+
this.pendingGFs = [];
|
|
40
|
+
}
|
|
41
|
+
async start() {
|
|
42
|
+
/**
|
|
43
|
+
* read content type, check if it is necessary to read the entire dir
|
|
44
|
+
* Seed content types
|
|
45
|
+
* Update content types, lookup extension.
|
|
46
|
+
* Update pending global fields
|
|
47
|
+
* write field rules
|
|
48
|
+
*/
|
|
49
|
+
this.cTs = utils_1.fsUtil.readFile(path.join(this.cTsFolderPath, 'schema.json'));
|
|
50
|
+
if (!this.cTs || (0, lodash_1.isEmpty)(this.cTs)) {
|
|
51
|
+
(0, utils_1.log)(this.importConfig, 'No content type found to import', 'info');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
|
|
55
|
+
this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
|
|
56
|
+
await this.seedCTs();
|
|
57
|
+
(0, utils_1.log)(this.importConfig, 'Created content types', 'success');
|
|
58
|
+
await this.updateCTs();
|
|
59
|
+
(0, utils_1.log)(this.importConfig, 'Updated content types with references', 'success');
|
|
60
|
+
if (this.fieldRules.length > 0) {
|
|
61
|
+
await utils_1.fsUtil.writeFile(path.join(this.cTsFolderPath, 'field_rules_uid.json'), this.fieldRules);
|
|
62
|
+
}
|
|
63
|
+
await this.updatePendingGFs().catch((error) => {
|
|
64
|
+
(0, utils_1.log)(this.importConfig, `Error while updating pending global field ${(0, utils_1.formatError)(error)}`, 'error');
|
|
65
|
+
});
|
|
66
|
+
(0, utils_1.log)(this.importConfig, 'Updated pending global fields with content type with references', 'success');
|
|
67
|
+
(0, utils_1.log)(this.importConfig, 'Content types have been imported successfully!', 'success');
|
|
68
|
+
}
|
|
69
|
+
async seedCTs() {
|
|
70
|
+
const onSuccess = ({ response: globalField, apiData: { content_type: { uid = null } = {} } = {} }) => {
|
|
71
|
+
(0, utils_1.log)(this.importConfig, `${uid} content type seeded`, 'info');
|
|
72
|
+
};
|
|
73
|
+
const onReject = ({ error, apiData: { content_type: { uid = null } = {} } = {} }) => {
|
|
74
|
+
if (error.errorCode === 115 && (error.errors.uid || error.errors.title)) {
|
|
75
|
+
(0, utils_1.log)(this.importConfig, `${uid} content type already exist`, 'info');
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return await this.makeConcurrentCall({
|
|
83
|
+
processName: 'Import content types',
|
|
84
|
+
apiContent: this.cTs,
|
|
85
|
+
apiParams: {
|
|
86
|
+
serializeData: this.serializeCTs.bind(this),
|
|
87
|
+
reject: onReject.bind(this),
|
|
88
|
+
resolve: onSuccess.bind(this),
|
|
89
|
+
entity: 'create-cts',
|
|
90
|
+
includeParamOnCompletion: true,
|
|
91
|
+
},
|
|
92
|
+
concurrencyLimit: this.reqConcurrency,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @method serializeCTs
|
|
97
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
98
|
+
* @returns {ApiOptions} ApiOptions
|
|
99
|
+
*/
|
|
100
|
+
serializeCTs(apiOptions) {
|
|
101
|
+
const { apiData: contentType } = apiOptions;
|
|
102
|
+
const updatedCT = (0, lodash_1.cloneDeep)(utils_1.schemaTemplate);
|
|
103
|
+
updatedCT.content_type.uid = contentType.uid;
|
|
104
|
+
updatedCT.content_type.title = contentType.title;
|
|
105
|
+
apiOptions.apiData = updatedCT;
|
|
106
|
+
return apiOptions;
|
|
107
|
+
}
|
|
108
|
+
async updateCTs() {
|
|
109
|
+
const onSuccess = ({ response: contentType, apiData: { uid } }) => {
|
|
110
|
+
(0, utils_1.log)(this.importConfig, `${uid} updated with references`, 'success');
|
|
111
|
+
};
|
|
112
|
+
const onReject = ({ error, apiData: { uid } }) => {
|
|
113
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
114
|
+
throw new Error(`Content type '${uid}' update error`);
|
|
115
|
+
};
|
|
116
|
+
return await this.makeConcurrentCall({
|
|
117
|
+
processName: 'Update content types',
|
|
118
|
+
apiContent: this.cTs,
|
|
119
|
+
apiParams: {
|
|
120
|
+
serializeData: this.serializeUpdateCTs.bind(this),
|
|
121
|
+
reject: onReject.bind(this),
|
|
122
|
+
resolve: onSuccess.bind(this),
|
|
123
|
+
entity: 'update-cts',
|
|
124
|
+
includeParamOnCompletion: true,
|
|
125
|
+
},
|
|
126
|
+
concurrencyLimit: this.reqConcurrency,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @method serializeUpdateCTs
|
|
131
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
132
|
+
* @returns {ApiOptions} ApiOptions
|
|
133
|
+
*/
|
|
134
|
+
serializeUpdateCTs(apiOptions) {
|
|
135
|
+
const { apiData: contentType } = apiOptions;
|
|
136
|
+
if (contentType.field_rules) {
|
|
137
|
+
this.fieldRules.push(contentType.uid);
|
|
138
|
+
delete contentType.field_rules;
|
|
139
|
+
}
|
|
140
|
+
(0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
|
|
141
|
+
const contentTypePayload = this.stack.contentType(contentType.uid);
|
|
142
|
+
Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
|
|
143
|
+
apiOptions.apiData = contentTypePayload;
|
|
144
|
+
return apiOptions;
|
|
145
|
+
}
|
|
146
|
+
async updatePendingGFs() {
|
|
147
|
+
this.pendingGFs = utils_1.fsUtil.readFile(this.gFsPendingPath);
|
|
148
|
+
this.gFs = utils_1.fsUtil.readFile(path.resolve(this.gFsFolderPath, this.gFsConfig.fileName));
|
|
149
|
+
const onSuccess = ({ response: globalField, apiData: { uid } = undefined }) => {
|
|
150
|
+
(0, utils_1.log)(this.importConfig, `Updated the global field ${uid} with content type references`, 'info');
|
|
151
|
+
};
|
|
152
|
+
const onReject = ({ error, apiData: { uid } = undefined }) => {
|
|
153
|
+
(0, utils_1.log)(this.importConfig, `failed to update the global field ${uid} ${(0, utils_1.formatError)(error)}`, 'error');
|
|
154
|
+
};
|
|
155
|
+
return await this.makeConcurrentCall({
|
|
156
|
+
processName: 'Update pending global fields',
|
|
157
|
+
apiContent: (0, lodash_1.map)(this.pendingGFs, (uid) => {
|
|
158
|
+
return { uid };
|
|
159
|
+
}),
|
|
160
|
+
apiParams: {
|
|
161
|
+
serializeData: this.serializeUpdateGFs.bind(this),
|
|
162
|
+
reject: onReject.bind(this),
|
|
163
|
+
resolve: onSuccess.bind(this),
|
|
164
|
+
entity: 'update-gfs',
|
|
165
|
+
includeParamOnCompletion: true,
|
|
166
|
+
},
|
|
167
|
+
concurrencyLimit: this.reqConcurrency,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* @method serializeUpdateGFs
|
|
172
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
173
|
+
* @returns {ApiOptions} ApiOptions
|
|
174
|
+
*/
|
|
175
|
+
serializeUpdateGFs(apiOptions) {
|
|
176
|
+
const { apiData: { uid }, } = apiOptions;
|
|
177
|
+
const globalField = (0, lodash_1.find)(this.gFs, { uid });
|
|
178
|
+
(0, utils_1.lookupExtension)(this.importConfig, globalField.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
|
|
179
|
+
apiOptions.apiData = globalField;
|
|
180
|
+
const globalFieldPayload = this.stack.globalField(uid);
|
|
181
|
+
Object.assign(globalFieldPayload, (0, lodash_1.cloneDeep)(globalField));
|
|
182
|
+
apiOptions.apiData = globalFieldPayload;
|
|
183
|
+
return apiOptions;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.default = ContentTypesImport;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import BaseClass, { ApiOptions } from './base-class';
|
|
2
|
+
import { ModuleClassParams } from '../../types';
|
|
3
|
+
export default class ImportCustomRoles extends BaseClass {
|
|
4
|
+
private customRolesMapperPath;
|
|
5
|
+
private customRolesFolderPath;
|
|
6
|
+
private customRolesUidMapperPath;
|
|
7
|
+
private envUidMapperFolderPath;
|
|
8
|
+
private entriesUidMapperFolderPath;
|
|
9
|
+
private createdCustomRolesPath;
|
|
10
|
+
private customRolesFailsPath;
|
|
11
|
+
private customRolesConfig;
|
|
12
|
+
private customRoles;
|
|
13
|
+
private customRolesLocales;
|
|
14
|
+
private customRolesUidMapper;
|
|
15
|
+
private createdCustomRoles;
|
|
16
|
+
private failedCustomRoles;
|
|
17
|
+
private environmentsUidMap;
|
|
18
|
+
private entriesUidMap;
|
|
19
|
+
private localesUidMap;
|
|
20
|
+
targetLocalesMap: Record<string, unknown>;
|
|
21
|
+
sourceLocalesMap: Record<string, unknown>;
|
|
22
|
+
constructor({ importConfig, stackAPIClient }: ModuleClassParams);
|
|
23
|
+
/**
|
|
24
|
+
* @method start
|
|
25
|
+
* @returns {Promise<void>} Promise<void>
|
|
26
|
+
*/
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
getLocalesUidMap(): Promise<void>;
|
|
29
|
+
importCustomRoles(): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* @method serializeWebhooks
|
|
32
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
33
|
+
* @returns {ApiOptions} ApiOptions
|
|
34
|
+
*/
|
|
35
|
+
serializeWebhooks(apiOptions: ApiOptions): ApiOptions;
|
|
36
|
+
getTransformUidsFactory: (rule: Record<string, any>) => Record<string, any>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
5
|
+
const values_1 = tslib_1.__importDefault(require("lodash/values"));
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const config_1 = tslib_1.__importDefault(require("../../config"));
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
10
|
+
const lodash_1 = require("lodash");
|
|
11
|
+
class ImportCustomRoles extends base_class_1.default {
|
|
12
|
+
constructor({ importConfig, stackAPIClient }) {
|
|
13
|
+
super({ importConfig, stackAPIClient });
|
|
14
|
+
this.getTransformUidsFactory = (rule) => {
|
|
15
|
+
if (rule.module === 'environment') {
|
|
16
|
+
rule.environments = (0, lodash_1.map)(rule.environments, (env) => this.environmentsUidMap[env]);
|
|
17
|
+
}
|
|
18
|
+
else if (rule.module === 'locale') {
|
|
19
|
+
rule.locales = (0, lodash_1.map)(rule.locales, (locale) => this.localesUidMap[locale]);
|
|
20
|
+
}
|
|
21
|
+
else if (rule.module === 'entry') {
|
|
22
|
+
rule.entries = (0, lodash_1.map)(rule.entries, (entry) => this.entriesUidMap[entry]);
|
|
23
|
+
}
|
|
24
|
+
return rule;
|
|
25
|
+
};
|
|
26
|
+
this.customRolesConfig = config_1.default.modules.customRoles;
|
|
27
|
+
this.customRolesMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'custom-roles');
|
|
28
|
+
this.customRolesFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, this.customRolesConfig.dirName);
|
|
29
|
+
this.customRolesUidMapperPath = (0, node_path_1.join)(this.customRolesMapperPath, 'uid-mapping.json');
|
|
30
|
+
this.envUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'environments');
|
|
31
|
+
this.entriesUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'entries');
|
|
32
|
+
this.createdCustomRolesPath = (0, node_path_1.join)(this.customRolesMapperPath, 'success.json');
|
|
33
|
+
this.customRolesFailsPath = (0, node_path_1.join)(this.customRolesMapperPath, 'fails.json');
|
|
34
|
+
this.customRoles = {};
|
|
35
|
+
this.failedCustomRoles = [];
|
|
36
|
+
this.createdCustomRoles = [];
|
|
37
|
+
this.customRolesUidMapper = {};
|
|
38
|
+
this.customRolesLocales = {};
|
|
39
|
+
this.environmentsUidMap = {};
|
|
40
|
+
this.entriesUidMap = {};
|
|
41
|
+
this.localesUidMap = {};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @method start
|
|
45
|
+
* @returns {Promise<void>} Promise<void>
|
|
46
|
+
*/
|
|
47
|
+
async start() {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
(0, utils_1.log)(this.importConfig, 'Migrating custom-roles', 'info');
|
|
50
|
+
//Step1 check folder exists or not
|
|
51
|
+
if (utils_1.fileHelper.fileExistsSync(this.customRolesFolderPath)) {
|
|
52
|
+
this.customRoles = utils_1.fsUtil.readFile((0, node_path_1.join)(this.customRolesFolderPath, this.customRolesConfig.fileName), true);
|
|
53
|
+
this.customRolesLocales = utils_1.fsUtil.readFile((0, node_path_1.join)(this.customRolesFolderPath, this.customRolesConfig.customRolesLocalesFileName), true);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
(0, utils_1.log)(this.importConfig, `No such file or directory - '${this.customRolesFolderPath}'`, 'error');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
//create webhooks in mapper directory
|
|
60
|
+
await utils_1.fsUtil.makeDirectory(this.customRolesMapperPath);
|
|
61
|
+
this.customRolesUidMapper = utils_1.fileHelper.fileExistsSync(this.customRolesUidMapperPath)
|
|
62
|
+
? utils_1.fsUtil.readFile((0, node_path_1.join)(this.customRolesUidMapperPath), true)
|
|
63
|
+
: {};
|
|
64
|
+
this.environmentsUidMap = utils_1.fileHelper.fileExistsSync(this.envUidMapperFolderPath)
|
|
65
|
+
? utils_1.fsUtil.readFile((0, node_path_1.join)(this.envUidMapperFolderPath, 'uid-mapping.json'), true)
|
|
66
|
+
: {};
|
|
67
|
+
this.entriesUidMap = utils_1.fileHelper.fileExistsSync(this.entriesUidMapperFolderPath)
|
|
68
|
+
? utils_1.fsUtil.readFile((0, node_path_1.join)(this.entriesUidMapperFolderPath, 'uid-mapping.json'), true)
|
|
69
|
+
: {};
|
|
70
|
+
//source and target stack locale map
|
|
71
|
+
await this.getLocalesUidMap();
|
|
72
|
+
await this.importCustomRoles();
|
|
73
|
+
if ((_a = this.createdCustomRoles) === null || _a === void 0 ? void 0 : _a.length) {
|
|
74
|
+
utils_1.fsUtil.writeFile(this.createdCustomRolesPath, this.createdCustomRoles);
|
|
75
|
+
}
|
|
76
|
+
if ((_b = this.failedCustomRoles) === null || _b === void 0 ? void 0 : _b.length) {
|
|
77
|
+
utils_1.fsUtil.writeFile(this.customRolesFailsPath, this.failedCustomRoles);
|
|
78
|
+
}
|
|
79
|
+
(0, utils_1.log)(this.importConfig, 'Custom roles have been imported successfully!', 'success');
|
|
80
|
+
}
|
|
81
|
+
async getLocalesUidMap() {
|
|
82
|
+
const { items } = await this.stack
|
|
83
|
+
.locale()
|
|
84
|
+
.query()
|
|
85
|
+
.find()
|
|
86
|
+
.then((data) => data)
|
|
87
|
+
.catch((error) => (0, utils_1.log)(this.importConfig, `Failed to fetch locale.${(0, utils_1.formatError)(error)}`, 'error'));
|
|
88
|
+
this.targetLocalesMap = {};
|
|
89
|
+
this.sourceLocalesMap = {};
|
|
90
|
+
(0, lodash_1.forEach)(items, (locale) => {
|
|
91
|
+
this.targetLocalesMap[locale.code] = locale.uid;
|
|
92
|
+
});
|
|
93
|
+
for (const key in this.customRolesLocales) {
|
|
94
|
+
const sourceLocales = this.customRolesLocales[key];
|
|
95
|
+
this.sourceLocalesMap[sourceLocales.code] = key;
|
|
96
|
+
}
|
|
97
|
+
for (const key in this.sourceLocalesMap) {
|
|
98
|
+
const sourceLocaleKey = this.sourceLocalesMap[key];
|
|
99
|
+
this.localesUidMap[sourceLocaleKey] = this.targetLocalesMap[key];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async importCustomRoles() {
|
|
103
|
+
if (this.customRoles === undefined || (0, isEmpty_1.default)(this.customRoles)) {
|
|
104
|
+
(0, utils_1.log)(this.importConfig, 'No custom-roles found', 'info');
|
|
105
|
+
return (0, node_path_1.resolve)();
|
|
106
|
+
}
|
|
107
|
+
const apiContent = (0, values_1.default)(this.customRoles);
|
|
108
|
+
const onSuccess = ({ response, apiData: { uid, name } = { uid: null, name: '' } }) => {
|
|
109
|
+
this.createdCustomRoles.push(response);
|
|
110
|
+
this.customRolesUidMapper[uid] = response.uid;
|
|
111
|
+
(0, utils_1.log)(this.importConfig, `custom-role '${name}' imported successfully`, 'success');
|
|
112
|
+
utils_1.fsUtil.writeFile(this.customRolesUidMapperPath, this.customRolesUidMapper);
|
|
113
|
+
};
|
|
114
|
+
const onReject = ({ error, apiData }) => {
|
|
115
|
+
var _a;
|
|
116
|
+
const err = (error === null || error === void 0 ? void 0 : error.message) ? JSON.parse(error.message) : error;
|
|
117
|
+
const { name } = apiData;
|
|
118
|
+
if ((_a = err === null || err === void 0 ? void 0 : err.errors) === null || _a === void 0 ? void 0 : _a.name) {
|
|
119
|
+
(0, utils_1.log)(this.importConfig, `custom-role '${name}' already exists`, 'info');
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.failedCustomRoles.push(apiData);
|
|
123
|
+
(0, utils_1.log)(this.importConfig, `custom-role '${name}' failed to be import.${(0, utils_1.formatError)(error)}`, 'error');
|
|
124
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
await this.makeConcurrentCall({
|
|
128
|
+
apiContent,
|
|
129
|
+
processName: 'create custom role',
|
|
130
|
+
apiParams: {
|
|
131
|
+
serializeData: this.serializeWebhooks.bind(this),
|
|
132
|
+
reject: onReject.bind(this),
|
|
133
|
+
resolve: onSuccess.bind(this),
|
|
134
|
+
entity: 'create-custom-role',
|
|
135
|
+
includeParamOnCompletion: true,
|
|
136
|
+
},
|
|
137
|
+
concurrencyLimit: config_1.default.fetchConcurrency || 1,
|
|
138
|
+
}, undefined, false);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* @method serializeWebhooks
|
|
142
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
143
|
+
* @returns {ApiOptions} ApiOptions
|
|
144
|
+
*/
|
|
145
|
+
serializeWebhooks(apiOptions) {
|
|
146
|
+
const { apiData: customRole } = apiOptions;
|
|
147
|
+
if (this.customRolesUidMapper.hasOwnProperty(customRole.uid)) {
|
|
148
|
+
(0, utils_1.log)(this.importConfig, `custom-role '${customRole.name}' already exists. Skipping it to avoid duplicates!`, 'info');
|
|
149
|
+
apiOptions.entity = undefined;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
let branchRuleExists = false;
|
|
153
|
+
(0, lodash_1.forEach)(customRole.rules, (rule) => {
|
|
154
|
+
rule = this.getTransformUidsFactory(rule);
|
|
155
|
+
// rules.branch is required to create custom roles.
|
|
156
|
+
if (rule.module === 'branch')
|
|
157
|
+
branchRuleExists = true;
|
|
158
|
+
});
|
|
159
|
+
if (!branchRuleExists) {
|
|
160
|
+
customRole.rules.push({
|
|
161
|
+
module: 'branch',
|
|
162
|
+
branches: ['main'],
|
|
163
|
+
acl: { read: true },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
apiOptions.apiData = customRole;
|
|
167
|
+
}
|
|
168
|
+
return apiOptions;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.default = ImportCustomRoles;
|