@esri/solution-creator 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.
@@ -1,268 +1,268 @@
1
- /** @license
2
- * Copyright 2018 Esri
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- /**
17
- * Manages the creation of a Solution item.
18
- *
19
- * @module creator
20
- */
21
- import { appendQueryParam, createItemWithData, createLongId, createShortId, CURRENT_SCHEMA_VERSION, generateSourceThumbnailUrl, getBlobAsFile, getFilenameFromUrl, getGroupBase, getGroupContents, getItemBase, getPortal, getUser, getVelocityUrlBase, removeItem, sanitizeJSON, setLocationTrackingEnabled } from "@esri/solution-common";
22
- import { failSafe } from "@esri/hub-common";
23
- import { addContentToSolution } from "./helpers/add-content-to-solution";
24
- // Simple no-op to clean up progressCallback management
25
- const noOp = () => { };
26
- /**
27
- * Creates a solution item.
28
- *
29
- * @param sourceId AGO id of group whose contents are to be added to solution or of an item to convert into a solution
30
- * @param srcAuthentication Credentials for requests to source items
31
- * @param destAuthentication Credentials for the requests to destination solution
32
- * @param options Customizations for creating the solution
33
- * @returns A promise that resolves with the AGO id of the new solution
34
- */
35
- export function createSolution(sourceId, srcAuthentication, destAuthentication, options) {
36
- const createOptions = options || {};
37
- const progressCb = createOptions.progressCallback || noOp;
38
- createOptions.templateDictionary = Object.assign({}, createOptions.templateDictionary);
39
- progressCb(1); // let the caller know that we've started
40
- // Assume that source is a group and try to get group's information
41
- return Promise.all([
42
- getGroupBase(sourceId, srcAuthentication),
43
- getGroupContents(sourceId, srcAuthentication),
44
- getVelocityUrlBase(srcAuthentication, createOptions.templateDictionary)
45
- ])
46
- .then(
47
- // Group fetches worked; assumption was correct
48
- responses => {
49
- createOptions.itemIds = responses[1];
50
- progressCb(15);
51
- return new Promise(resolve => {
52
- // Update the createOptions with values from the group
53
- resolve(_applySourceToCreateOptions(createOptions, responses[0], srcAuthentication, true));
54
- });
55
- },
56
- // Assumption incorrect; try source as an item
57
- () => {
58
- return new Promise((resolve, reject) => {
59
- createOptions.itemIds = [sourceId];
60
- getItemBase(sourceId, srcAuthentication).then(
61
- // Update the createOptions with values from the item
62
- itemBase => resolve(_applySourceToCreateOptions(createOptions, itemBase, srcAuthentication, false)), reject);
63
- });
64
- })
65
- .then(createOptions => {
66
- return new Promise((resolve, reject) => {
67
- Promise.all([
68
- getPortal("", srcAuthentication),
69
- getUser(srcAuthentication)
70
- ]).then(responses => {
71
- // check tracking
72
- const [portalResponse, userResponse] = responses;
73
- setLocationTrackingEnabled(portalResponse, userResponse, createOptions.templateDictionary);
74
- resolve(createOptions);
75
- }, reject);
76
- });
77
- })
78
- .then(
79
- // Use a copy of the thumbnail rather than a URL to it
80
- createOptions => {
81
- return _addThumbnailFileToCreateOptions(createOptions, srcAuthentication);
82
- })
83
- .then(
84
- // Create a solution
85
- createOptions => {
86
- return _createSolutionFromItemIds(createOptions, srcAuthentication, destAuthentication);
87
- })
88
- .then(
89
- // Successfully created solution
90
- createdSolutionId => {
91
- progressCb(100); // finished
92
- return createdSolutionId;
93
- },
94
- // Error fetching group, group contents, or item, or error creating solution from ids
95
- error => {
96
- progressCb(1);
97
- console.error(error);
98
- throw error;
99
- });
100
- }
101
- /**
102
- * Update the createOptions with the group properties
103
- *
104
- * @param createOptions
105
- * @param sourceInfo
106
- * @param authentication
107
- * @param isGroup Boolean to indicate if the files are associated with a group or item
108
- * @private
109
- */
110
- export function _applySourceToCreateOptions(createOptions, sourceInfo, srcAuthentication, isGroup = false) {
111
- // Create a solution from the group's or item's contents,
112
- // using the group's or item's information as defaults for the solution item
113
- ["title", "snippet", "description", "tags"].forEach(prop => {
114
- createOptions[prop] = createOptions[prop] ?? sourceInfo[prop];
115
- });
116
- if (!createOptions.thumbnailurl && sourceInfo.thumbnail) {
117
- // Get the full path to the thumbnail
118
- createOptions.thumbnailurl = generateSourceThumbnailUrl(srcAuthentication.portal, sourceInfo.id, sourceInfo.thumbnail, isGroup);
119
- delete sourceInfo.thumbnail;
120
- }
121
- return createOptions;
122
- }
123
- /**
124
- * Update the createOptions with the thumbnail file
125
- *
126
- * @param createOptions
127
- * @param srcAuthentication
128
- * @private
129
- */
130
- export function _addThumbnailFileToCreateOptions(createOptions, srcAuthentication) {
131
- return new Promise(resolve => {
132
- if (!createOptions.thumbnail && createOptions.thumbnailurl) {
133
- // Figure out the thumbnail's filename
134
- const filename = getFilenameFromUrl(createOptions.thumbnailurl) || "thumbnail";
135
- const thumbnailurl = appendQueryParam(createOptions.thumbnailurl, "w=400");
136
- delete createOptions.thumbnailurl;
137
- // Fetch the thumbnail
138
- getBlobAsFile(thumbnailurl, filename, srcAuthentication).then(thumbnail => {
139
- createOptions.thumbnail = thumbnail;
140
- resolve(createOptions);
141
- }, () => {
142
- resolve(createOptions);
143
- });
144
- }
145
- else {
146
- resolve(createOptions);
147
- }
148
- });
149
- }
150
- /**
151
- * Creates a solution item using a list of AGO item ids.
152
- *
153
- * @param options Customizations for creating the solution
154
- * @param srcAuthentication Credentials for requests to source items
155
- * @param destAuthentication Credentials for the requests to destination solution
156
- * @returns A promise that resolves with the AGO id of the new solution; solution item is deleted if its
157
- * there is a problem updating it
158
- * @private
159
- */
160
- export function _createSolutionFromItemIds(options, srcAuthentication, destAuthentication) {
161
- let solutionId = "";
162
- // Create a solution from the list of items
163
- return _createSolutionItem(destAuthentication, options)
164
- .then(id => {
165
- solutionId = id;
166
- // Add list of items to the new solution
167
- return addContentToSolution(solutionId, options, srcAuthentication, destAuthentication);
168
- })
169
- .catch(addError => {
170
- // If the solution item got created, delete it
171
- if (solutionId) {
172
- const failSafeRemove = failSafe(removeItem, { success: true });
173
- return failSafeRemove(solutionId, destAuthentication).then(() => {
174
- throw addError;
175
- });
176
- }
177
- else {
178
- throw addError;
179
- }
180
- });
181
- }
182
- /**
183
- * Creates an empty solution item.
184
- *
185
- * @param authentication Credentials for the request
186
- * @param options Customizations for creating the solution
187
- * @returns A promise that resolves with the AGO id of the new solution; solution item is deleted if its
188
- * there is a problem updating its thumbnail
189
- * @private
190
- */
191
- export function _createSolutionItem(authentication, options) {
192
- const model = _createSolutionItemModel(options);
193
- // Create new solution item
194
- delete model.item.thumbnailurl;
195
- model.item.thumbnail = options?.thumbnail;
196
- return createItemWithData(model.item, model.data, authentication, options?.folderId).then(createResponse => {
197
- return Promise.resolve(createResponse.id);
198
- });
199
- }
200
- /**
201
- * Create the Solution Item model to be used to create
202
- * the Solution Item itself
203
- *
204
- * @param options
205
- * @private
206
- */
207
- export function _createSolutionItemModel(options) {
208
- // Solution uses all supplied tags but for deploy.* tags; that information goes into properties
209
- const creationTags = options?.tags ?? [];
210
- const solutionItem = {
211
- type: "Solution",
212
- title: options?.title ?? createShortId(),
213
- snippet: options?.snippet ?? "",
214
- description: options?.description ?? "",
215
- properties: {
216
- schemaVersion: CURRENT_SCHEMA_VERSION
217
- },
218
- thumbnailurl: options?.thumbnailurl ?? "",
219
- tags: creationTags.filter((tag) => !tag.startsWith("deploy.")),
220
- typeKeywords: ["Solution", "Template"].concat(_getDeploymentProperties(creationTags))
221
- };
222
- // ensure that snippet and description are not nefarious
223
- const sanitizedItem = sanitizeJSON(solutionItem);
224
- const addlKeywords = options?.additionalTypeKeywords || [];
225
- sanitizedItem.typeKeywords = [].concat(solutionItem.typeKeywords, addlKeywords);
226
- const solutionData = {
227
- metadata: {},
228
- templates: []
229
- };
230
- return {
231
- item: sanitizedItem,
232
- data: solutionData
233
- };
234
- }
235
- /**
236
- * Gets the deploy.id and deploy.version tag values.
237
- *
238
- * @param tags A list of item tags
239
- * @returns A list containing the two values found in the tags, or defaulting to a new GUID and "1.0", respectively,
240
- * as needed
241
- * @private
242
- */
243
- export function _getDeploymentProperties(tags) {
244
- return [
245
- "solutionid-" +
246
- (_getDeploymentProperty("deploy.id.", tags) ?? createLongId()),
247
- "solutionversion-" +
248
- (_getDeploymentProperty("deploy.version.", tags) ?? "1.0")
249
- ];
250
- }
251
- /**
252
- * Searches for a tag that has the specified prefix and returns the rest of the tag following that prefix.
253
- *
254
- * @param desiredTagPrefix Tag prefix to look for
255
- * @param tags A list of item tags
256
- * @returns The extracted value of the first matching tag or null if a tag with the specified prefix is not found
257
- * @private
258
- */
259
- export function _getDeploymentProperty(desiredTagPrefix, tags) {
260
- const foundTagAsList = tags.filter(tag => tag.startsWith(desiredTagPrefix));
261
- if (foundTagAsList.length > 0) {
262
- return foundTagAsList[0].substr(desiredTagPrefix.length);
263
- }
264
- else {
265
- return null;
266
- }
267
- }
1
+ /** @license
2
+ * Copyright 2018 Esri
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Manages the creation of a Solution item.
18
+ *
19
+ * @module creator
20
+ */
21
+ import { appendQueryParam, createItemWithData, createLongId, createShortId, CURRENT_SCHEMA_VERSION, generateSourceThumbnailUrl, getBlobAsFile, getFilenameFromUrl, getGroupBase, getGroupContents, getItemBase, getPortal, getUser, getVelocityUrlBase, removeItem, sanitizeJSON, setLocationTrackingEnabled } from "@esri/solution-common";
22
+ import { failSafe } from "@esri/hub-common";
23
+ import { addContentToSolution } from "./helpers/add-content-to-solution";
24
+ // Simple no-op to clean up progressCallback management
25
+ const noOp = () => { };
26
+ /**
27
+ * Creates a solution item.
28
+ *
29
+ * @param sourceId AGO id of group whose contents are to be added to solution or of an item to convert into a solution
30
+ * @param srcAuthentication Credentials for requests to source items
31
+ * @param destAuthentication Credentials for the requests to destination solution
32
+ * @param options Customizations for creating the solution
33
+ * @returns A promise that resolves with the AGO id of the new solution
34
+ */
35
+ export function createSolution(sourceId, srcAuthentication, destAuthentication, options) {
36
+ const createOptions = options || {};
37
+ const progressCb = createOptions.progressCallback || noOp;
38
+ createOptions.templateDictionary = Object.assign({}, createOptions.templateDictionary);
39
+ progressCb(1); // let the caller know that we've started
40
+ // Assume that source is a group and try to get group's information
41
+ return Promise.all([
42
+ getGroupBase(sourceId, srcAuthentication),
43
+ getGroupContents(sourceId, srcAuthentication),
44
+ getVelocityUrlBase(srcAuthentication, createOptions.templateDictionary)
45
+ ])
46
+ .then(
47
+ // Group fetches worked; assumption was correct
48
+ responses => {
49
+ createOptions.itemIds = responses[1];
50
+ progressCb(15);
51
+ return new Promise(resolve => {
52
+ // Update the createOptions with values from the group
53
+ resolve(_applySourceToCreateOptions(createOptions, responses[0], srcAuthentication, true));
54
+ });
55
+ },
56
+ // Assumption incorrect; try source as an item
57
+ () => {
58
+ return new Promise((resolve, reject) => {
59
+ createOptions.itemIds = [sourceId];
60
+ getItemBase(sourceId, srcAuthentication).then(
61
+ // Update the createOptions with values from the item
62
+ itemBase => resolve(_applySourceToCreateOptions(createOptions, itemBase, srcAuthentication, false)), reject);
63
+ });
64
+ })
65
+ .then(createOptions => {
66
+ return new Promise((resolve, reject) => {
67
+ Promise.all([
68
+ getPortal("", srcAuthentication),
69
+ getUser(srcAuthentication)
70
+ ]).then(responses => {
71
+ // check tracking
72
+ const [portalResponse, userResponse] = responses;
73
+ setLocationTrackingEnabled(portalResponse, userResponse, createOptions.templateDictionary);
74
+ resolve(createOptions);
75
+ }, reject);
76
+ });
77
+ })
78
+ .then(
79
+ // Use a copy of the thumbnail rather than a URL to it
80
+ createOptions => {
81
+ return _addThumbnailFileToCreateOptions(createOptions, srcAuthentication);
82
+ })
83
+ .then(
84
+ // Create a solution
85
+ createOptions => {
86
+ return _createSolutionFromItemIds(createOptions, srcAuthentication, destAuthentication);
87
+ })
88
+ .then(
89
+ // Successfully created solution
90
+ createdSolutionId => {
91
+ progressCb(100); // finished
92
+ return createdSolutionId;
93
+ },
94
+ // Error fetching group, group contents, or item, or error creating solution from ids
95
+ error => {
96
+ progressCb(1);
97
+ console.error(error);
98
+ throw error;
99
+ });
100
+ }
101
+ /**
102
+ * Update the createOptions with the group properties
103
+ *
104
+ * @param createOptions
105
+ * @param sourceInfo
106
+ * @param authentication
107
+ * @param isGroup Boolean to indicate if the files are associated with a group or item
108
+ * @private
109
+ */
110
+ export function _applySourceToCreateOptions(createOptions, sourceInfo, srcAuthentication, isGroup = false) {
111
+ // Create a solution from the group's or item's contents,
112
+ // using the group's or item's information as defaults for the solution item
113
+ ["title", "snippet", "description", "tags"].forEach(prop => {
114
+ createOptions[prop] = createOptions[prop] ?? sourceInfo[prop];
115
+ });
116
+ if (!createOptions.thumbnailurl && sourceInfo.thumbnail) {
117
+ // Get the full path to the thumbnail
118
+ createOptions.thumbnailurl = generateSourceThumbnailUrl(srcAuthentication.portal, sourceInfo.id, sourceInfo.thumbnail, isGroup);
119
+ delete sourceInfo.thumbnail;
120
+ }
121
+ return createOptions;
122
+ }
123
+ /**
124
+ * Update the createOptions with the thumbnail file
125
+ *
126
+ * @param createOptions
127
+ * @param srcAuthentication
128
+ * @private
129
+ */
130
+ export function _addThumbnailFileToCreateOptions(createOptions, srcAuthentication) {
131
+ return new Promise(resolve => {
132
+ if (!createOptions.thumbnail && createOptions.thumbnailurl) {
133
+ // Figure out the thumbnail's filename
134
+ const filename = getFilenameFromUrl(createOptions.thumbnailurl) || "thumbnail";
135
+ const thumbnailurl = appendQueryParam(createOptions.thumbnailurl, "w=400");
136
+ delete createOptions.thumbnailurl;
137
+ // Fetch the thumbnail
138
+ getBlobAsFile(thumbnailurl, filename, srcAuthentication).then(thumbnail => {
139
+ createOptions.thumbnail = thumbnail;
140
+ resolve(createOptions);
141
+ }, () => {
142
+ resolve(createOptions);
143
+ });
144
+ }
145
+ else {
146
+ resolve(createOptions);
147
+ }
148
+ });
149
+ }
150
+ /**
151
+ * Creates a solution item using a list of AGO item ids.
152
+ *
153
+ * @param options Customizations for creating the solution
154
+ * @param srcAuthentication Credentials for requests to source items
155
+ * @param destAuthentication Credentials for the requests to destination solution
156
+ * @returns A promise that resolves with the AGO id of the new solution; solution item is deleted if its
157
+ * there is a problem updating it
158
+ * @private
159
+ */
160
+ export function _createSolutionFromItemIds(options, srcAuthentication, destAuthentication) {
161
+ let solutionId = "";
162
+ // Create a solution from the list of items
163
+ return _createSolutionItem(destAuthentication, options)
164
+ .then(id => {
165
+ solutionId = id;
166
+ // Add list of items to the new solution
167
+ return addContentToSolution(solutionId, options, srcAuthentication, destAuthentication);
168
+ })
169
+ .catch(addError => {
170
+ // If the solution item got created, delete it
171
+ if (solutionId) {
172
+ const failSafeRemove = failSafe(removeItem, { success: true });
173
+ return failSafeRemove(solutionId, destAuthentication).then(() => {
174
+ throw addError;
175
+ });
176
+ }
177
+ else {
178
+ throw addError;
179
+ }
180
+ });
181
+ }
182
+ /**
183
+ * Creates an empty solution item.
184
+ *
185
+ * @param authentication Credentials for the request
186
+ * @param options Customizations for creating the solution
187
+ * @returns A promise that resolves with the AGO id of the new solution; solution item is deleted if its
188
+ * there is a problem updating its thumbnail
189
+ * @private
190
+ */
191
+ export function _createSolutionItem(authentication, options) {
192
+ const model = _createSolutionItemModel(options);
193
+ // Create new solution item
194
+ delete model.item.thumbnailurl;
195
+ model.item.thumbnail = options?.thumbnail;
196
+ return createItemWithData(model.item, model.data, authentication, options?.folderId).then(createResponse => {
197
+ return Promise.resolve(createResponse.id);
198
+ });
199
+ }
200
+ /**
201
+ * Create the Solution Item model to be used to create
202
+ * the Solution Item itself
203
+ *
204
+ * @param options
205
+ * @private
206
+ */
207
+ export function _createSolutionItemModel(options) {
208
+ // Solution uses all supplied tags but for deploy.* tags; that information goes into properties
209
+ const creationTags = options?.tags ?? [];
210
+ const solutionItem = {
211
+ type: "Solution",
212
+ title: options?.title ?? createShortId(),
213
+ snippet: options?.snippet ?? "",
214
+ description: options?.description ?? "",
215
+ properties: {
216
+ schemaVersion: CURRENT_SCHEMA_VERSION
217
+ },
218
+ thumbnailurl: options?.thumbnailurl ?? "",
219
+ tags: creationTags.filter((tag) => !tag.startsWith("deploy.")),
220
+ typeKeywords: ["Solution", "Template"].concat(_getDeploymentProperties(creationTags))
221
+ };
222
+ // ensure that snippet and description are not nefarious
223
+ const sanitizedItem = sanitizeJSON(solutionItem);
224
+ const addlKeywords = options?.additionalTypeKeywords || [];
225
+ sanitizedItem.typeKeywords = [].concat(solutionItem.typeKeywords, addlKeywords);
226
+ const solutionData = {
227
+ metadata: {},
228
+ templates: []
229
+ };
230
+ return {
231
+ item: sanitizedItem,
232
+ data: solutionData
233
+ };
234
+ }
235
+ /**
236
+ * Gets the deploy.id and deploy.version tag values.
237
+ *
238
+ * @param tags A list of item tags
239
+ * @returns A list containing the two values found in the tags, or defaulting to a new GUID and "1.0", respectively,
240
+ * as needed
241
+ * @private
242
+ */
243
+ export function _getDeploymentProperties(tags) {
244
+ return [
245
+ "solutionid-" +
246
+ (_getDeploymentProperty("deploy.id.", tags) ?? createLongId()),
247
+ "solutionversion-" +
248
+ (_getDeploymentProperty("deploy.version.", tags) ?? "1.0")
249
+ ];
250
+ }
251
+ /**
252
+ * Searches for a tag that has the specified prefix and returns the rest of the tag following that prefix.
253
+ *
254
+ * @param desiredTagPrefix Tag prefix to look for
255
+ * @param tags A list of item tags
256
+ * @returns The extracted value of the first matching tag or null if a tag with the specified prefix is not found
257
+ * @private
258
+ */
259
+ export function _getDeploymentProperty(desiredTagPrefix, tags) {
260
+ const foundTagAsList = tags.filter(tag => tag.startsWith(desiredTagPrefix));
261
+ if (foundTagAsList.length > 0) {
262
+ return foundTagAsList[0].substr(desiredTagPrefix.length);
263
+ }
264
+ else {
265
+ return null;
266
+ }
267
+ }
268
268
  //# sourceMappingURL=creator.js.map