@esri/solution-deployer 4.1.2 → 5.0.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 (41) hide show
  1. package/dist/cjs/deploySolutionFromTemplate.d.ts +48 -48
  2. package/dist/cjs/deploySolutionFromTemplate.js +331 -331
  3. package/dist/cjs/deploySolutionFromTemplate.js.map +1 -1
  4. package/dist/cjs/deploySolutionItems.d.ts +224 -224
  5. package/dist/cjs/deploySolutionItems.js +853 -849
  6. package/dist/cjs/deploySolutionItems.js.map +1 -1
  7. package/dist/cjs/deployer.d.ts +34 -34
  8. package/dist/cjs/deployer.js +101 -101
  9. package/dist/cjs/deployerUtils.d.ts +47 -47
  10. package/dist/cjs/deployerUtils.js +123 -123
  11. package/dist/cjs/helpers/post-process.d.ts +29 -29
  12. package/dist/cjs/helpers/post-process.js +61 -61
  13. package/dist/cjs/helpers/share-templates-to-groups.d.ts +24 -24
  14. package/dist/cjs/helpers/share-templates-to-groups.js +64 -64
  15. package/dist/cjs/helpers/sortTemplates.d.ts +23 -23
  16. package/dist/cjs/helpers/sortTemplates.js +14 -14
  17. package/dist/cjs/index.d.ts +24 -24
  18. package/dist/cjs/index.js +27 -27
  19. package/dist/cjs/module-map.d.ts +23 -23
  20. package/dist/cjs/module-map.js +195 -195
  21. package/dist/esm/deploySolutionFromTemplate.d.ts +48 -48
  22. package/dist/esm/deploySolutionFromTemplate.js +317 -317
  23. package/dist/esm/deploySolutionFromTemplate.js.map +1 -1
  24. package/dist/esm/deploySolutionItems.d.ts +224 -224
  25. package/dist/esm/deploySolutionItems.js +830 -826
  26. package/dist/esm/deploySolutionItems.js.map +1 -1
  27. package/dist/esm/deployer.d.ts +34 -34
  28. package/dist/esm/deployer.js +96 -96
  29. package/dist/esm/deployerUtils.d.ts +47 -47
  30. package/dist/esm/deployerUtils.js +115 -115
  31. package/dist/esm/helpers/post-process.d.ts +29 -29
  32. package/dist/esm/helpers/post-process.js +57 -57
  33. package/dist/esm/helpers/share-templates-to-groups.d.ts +24 -24
  34. package/dist/esm/helpers/share-templates-to-groups.js +60 -60
  35. package/dist/esm/helpers/sortTemplates.d.ts +23 -23
  36. package/dist/esm/helpers/sortTemplates.js +10 -10
  37. package/dist/esm/index.d.ts +24 -24
  38. package/dist/esm/index.js +24 -24
  39. package/dist/esm/module-map.d.ts +23 -23
  40. package/dist/esm/module-map.js +191 -191
  41. package/package.json +12 -12
