1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const async = require('async');
|
17 |
|
18 | const { AllowedPermissionsOperations, AppOptionsName, BackendCollectionPermission, CollectionHook, DomainTypes,
|
19 | EntityType, EnvOptionsName, LogLevel, OperationType } = require('./Constants');
|
20 | const FileProcessorHelper = require('./FileProcessorHelper');
|
21 | const { Endpoints, getCustomNotFoundError, getObjectByOmitting, isEmpty, isNullOrUndefined } = require('./Utils');
|
22 |
|
23 | class EnvFileProcessor {
|
24 | constructor(options) {
|
25 | this.cliManager = options.cliManager;
|
26 | this.applicationsService = options.applicationsService;
|
27 | this.environmentsService = options.environmentsService;
|
28 | this.collectionsService = options.collectionsService;
|
29 | this.blService = options.businessLogicService;
|
30 | this.rolesService = options.rolesService;
|
31 | this.groupsService = options.groupsService;
|
32 | this.pushService = options.pushService;
|
33 | this.servicesService = options.servicesService;
|
34 | }
|
35 |
|
36 | process(options, done) {
|
37 | const operationType = options.operation;
|
38 | const source = options.parsedData;
|
39 | if (operationType === OperationType.CREATE) {
|
40 | this._createEnv(source, options, done);
|
41 | } else if (operationType === OperationType.UPDATE) {
|
42 | this._updateEnv(source, options, done);
|
43 | } else {
|
44 | return setImmediate(() => { done(new Error(`Operation type not supported: ${operationType}`)); });
|
45 | }
|
46 | }
|
47 |
|
48 | _createEnv(source, options, done) {
|
49 | let envId;
|
50 | let env;
|
51 |
|
52 | async.series([
|
53 | (next) => {
|
54 | let envData = { name: options.name };
|
55 | if (source.settings) {
|
56 | envData = Object.assign(envData, source.settings);
|
57 | }
|
58 |
|
59 | this.cliManager.log(LogLevel.INFO, `Creating environment: ${envData.name}`);
|
60 |
|
61 | this.environmentsService.create(envData, options[AppOptionsName.APP], (err, data) => {
|
62 | if (err) {
|
63 | return next(err);
|
64 | }
|
65 |
|
66 | envId = data.id;
|
67 | next();
|
68 | });
|
69 | },
|
70 | (next) => {
|
71 | this.environmentsService.getById(envId, (err, data) => {
|
72 | if (err) {
|
73 | return next(err);
|
74 | }
|
75 |
|
76 | env = data;
|
77 | next();
|
78 | });
|
79 | },
|
80 | (next) => {
|
81 | this._createCommonCode(envId, source.commonCode, next);
|
82 | },
|
83 | (next) => {
|
84 | this._createRoles(env, source.roles, next);
|
85 | },
|
86 | (next) => {
|
87 | this._createGroups(env, source.groups, next);
|
88 | },
|
89 | (next) => {
|
90 | this._modifyCollections(source.collections, env, next);
|
91 | },
|
92 | (next) => {
|
93 |
|
94 | this._createOrUpdateCollectionHooks(env, source.collectionHooks, next);
|
95 | },
|
96 | (next) => {
|
97 | this._createEndpoints(env, source.customEndpoints, next);
|
98 | },
|
99 | (next) => {
|
100 | this._modifyPushSettings(source.push, envId, next);
|
101 | }
|
102 | ], (err) => {
|
103 | if (err) {
|
104 | return done(err);
|
105 | }
|
106 |
|
107 | done(null, { id: envId });
|
108 | });
|
109 | }
|
110 |
|
111 | _createRoles(env, sourceRoles, done) {
|
112 | if (isNullOrUndefined(sourceRoles) || isEmpty(sourceRoles)) {
|
113 | return setImmediate(done);
|
114 | }
|
115 |
|
116 | const roles = Object.keys(sourceRoles);
|
117 | async.each(
|
118 | roles,
|
119 | (roleName, next) => {
|
120 | const currentRole = sourceRoles[roleName];
|
121 | const data = Object.assign({ name: roleName }, currentRole);
|
122 | this.cliManager.log(LogLevel.INFO, `Creating role: ${data.name}`);
|
123 | this.rolesService.create(data, env, next);
|
124 | },
|
125 | done
|
126 | );
|
127 | }
|
128 |
|
129 | _createGroups(env, sourceGroups, done) {
|
130 | if (isNullOrUndefined(sourceGroups) || isEmpty(sourceGroups)) {
|
131 | return setImmediate(done);
|
132 | }
|
133 |
|
134 | const groups = Object.keys(sourceGroups);
|
135 | async.each(
|
136 | groups,
|
137 | (groupId, next) => {
|
138 | const currentGroup = sourceGroups[groupId];
|
139 | const data = Object.assign({ _id: groupId }, currentGroup);
|
140 | if (Array.isArray(currentGroup.groups)) {
|
141 | data.groups = EnvFileProcessor._buildChildGroups(currentGroup.groups);
|
142 | }
|
143 |
|
144 | this.cliManager.log(LogLevel.INFO, `Creating group: ${data._id}`);
|
145 | this.groupsService.create(data, env, next);
|
146 | },
|
147 | done
|
148 | );
|
149 | }
|
150 |
|
151 | static _buildChildGroups(childGroups) {
|
152 | const result = childGroups.map((x) => {
|
153 | return {
|
154 | _type: 'KinveyRef',
|
155 | _collection: 'group',
|
156 | _id: x
|
157 | };
|
158 | });
|
159 |
|
160 | return result;
|
161 | }
|
162 |
|
163 | _createCommonCode(envId, sourceCommonCode, done) {
|
164 | if (isNullOrUndefined(sourceCommonCode) || isEmpty(sourceCommonCode)) {
|
165 | return setImmediate(done);
|
166 | }
|
167 |
|
168 | const commonCodeNames = Object.keys(sourceCommonCode);
|
169 | async.each(
|
170 | commonCodeNames,
|
171 | (codeName, next) => {
|
172 | const currentCommonCode = sourceCommonCode[codeName];
|
173 | const data = Object.assign({ name: codeName }, currentCommonCode);
|
174 | this.cliManager.log(LogLevel.INFO, `Creating common code: ${data.name}`);
|
175 | this.blService.createCommonCode(data, envId, next);
|
176 | },
|
177 | done
|
178 | );
|
179 | }
|
180 |
|
181 | _createOrUpdateCollectionHooks(env, sourceHooks, done) {
|
182 | if (isNullOrUndefined(sourceHooks) || isEmpty(sourceHooks)) {
|
183 | return setImmediate(done);
|
184 | }
|
185 |
|
186 | const collNames = Object.keys(sourceHooks);
|
187 | async.each(
|
188 | collNames,
|
189 | (collName, next) => {
|
190 | const hooksPerCollection = Object.assign({}, sourceHooks[collName]);
|
191 | const hookNames = Object.keys(hooksPerCollection);
|
192 |
|
193 | async.each(
|
194 | hookNames,
|
195 | (hookName, cb) => {
|
196 | const currentHook = hooksPerCollection[hookName];
|
197 | this._setServiceOnHookOrEndpoint(currentHook, hookName, env, (err) => {
|
198 | if (err) {
|
199 | return cb(err);
|
200 | }
|
201 |
|
202 | const mappedHookName = CollectionHook[hookName];
|
203 | this.cliManager.log(LogLevel.INFO, `Creating/updating hook for ${collName} collection: ${hookName}`);
|
204 | this.blService.createOrUpdateHook(currentHook, env.id, collName, mappedHookName, cb);
|
205 | });
|
206 | },
|
207 | next
|
208 | );
|
209 | },
|
210 | done
|
211 | );
|
212 | }
|
213 |
|
214 | _createEndpoints(env, sourceEndpoints, done) {
|
215 | if (isNullOrUndefined(sourceEndpoints) || isEmpty(sourceEndpoints)) {
|
216 | return setImmediate(done);
|
217 | }
|
218 |
|
219 | const endpointNames = Object.keys(sourceEndpoints);
|
220 | async.each(
|
221 | endpointNames,
|
222 | (name, next) => {
|
223 | const currentEndpoint = Object.assign({}, sourceEndpoints[name]);
|
224 | if (currentEndpoint.schedule && !currentEndpoint.schedule.interval) {
|
225 | currentEndpoint.schedule = currentEndpoint.schedule.start;
|
226 | }
|
227 |
|
228 | this._setServiceOnHookOrEndpoint(currentEndpoint, name, env, (err) => {
|
229 | if (err) {
|
230 | return next(err);
|
231 | }
|
232 |
|
233 | this.cliManager.log(LogLevel.INFO, `Creating endpoint: ${name}`);
|
234 | currentEndpoint.name = name;
|
235 | this.blService.createEndpoint(currentEndpoint, env.id, next);
|
236 | });
|
237 | },
|
238 | done
|
239 | );
|
240 | }
|
241 |
|
242 | _updateEnv(source, options, done) {
|
243 | const env = options[EnvOptionsName.ENV];
|
244 | const envId = env.id;
|
245 |
|
246 | async.series([
|
247 | (next) => {
|
248 | let envData = { name: source.name || env.name };
|
249 | envData = Object.assign(envData, source.settings);
|
250 | this.cliManager.log(LogLevel.INFO, `Updating environment: ${envData.name}`);
|
251 | this.environmentsService.update(envId, envData, next);
|
252 | },
|
253 | (next) => {
|
254 | this._modifyCommonCode(source.commonCode, env, next);
|
255 | },
|
256 | (next) => {
|
257 | this._modifyRoles(source.roles, env, next);
|
258 | },
|
259 | (next) => {
|
260 | this._modifyGroups(source.groups, env, next);
|
261 | },
|
262 | (next) => {
|
263 | this._modifyCollections(source.collections, env, next);
|
264 | },
|
265 | (next) => {
|
266 | this._createOrUpdateCollectionHooks(env, source.collectionHooks, next);
|
267 | },
|
268 | (next) => {
|
269 | this._modifyEndpoints(source.customEndpoints, env, next);
|
270 | },
|
271 | (next) => {
|
272 | this._modifyPushSettings(source.push, envId, next);
|
273 | }
|
274 | ], (err) => {
|
275 | if (err) {
|
276 | return done(err);
|
277 | }
|
278 |
|
279 | done(null, { id: envId });
|
280 | });
|
281 | }
|
282 |
|
283 | static _groupCollectionsPerOperationType(originalCollections, collections) {
|
284 | const groupedEntities = FileProcessorHelper.groupEntitiesPerOperationType(originalCollections, collections);
|
285 | if (!isEmpty(groupedEntities[OperationType.DELETE])) {
|
286 | const collToDel = groupedEntities[OperationType.DELETE].filter(x => x !== 'user' && x !== '_blob');
|
287 | groupedEntities[OperationType.DELETE] = collToDel;
|
288 | }
|
289 |
|
290 | return groupedEntities;
|
291 | }
|
292 |
|
293 | _modifyRoles(roles = {}, env, done) {
|
294 | if (isEmpty(roles)) {
|
295 | return setImmediate(done);
|
296 | }
|
297 |
|
298 | let groupedRoles;
|
299 |
|
300 | async.series([
|
301 | (next) => {
|
302 | this.rolesService.getAll(env, (err, originalRoles) => {
|
303 | if (err) {
|
304 | return next(err);
|
305 | }
|
306 |
|
307 | try {
|
308 | groupedRoles = this._groupRolesPerOperationType(originalRoles, roles);
|
309 | } catch (ex) {
|
310 | return next(ex);
|
311 | }
|
312 |
|
313 | next();
|
314 | });
|
315 | },
|
316 | (next) => {
|
317 | this._createRoles(env, groupedRoles[OperationType.CREATE], next);
|
318 | },
|
319 | (next) => {
|
320 | this._updateRoles(env, groupedRoles[OperationType.UPDATE], next);
|
321 | }
|
322 | ], done);
|
323 | }
|
324 |
|
325 | _updateRoles(env, sourceRoles, done) {
|
326 | if (isNullOrUndefined(sourceRoles) || isEmpty(sourceRoles)) {
|
327 | return setImmediate(done);
|
328 | }
|
329 |
|
330 | async.each(
|
331 | sourceRoles,
|
332 | (currentRole, next) => {
|
333 | this.cliManager.log(LogLevel.INFO, `Updating role: ${currentRole._id}(${currentRole.name})`);
|
334 | this.rolesService.update(currentRole._id, currentRole, env, next);
|
335 | },
|
336 | done
|
337 | );
|
338 | }
|
339 |
|
340 | |
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 | _groupRolesPerOperationType(originalRoles, rolesToModify) {
|
350 | const entitiesToCreate = {};
|
351 | const entitiesToUpdate = [];
|
352 |
|
353 | const groupedRoles = this._groupRolesByIdentifiers(originalRoles);
|
354 | const originalRolesGroupedById = groupedRoles.byId;
|
355 | const originalRolesGroupedByName = groupedRoles.byName;
|
356 | const originalRolesDuplicatedNames = groupedRoles.duplicatedNames;
|
357 |
|
358 | const originalRolesIds = Object.keys(originalRolesGroupedById);
|
359 | const originalRolesNames = Object.keys(originalRolesGroupedByName);
|
360 | const rolesToModifyIdentifiers = Object.keys(rolesToModify);
|
361 |
|
362 | rolesToModifyIdentifiers.forEach((modifiedRoleIdentifier) => {
|
363 | const isIdAndExists = originalRolesIds.includes(modifiedRoleIdentifier);
|
364 | const isNameAndExists = originalRolesNames.includes(modifiedRoleIdentifier);
|
365 | const roleExists = isIdAndExists || isNameAndExists;
|
366 | if (roleExists) {
|
367 | let id;
|
368 | if (isIdAndExists) {
|
369 | id = modifiedRoleIdentifier;
|
370 | } else {
|
371 | if (originalRolesDuplicatedNames.includes(modifiedRoleIdentifier)) {
|
372 | throw new Error(`Cannot update role '${modifiedRoleIdentifier}' using the name as identifier as there is more than one role with this name.`);
|
373 | }
|
374 |
|
375 | id = originalRolesGroupedByName[modifiedRoleIdentifier]._id;
|
376 | }
|
377 |
|
378 | const name = rolesToModify[modifiedRoleIdentifier].name || originalRolesGroupedById[id].name;
|
379 | entitiesToUpdate.push(Object.assign({ _id: id, name }, rolesToModify[modifiedRoleIdentifier]));
|
380 | } else {
|
381 | entitiesToCreate[modifiedRoleIdentifier] = rolesToModify[modifiedRoleIdentifier];
|
382 | }
|
383 | });
|
384 |
|
385 | return {
|
386 | [OperationType.CREATE]: entitiesToCreate,
|
387 | [OperationType.UPDATE]: entitiesToUpdate
|
388 | };
|
389 | }
|
390 |
|
391 |
|
392 | _groupRolesByIdentifiers(roles) {
|
393 | const result = {
|
394 | byId: {},
|
395 | byName: {},
|
396 | duplicatedNames: []
|
397 | };
|
398 |
|
399 | roles.forEach((role) => {
|
400 | result.byId[role._id] = role;
|
401 | const name = role.name;
|
402 | if (result.byName[name]) {
|
403 | result.duplicatedNames.push(name);
|
404 | }
|
405 |
|
406 | result.byName[name] = role;
|
407 | });
|
408 |
|
409 | return result;
|
410 | }
|
411 |
|
412 | _modifyCollections(collections = {}, env, done) {
|
413 | let groupedEntities;
|
414 | const envId = env.id;
|
415 | let existingRolesGrouped;
|
416 |
|
417 | async.series([
|
418 | (next) => {
|
419 | this.collectionsService.getAll(envId, (err, originalCollections) => {
|
420 | if (err) {
|
421 | return next(err);
|
422 | }
|
423 |
|
424 | groupedEntities = EnvFileProcessor._groupCollectionsPerOperationType(originalCollections, collections);
|
425 | next();
|
426 | });
|
427 | },
|
428 | (next) => {
|
429 | this.rolesService.getAll(env, (err, roles) => {
|
430 | if (err) {
|
431 | return next(err);
|
432 | }
|
433 |
|
434 | existingRolesGrouped = this._groupRolesByIdentifiers(roles);
|
435 | next();
|
436 | });
|
437 | },
|
438 |
|
439 |
|
440 |
|
441 |
|
442 | (next) => {
|
443 | this._updateCollections(groupedEntities[OperationType.UPDATE], env, existingRolesGrouped, next);
|
444 | },
|
445 | (next) => {
|
446 | this._createCollections(groupedEntities[OperationType.CREATE], env, existingRolesGrouped, next);
|
447 | }
|
448 | ], done);
|
449 | }
|
450 |
|
451 | _modifyGroups(groups = {}, env, done) {
|
452 | if (isEmpty(groups)) {
|
453 | return setImmediate(done);
|
454 | }
|
455 |
|
456 | let groupedGroups;
|
457 |
|
458 | async.series([
|
459 | (next) => {
|
460 | this.groupsService.getAll(env, (err, originalGroups) => {
|
461 | if (err) {
|
462 | return next(err);
|
463 | }
|
464 |
|
465 | try {
|
466 | groupedGroups = this._groupRolesPerOperationType(originalGroups, groups, '_id');
|
467 | } catch (ex) {
|
468 | return next(ex);
|
469 | }
|
470 |
|
471 | next();
|
472 | });
|
473 | },
|
474 | (next) => {
|
475 | this._createGroups(env, groupedGroups[OperationType.CREATE], next);
|
476 | },
|
477 | (next) => {
|
478 | this._updateGroups(env, groupedGroups[OperationType.UPDATE], next);
|
479 | }
|
480 | ], done);
|
481 | }
|
482 |
|
483 | _updateGroups(env, groups, done) {
|
484 | if (isEmpty(groups)) {
|
485 | return setImmediate(done);
|
486 | }
|
487 |
|
488 | async.each(
|
489 | groups,
|
490 | (currentGroup, next) => {
|
491 | if (Array.isArray(currentGroup.groups)) {
|
492 | currentGroup.groups = EnvFileProcessor._buildChildGroups(currentGroup.groups);
|
493 | }
|
494 |
|
495 | this.cliManager.log(LogLevel.INFO, `Updating group: ${currentGroup._id}`);
|
496 | this.groupsService.update(currentGroup._id, currentGroup, env, next);
|
497 | },
|
498 | done
|
499 | );
|
500 | }
|
501 |
|
502 | |
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 | _modifyEndpoints(endpoints = {}, env, done) {
|
511 |
|
512 | if (isEmpty(endpoints)) {
|
513 | return setImmediate(done);
|
514 | }
|
515 |
|
516 | let groupedEntities;
|
517 | let existingEndpoints;
|
518 | const envId = env.id;
|
519 |
|
520 | async.series([
|
521 | (next) => {
|
522 | this.blService.getEndpoints(envId, null, (err, originalEndpoints) => {
|
523 | if (err) {
|
524 | return next(err);
|
525 | }
|
526 |
|
527 | existingEndpoints = originalEndpoints;
|
528 | groupedEntities = FileProcessorHelper.groupEntitiesPerOperationType(originalEndpoints, endpoints);
|
529 |
|
530 | next();
|
531 | });
|
532 | },
|
533 | (next) => {
|
534 | this._updateEndpoints(groupedEntities[OperationType.UPDATE], env, next);
|
535 | },
|
536 | (next) => {
|
537 | this._createEndpoints(env, groupedEntities[OperationType.CREATE], next);
|
538 | }
|
539 | ], done);
|
540 | }
|
541 |
|
542 | _updateEndpoints(endpointsToUpdate, env, done) {
|
543 | const envId = env.id;
|
544 |
|
545 | async.each(
|
546 | endpointsToUpdate,
|
547 | (endpoint, next) => {
|
548 | const nameIdentifier = Object.keys(endpoint)[0];
|
549 | this.cliManager.log(LogLevel.INFO, `Updating endpoint: ${nameIdentifier}`);
|
550 | const updateData = endpoint[nameIdentifier];
|
551 | updateData.name = updateData.name || nameIdentifier;
|
552 | if (updateData.schedule && !updateData.schedule.interval) {
|
553 | updateData.schedule = updateData.schedule.start;
|
554 | }
|
555 |
|
556 | this._setServiceOnHookOrEndpoint(updateData, nameIdentifier, env, (err) => {
|
557 | if (err) {
|
558 | return next(err);
|
559 | }
|
560 |
|
561 | this.blService.updateEndpoint(nameIdentifier, updateData, envId, next);
|
562 | });
|
563 | },
|
564 | done
|
565 | );
|
566 | }
|
567 |
|
568 | _modifyPushSettings(sourcePush, envId, done) {
|
569 | if (isEmpty(sourcePush)) {
|
570 | return setImmediate(done);
|
571 | }
|
572 |
|
573 | async.series([
|
574 | (next) => {
|
575 | const androidSettings = sourcePush.android;
|
576 | if (isEmpty(androidSettings)) {
|
577 | return setImmediate(next);
|
578 | }
|
579 |
|
580 | const data = {
|
581 | projectId: androidSettings.senderId,
|
582 | apiKey: androidSettings.apiKey
|
583 | };
|
584 | this.cliManager.log(LogLevel.INFO, 'Modifying Android push configuration');
|
585 | this.pushService.configureAndroidSettings(envId, data, next);
|
586 | },
|
587 | (next) => {
|
588 | const iosSettings = sourcePush.ios;
|
589 | if (isEmpty(iosSettings)) {
|
590 | return setImmediate(next);
|
591 | }
|
592 |
|
593 | this.cliManager.log(LogLevel.INFO, 'Modifying iOS push configuration');
|
594 | this.pushService.configureIosSettings(envId, iosSettings, next);
|
595 | }
|
596 | ], done);
|
597 | }
|
598 |
|
599 | _modifyCommonCode(commonCode = {}, env, done) {
|
600 | const envId = env.id;
|
601 | let groupedEntities;
|
602 |
|
603 | async.series([
|
604 | (next) => {
|
605 | this.blService.getCommonCode(envId, null, null, (err, originalCommonModules) => {
|
606 | if (err) {
|
607 | return next(err);
|
608 | }
|
609 |
|
610 | groupedEntities = FileProcessorHelper.groupEntitiesPerOperationType(originalCommonModules, commonCode);
|
611 | next();
|
612 | });
|
613 | },
|
614 | (next) => {
|
615 | this._updateCommonCode(groupedEntities[OperationType.UPDATE], env, next);
|
616 | },
|
617 | (next) => {
|
618 | this._createCommonCode(envId, groupedEntities[OperationType.CREATE], next);
|
619 | }
|
620 | ], done);
|
621 | }
|
622 |
|
623 | _updateCommonCode(commonCodeModules, env, done) {
|
624 | const envId = env.id;
|
625 |
|
626 | async.each(
|
627 | commonCodeModules,
|
628 | (commonModule, next) => {
|
629 | const moduleName = Object.keys(commonModule)[0];
|
630 | this.cliManager.log(LogLevel.INFO, `Updating common code module: ${moduleName}`);
|
631 | const sourceModule = commonModule[moduleName];
|
632 | sourceModule.name = sourceModule.name || moduleName;
|
633 | this.blService.updateCommonCode(moduleName, sourceModule, envId, next);
|
634 | },
|
635 | done
|
636 | );
|
637 | }
|
638 |
|
639 | static _getFilteredCollectionData(sourceCollection) {
|
640 | const collBlacklist = ['type', 'service', 'serviceEnvironment', 'serviceObject'];
|
641 | const filteredData = getObjectByOmitting(sourceCollection, collBlacklist);
|
642 | return filteredData;
|
643 | }
|
644 |
|
645 | |
646 |
|
647 |
|
648 |
|
649 |
|
650 |
|
651 |
|
652 |
|
653 |
|
654 | _createCollections(collections, env, groupedOriginalRoles, done) {
|
655 | if (isEmpty(collections)) {
|
656 | return setImmediate(done);
|
657 | }
|
658 |
|
659 | const collectionNames = Object.keys(collections);
|
660 | async.each(
|
661 | collectionNames,
|
662 | (collName, next) => {
|
663 | this._createCollection(collName, collections[collName], env, groupedOriginalRoles, next);
|
664 | },
|
665 | done
|
666 | );
|
667 | }
|
668 |
|
669 | |
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 |
|
677 |
|
678 | _setServiceOnCollection(sourceColl, targetColl, env, done) {
|
679 | this._findServiceFromSource(sourceColl, targetColl.name, env, (err, data) => {
|
680 | if (err) {
|
681 | return done(err);
|
682 | }
|
683 |
|
684 | if (data) {
|
685 | targetColl.dataLink = {
|
686 | serviceObjectName: sourceColl.serviceObject,
|
687 | id: data.service.id,
|
688 | backingServerId: data.svcEnv.id
|
689 | };
|
690 | }
|
691 |
|
692 | done();
|
693 | });
|
694 | }
|
695 |
|
696 | _setServiceOnHookOrEndpoint(source, name, env, done) {
|
697 | this._findServiceFromSource(source, name, env, (err, data) => {
|
698 | if (err) {
|
699 | return done(err);
|
700 | }
|
701 |
|
702 | if (data) {
|
703 | source.host = data.svcEnv.id;
|
704 | source.sdkHandlerName = source.handlerName;
|
705 | }
|
706 |
|
707 | done();
|
708 | });
|
709 | }
|
710 |
|
711 | _findServiceFromSource(source, name, env, done) {
|
712 | if (source.type !== 'external') {
|
713 | return setImmediate(done);
|
714 | }
|
715 |
|
716 | const domainId = env.app;
|
717 | this._getServiceInfo(source.service, source.serviceEnvironment, domainId, done);
|
718 | }
|
719 |
|
720 | _createCollection(collName, sourceColl, env, groupedOriginalRoles, done) {
|
721 | this.cliManager.log(LogLevel.INFO, `Creating collection: ${collName}`);
|
722 |
|
723 | const collData = EnvFileProcessor._getFilteredCollectionData(sourceColl);
|
724 | collData.name = collName;
|
725 |
|
726 | try {
|
727 | EnvFileProcessor.setPermissionsOnCollection(collData, groupedOriginalRoles);
|
728 | } catch (ex) {
|
729 | return done(ex);
|
730 | }
|
731 |
|
732 | async.series([
|
733 | (next) => {
|
734 | this._setServiceOnCollection(sourceColl, collData, env, next);
|
735 | },
|
736 | (next) => {
|
737 | const envId = env.id;
|
738 | this.collectionsService.create(collData, envId, next);
|
739 | }
|
740 | ], done);
|
741 | }
|
742 |
|
743 | _getServiceInfo(serviceIdentifier, svcEnvIdentifier, appId, done) {
|
744 | let service;
|
745 | let svcEnv;
|
746 | let app;
|
747 |
|
748 | async.series([
|
749 | (next) => {
|
750 | this.applicationsService.getByIdOrName(appId, (err, data) => {
|
751 | if (err) {
|
752 | return next(err);
|
753 | }
|
754 |
|
755 | app = data;
|
756 | next();
|
757 | });
|
758 | },
|
759 | (next) => {
|
760 | this.servicesService.getAllByDomainType(app, null, (err, data) => {
|
761 | if (err) {
|
762 | return next(err);
|
763 | }
|
764 |
|
765 | service = data.find(x => x.id === serviceIdentifier || x.name === serviceIdentifier);
|
766 | if (!service) {
|
767 | return next(getCustomNotFoundError(EntityType.SERVICE, serviceIdentifier));
|
768 | }
|
769 |
|
770 | next();
|
771 | });
|
772 | },
|
773 | (next) => {
|
774 | this.servicesService.getServiceEnvs(service.id, (err, data) => {
|
775 | if (err) {
|
776 | return next(err);
|
777 | }
|
778 |
|
779 | svcEnv = data.find(x => x.id === svcEnvIdentifier || x.name === svcEnvIdentifier);
|
780 | if (!svcEnv) {
|
781 | return next(getCustomNotFoundError(EntityType.SCV_ENV, svcEnvIdentifier));
|
782 | }
|
783 |
|
784 | next();
|
785 | });
|
786 | }
|
787 | ], (err) => {
|
788 | if (err) {
|
789 | return done(err);
|
790 | }
|
791 |
|
792 | done(null, { service, svcEnv });
|
793 | });
|
794 | }
|
795 |
|
796 | _updateCollections(collections, env, groupedOriginalRoles, done) {
|
797 | const envId = env.id;
|
798 |
|
799 | async.each(
|
800 | collections,
|
801 | (coll, next) => {
|
802 | const collName = Object.keys(coll)[0];
|
803 | this.cliManager.log(LogLevel.INFO, `Updating collection: ${collName}`);
|
804 | const sourceColl = coll[collName];
|
805 | const data = EnvFileProcessor._getFilteredCollectionData(sourceColl);
|
806 | data.name = data.name || collName;
|
807 |
|
808 | try {
|
809 | EnvFileProcessor.setPermissionsOnCollection(data, groupedOriginalRoles);
|
810 | } catch (ex) {
|
811 | return next(ex);
|
812 | }
|
813 |
|
814 | this._setServiceOnCollection(sourceColl, data, env, (err) => {
|
815 | if (err) {
|
816 | return next(err);
|
817 | }
|
818 |
|
819 | this.collectionsService.update(envId, collName, data, next);
|
820 | });
|
821 | },
|
822 | done
|
823 | );
|
824 | }
|
825 |
|
826 | |
827 |
|
828 |
|
829 |
|
830 |
|
831 |
|
832 |
|
833 |
|
834 |
|
835 |
|
836 | static setPermissionsOnCollection(collection, existingRoles) {
|
837 | const initialPermissions = collection.permissions;
|
838 | const isBasicPermissionsFormat = typeof initialPermissions === 'string';
|
839 | if (isBasicPermissionsFormat) {
|
840 | collection.permissions = BackendCollectionPermission[initialPermissions];
|
841 | return;
|
842 | }
|
843 |
|
844 | const transformedPermissions = {};
|
845 | AllowedPermissionsOperations.forEach((op) => { transformedPermissions[op] = []; });
|
846 |
|
847 | const rolesIdentifiers = Object.keys(initialPermissions);
|
848 | rolesIdentifiers.forEach((roleIdentifier) => {
|
849 | const isIdAndExists = Object.prototype.hasOwnProperty.call(existingRoles.byId, roleIdentifier);
|
850 | const isNameAndExists = Object.prototype.hasOwnProperty.call(existingRoles.byName, roleIdentifier);
|
851 | const isSystemRole = roleIdentifier === 'all-users';
|
852 | const roleExists = isIdAndExists || isNameAndExists || isSystemRole;
|
853 | const basicErrMsg = `Cannot set permissions on collection '${collection.name}'.`;
|
854 | if (!roleExists) {
|
855 | throw new Error(`${basicErrMsg} Role with identifier '${roleIdentifier}' not found.`);
|
856 | }
|
857 |
|
858 | let id;
|
859 | if (isIdAndExists || isSystemRole) {
|
860 | id = roleIdentifier;
|
861 | } else {
|
862 | if (existingRoles.duplicatedNames.includes(roleIdentifier)) {
|
863 | throw new Error(`${basicErrMsg} More than one role exists with name '${roleIdentifier}'.`);
|
864 | }
|
865 |
|
866 | id = existingRoles.byName[roleIdentifier]._id;
|
867 | }
|
868 |
|
869 | AllowedPermissionsOperations.forEach((op) => {
|
870 | if (Object.prototype.hasOwnProperty.call(initialPermissions[roleIdentifier], op)) {
|
871 | transformedPermissions[op].push({
|
872 | roleId: id,
|
873 | type: initialPermissions[roleIdentifier][op]
|
874 | });
|
875 | }
|
876 | });
|
877 | });
|
878 |
|
879 | collection.permissions = transformedPermissions;
|
880 | }
|
881 |
|
882 | _deleteCollections(collections, envId, done) {
|
883 | async.each(
|
884 | collections,
|
885 | (collName, next) => {
|
886 | this.cliManager.log(LogLevel.INFO, `Deleting collection ${collName}`);
|
887 | this.collectionsService.deleteById(envId, collName, next);
|
888 | },
|
889 | done
|
890 | );
|
891 | }
|
892 | }
|
893 |
|
894 | module.exports = EnvFileProcessor;
|