@@ -1,332 +1,332 @@
1
- "use strict";
2
- /** @license
3
- * Copyright 2018 Esri
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports._getNewItemId = exports._purgeTemplateProperties = exports._updateGroupReferences = exports._getPortalBaseUrl = exports._checkedReplaceAll = exports._updateProp = exports._replaceParamVariables = exports._applySourceToDeployOptions = exports._addSourceId = exports.deploySolutionFromTemplate = void 0;
19
- const tslib_1 = require("tslib");
20
- const common = tslib_1.__importStar(require("@esri/solution-common"));
21
- const deployItems = tslib_1.__importStar(require("./deploySolutionItems"));
22
- const hub_common_1 = require("@esri/hub-common");
23
- const portal = tslib_1.__importStar(require("@esri/arcgis-rest-portal"));
24
- const post_process_1 = require("./helpers/post-process");
25
- const sortTemplates_1 = require("./helpers/sortTemplates");
26
- const solution_common_1 = require("@esri/solution-common");
27
- // NOTE: Moved to separate file to allow stubbing in main deploySolution tests
28
- function deploySolutionFromTemplate(templateSolutionId, solutionTemplateBase, solutionTemplateData, authentication, options) {
29
- options.storageVersion = common.extractSolutionVersion(solutionTemplateData);
30
- return new Promise((resolve, reject) => {
31
- // It is possible to provide a separate authentication for the source
32
- const storageAuthentication = options.storageAuthentication
33
- ? options.storageAuthentication
34
- : authentication;
35
- // Replacement dictionary and high-level deployment ids for cleanup
36
- // TODO: Extract all templateDictionary prep into a separate function
37
- const templateDictionary = options.templateDictionary ?? {};
38
- let deployedFolderId;
39
- let deployedSolutionId;
40
- _applySourceToDeployOptions(options, solutionTemplateBase, templateDictionary, authentication);
41
- if (options.additionalTypeKeywords) {
42
- solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, options.additionalTypeKeywords);
43
- }
44
- // Get the thumbnail file
45
- let thumbFilename = "thumbnail";
46
- let thumbDef = Promise.resolve(null);
47
- if (!options.thumbnail && options.thumbnailurl) {
48
- // Figure out the thumbnail's filename
49
- thumbFilename =
50
- common.getFilenameFromUrl(options.thumbnailurl) || thumbFilename;
51
- const thumbnailurl = common.appendQueryParam(options.thumbnailurl, "w=400");
52
- delete options.thumbnailurl;
53
- // Fetch the thumbnail
54
- thumbDef = common.getBlobAsFile(thumbnailurl, thumbFilename, storageAuthentication, [400]);
55
- }
56
- _replaceParamVariables(solutionTemplateData, templateDictionary);
57
- // Get information about deployment environment
58
- Promise.all([
59
- common.getPortal("", authentication),
60
- common.getUser(authentication),
61
- common.getFoldersAndGroups(authentication),
62
- thumbDef
63
- ])
64
- .then(responses => {
65
- const [portalResponse, userResponse, foldersAndGroupsResponse, thumbnailFile] = responses;
66
- if (!options.thumbnail && thumbnailFile) {
67
- options.thumbnail = thumbnailFile;
68
- }
69
- // update template items with source-itemId type keyword
70
- solutionTemplateData.templates = _addSourceId(solutionTemplateData.templates);
71
- templateDictionary.isPortal = portalResponse.isPortal;
72
- templateDictionary.organization = Object.assign(templateDictionary.organization || {}, portalResponse);
73
- // TODO: Add more computed properties here
74
- // portal: portalResponse
75
- // orgextent as bbox for assignment onto items
76
- // more info in #266 https://github.com/Esri/solution.js/issues/266
77
- templateDictionary.portalBaseUrl = _getPortalBaseUrl(portalResponse, authentication);
78
- templateDictionary.user = userResponse;
79
- templateDictionary.user.folders = foldersAndGroupsResponse.folders;
80
- templateDictionary.user.groups = foldersAndGroupsResponse.groups.filter((group) => group.owner === templateDictionary.user.username);
81
- // if we have tracking views and the user is not admin or the org doesn't support tracking an error is thrown
82
- common.setLocationTrackingEnabled(portalResponse, userResponse, templateDictionary, solutionTemplateData.templates);
83
- const trackingOwnerPromise = common.getTackingServiceOwner(templateDictionary, authentication);
84
- // Create a folder to hold the deployed solution. We use the solution name, appending a sequential
85
- // suffix if the folder exists, e.g.,
86
- // * Manage Right of Way Activities
87
- // * Manage Right of Way Activities 1
88
- // * Manage Right of Way Activities 2
89
- const folderPromise = common.createUniqueFolder(solutionTemplateBase.title, templateDictionary, authentication);
90
- // Apply the portal extents to the solution
91
- const portalExtent = portalResponse.defaultExtent;
92
- const extentsPromise = common.convertExtentWithFallback(portalExtent, undefined, { wkid: 4326 }, portalResponse.helperServices.geometry.url, authentication);
93
- // Await completion of async actions: folder creation & extents conversion
94
- return Promise.all([folderPromise, extentsPromise, trackingOwnerPromise]);
95
- })
96
- .then(responses => {
97
- const [folderResponse, wgs84Extent, trackingOwnerResponse] = responses;
98
- deployedFolderId = folderResponse.folder.id;
99
- templateDictionary.folderId = deployedFolderId;
100
- templateDictionary.solutionItemExtent =
101
- wgs84Extent.xmin +
102
- "," +
103
- wgs84Extent.ymin +
104
- "," +
105
- wgs84Extent.xmax +
106
- "," +
107
- wgs84Extent.ymax;
108
- // Hub Solutions depend on organization defaultExtentBBox as a nested array not a string
109
- templateDictionary.organization.defaultExtentBBox = [
110
- [wgs84Extent.xmin, wgs84Extent.ymin],
111
- [wgs84Extent.xmax, wgs84Extent.ymax]
112
- ];
113
- // update templateDictionary to indicate if the user owns the tracking service
114
- // this will affect how we handle group sharing
115
- /* istanbul ignore else */
116
- if (templateDictionary.locationTrackingEnabled) {
117
- (0, solution_common_1.setCreateProp)(templateDictionary, "locationTracking.userIsOwner", trackingOwnerResponse);
118
- }
119
- // Create a deployed Solution item
120
- const createSolutionItemBase = {
121
- ...common.sanitizeJSON(solutionTemplateBase),
122
- type: "Solution",
123
- typeKeywords: ["Solution"]
124
- };
125
- if (options.additionalTypeKeywords) {
126
- createSolutionItemBase.typeKeywords = ["Solution"].concat(options.additionalTypeKeywords);
127
- }
128
- // Create deployed solution item
129
- createSolutionItemBase.thumbnail = options.thumbnail;
130
- return common.createItemWithData(createSolutionItemBase, {}, authentication, deployedFolderId);
131
- })
132
- .then(createSolutionResponse => {
133
- deployedSolutionId = createSolutionResponse.id;
134
- // Protect the solution item
135
- const protectOptions = {
136
- id: deployedSolutionId,
137
- authentication
138
- };
139
- return portal.protectItem(protectOptions);
140
- })
141
- .then(() => {
142
- // TODO: Attach the whole solution model so we can
143
- // have stuff like `{{solution.item.title}}
144
- templateDictionary.solutionItemId = deployedSolutionId;
145
- solutionTemplateBase.id = deployedSolutionId;
146
- solutionTemplateBase.tryitUrl = _checkedReplaceAll(solutionTemplateBase.tryitUrl, templateSolutionId, deployedSolutionId);
147
- solutionTemplateBase.url = _checkedReplaceAll(solutionTemplateBase.url, templateSolutionId, deployedSolutionId);
148
- // Handle the contained item templates
149
- return deployItems.deploySolutionItems(storageAuthentication.portal, templateSolutionId, solutionTemplateData.templates, storageAuthentication, templateDictionary, deployedSolutionId, authentication, options);
150
- })
151
- .then((clonedSolutionsResponse) => {
152
- solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => {
153
- // Update ids present in template dictionary
154
- itemTemplate.itemId = common.getProp(templateDictionary, `${itemTemplate.itemId}.itemId`);
155
- // Update the dependencies hash to point to the new item ids
156
- itemTemplate.dependencies = itemTemplate.dependencies.map((id) => (0, hub_common_1.getWithDefault)(templateDictionary, `${id}.itemId`, id));
157
- return itemTemplate;
158
- });
159
- // Sort the templates into build order, which is provided by clonedSolutionsResponse
160
- (0, sortTemplates_1.sortTemplates)(solutionTemplateData.templates, clonedSolutionsResponse.map(response => response.id));
161
- // Wrap up with post-processing, in which we deal with groups and cycle remnants
162
- return (0, post_process_1.postProcess)(deployedSolutionId, solutionTemplateData.templates, clonedSolutionsResponse, authentication, templateDictionary);
163
- })
164
- .then(() => {
165
- // Update solution item using internal representation & and the updated data JSON
166
- solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, ["Deployed"]);
167
- const iTemplateKeyword = solutionTemplateBase.typeKeywords.indexOf("Template");
168
- /* istanbul ignore else */
169
- if (iTemplateKeyword >= 0) {
170
- solutionTemplateBase.typeKeywords.splice(iTemplateKeyword, 1);
171
- }
172
- solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => _purgeTemplateProperties(itemTemplate));
173
- solutionTemplateData.templates = _updateGroupReferences(solutionTemplateData.templates, templateDictionary);
174
- // Update solution items data using template dictionary, and then update the
175
- // itemId & dependencies in each item template
176
- solutionTemplateBase.data = common.replaceInTemplate(solutionTemplateData, templateDictionary);
177
- // Write any user defined params to the solution
178
- /* istanbul ignore else */
179
- if (templateDictionary.params) {
180
- solutionTemplateBase.data.params = templateDictionary.params;
181
- }
182
- return common.updateItem(solutionTemplateBase, authentication, deployedFolderId);
183
- })
184
- .then(() => resolve(solutionTemplateBase.id), reject);
185
- });
186
- }
187
- exports.deploySolutionFromTemplate = deploySolutionFromTemplate;
188
- /**
189
- * Add source-id to items/groups typeKeywords
190
- *
191
- * @param template the array of solution data templates
192
- * @private
193
- */
194
- function _addSourceId(templates) {
195
- return templates.map((template) => {
196
- /* istanbul ignore else */
197
- if (template.item) {
198
- const typeKeywords = template.item.typeKeywords || [];
199
- typeKeywords.push("source-" + template.itemId);
200
- template.item.typeKeywords = typeKeywords;
201
- }
202
- return template;
203
- });
204
- }
205
- exports._addSourceId = _addSourceId;
206
- /**
207
- * Update the deployOptions with the group properties
208
- *
209
- * @param deployOptions
210
- * @param sourceInfo
211
- * @param authentication
212
- * @param isGroup Boolean to indicate if the files are associated with a group or item
213
- * @private
214
- */
215
- function _applySourceToDeployOptions(deployOptions, solutionTemplateBase, templateDictionary, authentication) {
216
- // Deploy a solution from the template's contents,
217
- // using the template's information as defaults for the deployed solution item
218
- ["title", "snippet", "description", "tags"].forEach(prop => {
219
- deployOptions[prop] = deployOptions[prop] ?? solutionTemplateBase[prop];
220
- if (deployOptions[prop]) {
221
- solutionTemplateBase[prop] = deployOptions[prop];
222
- // carry these options forward on the templateDict
223
- templateDictionary[prop] = deployOptions[prop];
224
- }
225
- });
226
- if (!deployOptions.thumbnailurl && solutionTemplateBase.thumbnail) {
227
- // Get the full path to the thumbnail
228
- deployOptions.thumbnailurl = common.generateSourceThumbnailUrl(authentication.portal, solutionTemplateBase.id, solutionTemplateBase.thumbnail);
229
- delete solutionTemplateBase.thumbnail;
230
- }
231
- return deployOptions;
232
- }
233
- exports._applySourceToDeployOptions = _applySourceToDeployOptions;
234
- //???
235
- function _replaceParamVariables(solutionTemplateData, templateDictionary) {
236
- // a custom params object can be passed in with the options to deploy a solution
237
- // in most cases we can defer to the item type handlers to use these values
238
- // for variable replacement
239
- // for spatial reference specifically we need to replace up front so the default extent
240
- // logic can execute as expected
241
- solutionTemplateData.templates = solutionTemplateData.templates.map((template) => {
242
- // can't do this as it causes other values that don't exist in the dict yet to revert to defaults they may have defined
243
- // return common.replaceInTemplate(template, templateDictionary);
244
- /* istanbul ignore else */
245
- if (template.type === "Feature Service") {
246
- const paramsLookup = "params.";
247
- const wkidItemPath = "item.spatialReference.wkid";
248
- template = _updateProp(template, wkidItemPath, paramsLookup, templateDictionary);
249
- const wkidServicePath = "properties.service.spatialReference.wkid";
250
- template = _updateProp(template, wkidServicePath, paramsLookup, templateDictionary);
251
- }
252
- return template;
253
- });
254
- }
255
- exports._replaceParamVariables = _replaceParamVariables;
256
- //???
257
- function _updateProp(template, path, lookup, templateDictionary) {
258
- const wkid = common.getProp(template, path);
259
- /* istanbul ignore else */
260
- if (wkid && typeof wkid === "string" && wkid.indexOf(lookup) > -1) {
261
- common.setProp(template, path, common.replaceInTemplate(wkid, templateDictionary));
262
- }
263
- return template;
264
- }
265
- exports._updateProp = _updateProp;
266
- //???
267
- function _checkedReplaceAll(template, oldValue, newValue) {
268
- let newTemplate;
269
- if (template && template.indexOf(oldValue) > -1) {
270
- const re = new RegExp(oldValue, "g");
271
- newTemplate = template.replace(re, newValue);
272
- }
273
- else {
274
- newTemplate = template;
275
- }
276
- return newTemplate;
277
- }
278
- exports._checkedReplaceAll = _checkedReplaceAll;
279
- //???
280
- function _getPortalBaseUrl(portalResponse, authentication) {
281
- // As of Spring 2020, only HTTPS (see
282
- // https://www.esri.com/arcgis-blog/products/product/administration/2019-arcgis-transport-security-improvements/)
283
- const scheme = "https"; // portalResponse.allSSL ? "https" : "http";
284
- const urlKey = common.getProp(portalResponse, "urlKey");
285
- const customBaseUrl = common.getProp(portalResponse, "customBaseUrl");
286
- const enterpriseBaseUrl = common.getProp(portalResponse, "portalHostname");
287
- return urlKey && customBaseUrl
288
- ? `${scheme}://${urlKey}.${customBaseUrl}`
289
- : enterpriseBaseUrl
290
- ? `${scheme}://${enterpriseBaseUrl}`
291
- : authentication.portal.replace("/sharing/rest", "");
292
- }
293
- exports._getPortalBaseUrl = _getPortalBaseUrl;
294
- //???
295
- function _updateGroupReferences(itemTemplates, templateDictionary) {
296
- const groupIds = itemTemplates.reduce((result, t) => {
297
- if (t.type === "Group") {
298
- result.push(t.itemId);
299
- }
300
- return result;
301
- }, []);
302
- Object.keys(templateDictionary).forEach(k => {
303
- const newId = templateDictionary[k].itemId;
304
- if (groupIds.indexOf(newId) > -1) {
305
- itemTemplates.forEach(t => {
306
- t.groups = t.groups.map((id) => (id === k ? newId : id));
307
- });
308
- }
309
- });
310
- return itemTemplates;
311
- }
312
- exports._updateGroupReferences = _updateGroupReferences;
313
- //???
314
- function _purgeTemplateProperties(itemTemplate) {
315
- const retainProps = ["itemId", "type", "dependencies", "groups"];
316
- const deleteProps = Object.keys(itemTemplate).filter(k => retainProps.indexOf(k) < 0);
317
- common.deleteProps(itemTemplate, deleteProps);
318
- return itemTemplate;
319
- }
320
- exports._purgeTemplateProperties = _purgeTemplateProperties;
321
- /**
322
- * Returns a match of a supplied id with the suffix ".itemId" in the template dictionary.
323
- *
324
- * @param id Id to look for
325
- * @param templateDictionary Hash mapping property names to replacement values
326
- * @returns Match in template dictionary or original id
327
- */
328
- function _getNewItemId(id, templateDictionary) {
329
- return common.getProp(templateDictionary, id + ".itemId") ?? id;
330
- }
331
- exports._getNewItemId = _getNewItemId;
1
+ "use strict";
2
+ /** @license
3
+ * Copyright 2018 Esri
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports._getNewItemId = exports._purgeTemplateProperties = exports._updateGroupReferences = exports._getPortalBaseUrl = exports._checkedReplaceAll = exports._updateProp = exports._replaceParamVariables = exports._applySourceToDeployOptions = exports._addSourceId = exports.deploySolutionFromTemplate = void 0;
19
+ const tslib_1 = require("tslib");
20
+ const common = tslib_1.__importStar(require("@esri/solution-common"));
21
+ const deployItems = tslib_1.__importStar(require("./deploySolutionItems"));
22
+ const hub_common_1 = require("@esri/hub-common");
23
+ const portal = tslib_1.__importStar(require("@esri/arcgis-rest-portal"));
24
+ const post_process_1 = require("./helpers/post-process");
25
+ const sortTemplates_1 = require("./helpers/sortTemplates");
26
+ const solution_common_1 = require("@esri/solution-common");
27
+ // NOTE: Moved to separate file to allow stubbing in main deploySolution tests
28
+ function deploySolutionFromTemplate(templateSolutionId, solutionTemplateBase, solutionTemplateData, authentication, options) {
29
+ options.storageVersion = common.extractSolutionVersion(solutionTemplateData);
30
+ return new Promise((resolve, reject) => {
31
+ // It is possible to provide a separate authentication for the source
32
+ const storageAuthentication = options.storageAuthentication
33
+ ? options.storageAuthentication
34
+ : authentication;
35
+ // Replacement dictionary and high-level deployment ids for cleanup
36
+ // TODO: Extract all templateDictionary prep into a separate function
37
+ const templateDictionary = options.templateDictionary ?? {};
38
+ let deployedFolderId;
39
+ let deployedSolutionId;
40
+ _applySourceToDeployOptions(options, solutionTemplateBase, templateDictionary, authentication);
41
+ if (options.additionalTypeKeywords) {
42
+ solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, options.additionalTypeKeywords);
43
+ }
44
+ // Get the thumbnail file
45
+ let thumbFilename = "thumbnail";
46
+ let thumbDef = Promise.resolve(null);
47
+ if (!options.thumbnail && options.thumbnailurl) {
48
+ // Figure out the thumbnail's filename
49
+ thumbFilename =
50
+ common.getFilenameFromUrl(options.thumbnailurl) || thumbFilename;
51
+ const thumbnailurl = common.appendQueryParam(options.thumbnailurl, "w=400");
52
+ delete options.thumbnailurl;
53
+ // Fetch the thumbnail
54
+ thumbDef = common.getBlobAsFile(thumbnailurl, thumbFilename, storageAuthentication, [400]);
55
+ }
56
+ _replaceParamVariables(solutionTemplateData, templateDictionary);
57
+ // Get information about deployment environment
58
+ Promise.all([
59
+ common.getPortal("", authentication),
60
+ common.getUser(authentication),
61
+ common.getFoldersAndGroups(authentication),
62
+ thumbDef
63
+ ])
64
+ .then(responses => {
65
+ const [portalResponse, userResponse, foldersAndGroupsResponse, thumbnailFile] = responses;
66
+ if (!options.thumbnail && thumbnailFile) {
67
+ options.thumbnail = thumbnailFile;
68
+ }
69
+ // update template items with source-itemId type keyword
70
+ solutionTemplateData.templates = _addSourceId(solutionTemplateData.templates);
71
+ templateDictionary.isPortal = portalResponse.isPortal;
72
+ templateDictionary.organization = Object.assign(templateDictionary.organization || {}, portalResponse);
73
+ // TODO: Add more computed properties here
74
+ // portal: portalResponse
75
+ // orgextent as bbox for assignment onto items
76
+ // more info in #266 https://github.com/Esri/solution.js/issues/266
77
+ templateDictionary.portalBaseUrl = _getPortalBaseUrl(portalResponse, authentication);
78
+ templateDictionary.user = userResponse;
79
+ templateDictionary.user.folders = foldersAndGroupsResponse.folders;
80
+ templateDictionary.user.groups = foldersAndGroupsResponse.groups.filter((group) => group.owner === templateDictionary.user.username);
81
+ // if we have tracking views and the user is not admin or the org doesn't support tracking an error is thrown
82
+ common.setLocationTrackingEnabled(portalResponse, userResponse, templateDictionary, solutionTemplateData.templates);
83
+ const trackingOwnerPromise = common.getTackingServiceOwner(templateDictionary, authentication);
84
+ // Create a folder to hold the deployed solution. We use the solution name, appending a sequential
85
+ // suffix if the folder exists, e.g.,
86
+ // * Manage Right of Way Activities
87
+ // * Manage Right of Way Activities 1
88
+ // * Manage Right of Way Activities 2
89
+ const folderPromise = common.createUniqueFolder(solutionTemplateBase.title, templateDictionary, authentication);
90
+ // Apply the portal extents to the solution
91
+ const portalExtent = portalResponse.defaultExtent;
92
+ const extentsPromise = common.convertExtentWithFallback(portalExtent, undefined, { wkid: 4326 }, portalResponse.helperServices.geometry.url, authentication);
93
+ // Await completion of async actions: folder creation & extents conversion
94
+ return Promise.all([folderPromise, extentsPromise, trackingOwnerPromise]);
95
+ })
96
+ .then(responses => {
97
+ const [folderResponse, wgs84Extent, trackingOwnerResponse] = responses;
98
+ deployedFolderId = folderResponse.folder.id;
99
+ templateDictionary.folderId = deployedFolderId;
100
+ templateDictionary.solutionItemExtent =
101
+ wgs84Extent.xmin +
102
+ "," +
103
+ wgs84Extent.ymin +
104
+ "," +
105
+ wgs84Extent.xmax +
106
+ "," +
107
+ wgs84Extent.ymax;
108
+ // Hub Solutions depend on organization defaultExtentBBox as a nested array not a string
109
+ templateDictionary.organization.defaultExtentBBox = [
110
+ [wgs84Extent.xmin, wgs84Extent.ymin],
111
+ [wgs84Extent.xmax, wgs84Extent.ymax]
112
+ ];
113
+ // update templateDictionary to indicate if the user owns the tracking service
114
+ // this will affect how we handle group sharing
115
+ /* istanbul ignore else */
116
+ if (templateDictionary.locationTrackingEnabled) {
117
+ (0, solution_common_1.setCreateProp)(templateDictionary, "locationTracking.userIsOwner", trackingOwnerResponse);
118
+ }
119
+ // Create a deployed Solution item
120
+ const createSolutionItemBase = {
121
+ ...common.sanitizeJSON(solutionTemplateBase),
122
+ type: "Solution",
123
+ typeKeywords: ["Solution"]
124
+ };
125
+ if (options.additionalTypeKeywords) {
126
+ createSolutionItemBase.typeKeywords = ["Solution"].concat(options.additionalTypeKeywords);
127
+ }
128
+ // Create deployed solution item
129
+ createSolutionItemBase.thumbnail = options.thumbnail;
130
+ return common.createItemWithData(createSolutionItemBase, {}, authentication, deployedFolderId);
131
+ })
132
+ .then(createSolutionResponse => {
133
+ deployedSolutionId = createSolutionResponse.id;
134
+ // Protect the solution item
135
+ const protectOptions = {
136
+ id: deployedSolutionId,
137
+ authentication
138
+ };
139
+ return portal.protectItem(protectOptions);
140
+ })
141
+ .then(() => {
142
+ // TODO: Attach the whole solution model so we can
143
+ // have stuff like `{{solution.item.title}}
144
+ templateDictionary.solutionItemId = deployedSolutionId;
145
+ solutionTemplateBase.id = deployedSolutionId;
146
+ solutionTemplateBase.tryitUrl = _checkedReplaceAll(solutionTemplateBase.tryitUrl, templateSolutionId, deployedSolutionId);
147
+ solutionTemplateBase.url = _checkedReplaceAll(solutionTemplateBase.url, templateSolutionId, deployedSolutionId);
148
+ // Handle the contained item templates
149
+ return deployItems.deploySolutionItems(storageAuthentication.portal, templateSolutionId, solutionTemplateData.templates, storageAuthentication, templateDictionary, deployedSolutionId, authentication, options);
150
+ })
151
+ .then((clonedSolutionsResponse) => {
152
+ solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => {
153
+ // Update ids present in template dictionary
154
+ itemTemplate.itemId = common.getProp(templateDictionary, `${itemTemplate.itemId}.itemId`);
155
+ // Update the dependencies hash to point to the new item ids
156
+ itemTemplate.dependencies = itemTemplate.dependencies.map((id) => (0, hub_common_1.getWithDefault)(templateDictionary, `${id}.itemId`, id));
157
+ return itemTemplate;
158
+ });
159
+ // Sort the templates into build order, which is provided by clonedSolutionsResponse
160
+ (0, sortTemplates_1.sortTemplates)(solutionTemplateData.templates, clonedSolutionsResponse.map(response => response.id));
161
+ // Wrap up with post-processing, in which we deal with groups and cycle remnants
162
+ return (0, post_process_1.postProcess)(deployedSolutionId, solutionTemplateData.templates, clonedSolutionsResponse, authentication, templateDictionary);
163
+ })
164
+ .then(() => {
165
+ // Update solution item using internal representation & and the updated data JSON
166
+ solutionTemplateBase.typeKeywords = [].concat(solutionTemplateBase.typeKeywords, ["Deployed"]);
167
+ const iTemplateKeyword = solutionTemplateBase.typeKeywords.indexOf("Template");
168
+ /* istanbul ignore else */
169
+ if (iTemplateKeyword >= 0) {
170
+ solutionTemplateBase.typeKeywords.splice(iTemplateKeyword, 1);
171
+ }
172
+ solutionTemplateData.templates = solutionTemplateData.templates.map((itemTemplate) => _purgeTemplateProperties(itemTemplate));
173
+ solutionTemplateData.templates = _updateGroupReferences(solutionTemplateData.templates, templateDictionary);
174
+ // Update solution items data using template dictionary, and then update the
175
+ // itemId & dependencies in each item template
176
+ solutionTemplateBase.data = common.replaceInTemplate(solutionTemplateData, templateDictionary);
177
+ // Write any user defined params to the solution
178
+ /* istanbul ignore else */
179
+ if (templateDictionary.params) {
180
+ solutionTemplateBase.data.params = templateDictionary.params;
181
+ }
182
+ return common.updateItem(solutionTemplateBase, authentication, deployedFolderId);
183
+ })
184
+ .then(() => resolve(solutionTemplateBase.id), reject);
185
+ });
186
+ }
187
+ exports.deploySolutionFromTemplate = deploySolutionFromTemplate;
188
+ /**
189
+ * Add source-id to items/groups typeKeywords
190
+ *
191
+ * @param template the array of solution data templates
192
+ * @private
193
+ */
194
+ function _addSourceId(templates) {
195
+ return templates.map((template) => {
196
+ /* istanbul ignore else */
197
+ if (template.item) {
198
+ const typeKeywords = template.item.typeKeywords || [];
199
+ typeKeywords.push("source-" + template.itemId);
200
+ template.item.typeKeywords = typeKeywords;
201
+ }
202
+ return template;
203
+ });
204
+ }
205
+ exports._addSourceId = _addSourceId;
206
+ /**
207
+ * Update the deployOptions with the group properties
208
+ *
209
+ * @param deployOptions
210
+ * @param sourceInfo
211
+ * @param authentication
212
+ * @param isGroup Boolean to indicate if the files are associated with a group or item
213
+ * @private
214
+ */
215
+ function _applySourceToDeployOptions(deployOptions, solutionTemplateBase, templateDictionary, authentication) {
216
+ // Deploy a solution from the template's contents,
217
+ // using the template's information as defaults for the deployed solution item
218
+ ["title", "snippet", "description", "tags"].forEach(prop => {
219
+ deployOptions[prop] = deployOptions[prop] ?? solutionTemplateBase[prop];
220
+ if (deployOptions[prop]) {
221
+ solutionTemplateBase[prop] = deployOptions[prop];
222
+ // carry these options forward on the templateDict
223
+ templateDictionary[prop] = deployOptions[prop];
224
+ }
225
+ });
226
+ if (!deployOptions.thumbnailurl && solutionTemplateBase.thumbnail) {
227
+ // Get the full path to the thumbnail
228
+ deployOptions.thumbnailurl = common.generateSourceThumbnailUrl(authentication.portal, solutionTemplateBase.id, solutionTemplateBase.thumbnail);
229
+ delete solutionTemplateBase.thumbnail;
230
+ }
231
+ return deployOptions;
232
+ }
233
+ exports._applySourceToDeployOptions = _applySourceToDeployOptions;
234
+ //TODO: function doc
235
+ function _replaceParamVariables(solutionTemplateData, templateDictionary) {
236
+ // a custom params object can be passed in with the options to deploy a solution
237
+ // in most cases we can defer to the item type handlers to use these values
238
+ // for variable replacement
239
+ // for spatial reference specifically we need to replace up front so the default extent
240
+ // logic can execute as expected
241
+ solutionTemplateData.templates = solutionTemplateData.templates.map((template) => {
242
+ // can't do this as it causes other values that don't exist in the dict yet to revert to defaults they may have defined
243
+ // return common.replaceInTemplate(template, templateDictionary);
244
+ /* istanbul ignore else */
245
+ if (template.type === "Feature Service") {
246
+ const paramsLookup = "params.";
247
+ const wkidItemPath = "item.spatialReference.wkid";
248
+ template = _updateProp(template, wkidItemPath, paramsLookup, templateDictionary);
249
+ const wkidServicePath = "properties.service.spatialReference.wkid";
250
+ template = _updateProp(template, wkidServicePath, paramsLookup, templateDictionary);
251
+ }
252
+ return template;
253
+ });
254
+ }
255
+ exports._replaceParamVariables = _replaceParamVariables;
256
+ //TODO: function doc
257
+ function _updateProp(template, path, lookup, templateDictionary) {
258
+ const wkid = common.getProp(template, path);
259
+ /* istanbul ignore else */
260
+ if (wkid && typeof wkid === "string" && wkid.indexOf(lookup) > -1) {
261
+ common.setProp(template, path, common.replaceInTemplate(wkid, templateDictionary));
262
+ }
263
+ return template;
264
+ }
265
+ exports._updateProp = _updateProp;
266
+ //TODO: function doc
267
+ function _checkedReplaceAll(template, oldValue, newValue) {
268
+ let newTemplate;
269
+ if (template && template.indexOf(oldValue) > -1) {
270
+ const re = new RegExp(oldValue, "g");
271
+ newTemplate = template.replace(re, newValue);
272
+ }
273
+ else {
274
+ newTemplate = template;
275
+ }
276
+ return newTemplate;
277
+ }
278
+ exports._checkedReplaceAll = _checkedReplaceAll;
279
+ //TODO: function doc
280
+ function _getPortalBaseUrl(portalResponse, authentication) {
281
+ // As of Spring 2020, only HTTPS (see
282
+ // https://www.esri.com/arcgis-blog/products/product/administration/2019-arcgis-transport-security-improvements/)
283
+ const scheme = "https"; // portalResponse.allSSL ? "https" : "http";
284
+ const urlKey = common.getProp(portalResponse, "urlKey");
285
+ const customBaseUrl = common.getProp(portalResponse, "customBaseUrl");
286
+ const enterpriseBaseUrl = common.getProp(portalResponse, "portalHostname");
287
+ return urlKey && customBaseUrl
288
+ ? `${scheme}://${urlKey}.${customBaseUrl}`
289
+ : enterpriseBaseUrl
290
+ ? `${scheme}://${enterpriseBaseUrl}`
291
+ : authentication.portal.replace("/sharing/rest", "");
292
+ }
293
+ exports._getPortalBaseUrl = _getPortalBaseUrl;
294
+ //TODO: function doc
295
+ function _updateGroupReferences(itemTemplates, templateDictionary) {
296
+ const groupIds = itemTemplates.reduce((result, t) => {
297
+ if (t.type === "Group") {
298
+ result.push(t.itemId);
299
+ }
300
+ return result;
301
+ }, []);
302
+ Object.keys(templateDictionary).forEach(k => {
303
+ const newId = templateDictionary[k].itemId;
304
+ if (groupIds.indexOf(newId) > -1) {
305
+ itemTemplates.forEach(t => {
306
+ t.groups = t.groups.map((id) => (id === k ? newId : id));
307
+ });
308
+ }
309
+ });
310
+ return itemTemplates;
311
+ }
312
+ exports._updateGroupReferences = _updateGroupReferences;
313
+ //TODO: function doc
314
+ function _purgeTemplateProperties(itemTemplate) {
315
+ const retainProps = ["itemId", "type", "dependencies", "groups"];
316
+ const deleteProps = Object.keys(itemTemplate).filter(k => retainProps.indexOf(k) < 0);
317
+ common.deleteProps(itemTemplate, deleteProps);
318
+ return itemTemplate;
319
+ }
320
+ exports._purgeTemplateProperties = _purgeTemplateProperties;
321
+ /**
322
+ * Returns a match of a supplied id with the suffix ".itemId" in the template dictionary.
323
+ *
324
+ * @param id Id to look for
325
+ * @param templateDictionary Hash mapping property names to replacement values
326
+ * @returns Match in template dictionary or original id
327
+ */
328
+ function _getNewItemId(id, templateDictionary) {
329
+ return common.getProp(templateDictionary, id + ".itemId") ?? id;
330
+ }
331
+ exports._getNewItemId = _getNewItemId;
332
332
  //# sourceMappingURL=deploySolutionFromTemplate.js.map