@esri/solution-common 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 (261) hide show
  1. package/dist/cjs/completeItem.d.ts +29 -29
  2. package/dist/cjs/completeItem.js +81 -81
  3. package/dist/cjs/create-hub-request-options.d.ts +29 -29
  4. package/dist/cjs/create-hub-request-options.js +63 -63
  5. package/dist/cjs/deleteHelpers/deleteEmptyGroups.d.ts +24 -24
  6. package/dist/cjs/deleteHelpers/deleteEmptyGroups.js +41 -41
  7. package/dist/cjs/deleteHelpers/deleteGroupIfEmpty.d.ts +27 -27
  8. package/dist/cjs/deleteHelpers/deleteGroupIfEmpty.js +96 -96
  9. package/dist/cjs/deleteHelpers/deleteSolutionContents.d.ts +38 -38
  10. package/dist/cjs/deleteHelpers/deleteSolutionContents.js +129 -129
  11. package/dist/cjs/deleteHelpers/deleteSolutionFolder.d.ts +29 -29
  12. package/dist/cjs/deleteHelpers/deleteSolutionFolder.js +78 -78
  13. package/dist/cjs/deleteHelpers/deleteSolutionItem.d.ts +30 -30
  14. package/dist/cjs/deleteHelpers/deleteSolutionItem.js +53 -53
  15. package/dist/cjs/deleteHelpers/index.d.ts +22 -22
  16. package/dist/cjs/deleteHelpers/index.js +25 -25
  17. package/dist/cjs/deleteHelpers/reconstructBuildOrderIds.d.ts +27 -27
  18. package/dist/cjs/deleteHelpers/reconstructBuildOrderIds.js +33 -33
  19. package/dist/cjs/deleteHelpers/removeItems.d.ts +34 -34
  20. package/dist/cjs/deleteHelpers/removeItems.js +111 -111
  21. package/dist/cjs/deleteHelpers/reportProgress.d.ts +27 -27
  22. package/dist/cjs/deleteHelpers/reportProgress.js +45 -45
  23. package/dist/cjs/deleteSolution.d.ts +55 -55
  24. package/dist/cjs/deleteSolution.js +106 -106
  25. package/dist/cjs/dependencies.d.ts +26 -26
  26. package/dist/cjs/dependencies.js +170 -170
  27. package/dist/cjs/featureServiceHelpers.d.ts +791 -791
  28. package/dist/cjs/featureServiceHelpers.js +2420 -2420
  29. package/dist/cjs/generalHelpers.d.ts +392 -385
  30. package/dist/cjs/generalHelpers.js +857 -854
  31. package/dist/cjs/generalHelpers.js.map +1 -1
  32. package/dist/cjs/get-subscription-info.d.ts +27 -27
  33. package/dist/cjs/get-subscription-info.js +38 -38
  34. package/dist/cjs/getDeletableSolutionInfo.d.ts +29 -29
  35. package/dist/cjs/getDeletableSolutionInfo.js +52 -52
  36. package/dist/cjs/getItemTypeAbbrev.d.ts +19 -19
  37. package/dist/cjs/getItemTypeAbbrev.js +184 -184
  38. package/dist/cjs/getSolutionSummary.d.ts +27 -27
  39. package/dist/cjs/getSolutionSummary.js +100 -100
  40. package/dist/cjs/index.d.ts +43 -44
  41. package/dist/cjs/index.js +46 -47
  42. package/dist/cjs/index.js.map +1 -1
  43. package/dist/cjs/interfaces.d.ts +1334 -1334
  44. package/dist/cjs/interfaces.js +74 -74
  45. package/dist/cjs/interfaces.js.map +1 -1
  46. package/dist/cjs/libConnectors.d.ts +73 -73
  47. package/dist/cjs/libConnectors.js +114 -114
  48. package/dist/cjs/migrations/apply-schema.d.ts +24 -24
  49. package/dist/cjs/migrations/apply-schema.js +35 -35
  50. package/dist/cjs/migrations/is-legacy-solution.d.ts +24 -24
  51. package/dist/cjs/migrations/is-legacy-solution.js +39 -39
  52. package/dist/cjs/migrations/upgrade-three-dot-one.d.ts +27 -27
  53. package/dist/cjs/migrations/upgrade-three-dot-one.js +48 -48
  54. package/dist/cjs/migrations/upgrade-three-dot-zero.d.ts +27 -27
  55. package/dist/cjs/migrations/upgrade-three-dot-zero.js +42 -42
  56. package/dist/cjs/migrations/upgrade-two-dot-five.d.ts +24 -24
  57. package/dist/cjs/migrations/upgrade-two-dot-five.js +72 -72
  58. package/dist/cjs/migrations/upgrade-two-dot-four.d.ts +24 -24
  59. package/dist/cjs/migrations/upgrade-two-dot-four.js +71 -71
  60. package/dist/cjs/migrations/upgrade-two-dot-one.d.ts +7 -7
  61. package/dist/cjs/migrations/upgrade-two-dot-one.js +38 -38
  62. package/dist/cjs/migrations/upgrade-two-dot-seven.d.ts +23 -23
  63. package/dist/cjs/migrations/upgrade-two-dot-seven.js +57 -57
  64. package/dist/cjs/migrations/upgrade-two-dot-six.d.ts +27 -27
  65. package/dist/cjs/migrations/upgrade-two-dot-six.js +60 -60
  66. package/dist/cjs/migrations/upgrade-two-dot-three.d.ts +23 -23
  67. package/dist/cjs/migrations/upgrade-two-dot-three.js +54 -54
  68. package/dist/cjs/migrations/upgrade-two-dot-two.d.ts +23 -23
  69. package/dist/cjs/migrations/upgrade-two-dot-two.js +57 -57
  70. package/dist/cjs/migrations/upgrade-two-dot-zero.d.ts +44 -44
  71. package/dist/cjs/migrations/upgrade-two-dot-zero.js +94 -94
  72. package/dist/cjs/migrator.d.ts +25 -25
  73. package/dist/cjs/migrator.js +76 -76
  74. package/dist/cjs/resourceHelpers.d.ts +191 -191
  75. package/dist/cjs/resourceHelpers.js +383 -390
  76. package/dist/cjs/resourceHelpers.js.map +1 -1
  77. package/dist/cjs/resources/add-resource-from-blob.d.ts +26 -26
  78. package/dist/cjs/resources/add-resource-from-blob.js +51 -51
  79. package/dist/cjs/resources/addMetadataFromBlob.d.ts +25 -25
  80. package/dist/cjs/resources/addMetadataFromBlob.js +42 -42
  81. package/dist/cjs/resources/convert-item-resource-to-storage-resource.d.ts +32 -32
  82. package/dist/cjs/resources/convert-item-resource-to-storage-resource.js +69 -69
  83. package/dist/cjs/resources/convert-storage-resource-to-item-resource.d.ts +29 -29
  84. package/dist/cjs/resources/convert-storage-resource-to-item-resource.js +69 -69
  85. package/dist/cjs/resources/copyAssociatedFiles.d.ts +67 -67
  86. package/dist/cjs/resources/copyAssociatedFiles.js +301 -301
  87. package/dist/cjs/resources/copyDataIntoItem.d.ts +33 -33
  88. package/dist/cjs/resources/copyDataIntoItem.js +61 -62
  89. package/dist/cjs/resources/copyDataIntoItem.js.map +1 -1
  90. package/dist/cjs/resources/copyMetadataIntoItem.d.ts +26 -26
  91. package/dist/cjs/resources/copyMetadataIntoItem.js +45 -45
  92. package/dist/cjs/resources/copyResourceIntoZip.d.ts +33 -33
  93. package/dist/cjs/resources/copyResourceIntoZip.js +77 -77
  94. package/dist/cjs/resources/copyZipIntoItem.d.ts +25 -25
  95. package/dist/cjs/resources/copyZipIntoItem.js +53 -53
  96. package/dist/cjs/resources/createCopyResults.d.ts +25 -25
  97. package/dist/cjs/resources/createCopyResults.js +35 -35
  98. package/dist/cjs/resources/get-blob.d.ts +26 -26
  99. package/dist/cjs/resources/get-blob.js +26 -26
  100. package/dist/cjs/resources/getItemResourcesFilesFromPaths.d.ts +24 -24
  101. package/dist/cjs/resources/getItemResourcesFilesFromPaths.js +48 -48
  102. package/dist/cjs/resources/getItemResourcesPaths.d.ts +26 -26
  103. package/dist/cjs/resources/getItemResourcesPaths.js +72 -72
  104. package/dist/cjs/resources/index.d.ts +29 -29
  105. package/dist/cjs/resources/index.js +32 -32
  106. package/dist/cjs/resources/solution-resource.d.ts +35 -35
  107. package/dist/cjs/resources/solution-resource.js +30 -30
  108. package/dist/cjs/resources/solution-resource.js.map +1 -1
  109. package/dist/cjs/resources/transform-resource-paths-to-solution-resources.d.ts +56 -56
  110. package/dist/cjs/resources/transform-resource-paths-to-solution-resources.js +145 -145
  111. package/dist/cjs/restHelpers.d.ts +586 -585
  112. package/dist/cjs/restHelpers.js +1888 -1883
  113. package/dist/cjs/restHelpers.js.map +1 -1
  114. package/dist/cjs/restHelpersGet.d.ts +288 -288
  115. package/dist/cjs/restHelpersGet.js +803 -803
  116. package/dist/cjs/sharing/index.d.ts +16 -16
  117. package/dist/cjs/sharing/index.js +19 -19
  118. package/dist/cjs/sharing/share-item-to-groups.d.ts +26 -26
  119. package/dist/cjs/sharing/share-item-to-groups.js +43 -43
  120. package/dist/cjs/templatization.d.ts +139 -139
  121. package/dist/cjs/templatization.js +313 -313
  122. package/dist/cjs/trackingHelpers.d.ts +116 -116
  123. package/dist/cjs/trackingHelpers.js +216 -216
  124. package/dist/cjs/velocityHelpers.d.ts +57 -57
  125. package/dist/cjs/velocityHelpers.js +134 -134
  126. package/dist/cjs/workforceHelpers.d.ts +115 -115
  127. package/dist/cjs/workforceHelpers.js +746 -746
  128. package/dist/cjs/workforceHelpers.js.map +1 -1
  129. package/dist/esm/completeItem.d.ts +29 -29
  130. package/dist/esm/completeItem.js +76 -76
  131. package/dist/esm/create-hub-request-options.d.ts +29 -29
  132. package/dist/esm/create-hub-request-options.js +59 -59
  133. package/dist/esm/deleteHelpers/deleteEmptyGroups.d.ts +24 -24
  134. package/dist/esm/deleteHelpers/deleteEmptyGroups.js +37 -37
  135. package/dist/esm/deleteHelpers/deleteGroupIfEmpty.d.ts +27 -27
  136. package/dist/esm/deleteHelpers/deleteGroupIfEmpty.js +91 -91
  137. package/dist/esm/deleteHelpers/deleteSolutionContents.d.ts +38 -38
  138. package/dist/esm/deleteHelpers/deleteSolutionContents.js +124 -124
  139. package/dist/esm/deleteHelpers/deleteSolutionFolder.d.ts +29 -29
  140. package/dist/esm/deleteHelpers/deleteSolutionFolder.js +73 -73
  141. package/dist/esm/deleteHelpers/deleteSolutionItem.d.ts +30 -30
  142. package/dist/esm/deleteHelpers/deleteSolutionItem.js +48 -48
  143. package/dist/esm/deleteHelpers/index.d.ts +22 -22
  144. package/dist/esm/deleteHelpers/index.js +22 -22
  145. package/dist/esm/deleteHelpers/reconstructBuildOrderIds.d.ts +27 -27
  146. package/dist/esm/deleteHelpers/reconstructBuildOrderIds.js +28 -28
  147. package/dist/esm/deleteHelpers/removeItems.d.ts +34 -34
  148. package/dist/esm/deleteHelpers/removeItems.js +106 -106
  149. package/dist/esm/deleteHelpers/reportProgress.d.ts +27 -27
  150. package/dist/esm/deleteHelpers/reportProgress.js +41 -41
  151. package/dist/esm/deleteSolution.d.ts +55 -55
  152. package/dist/esm/deleteSolution.js +100 -100
  153. package/dist/esm/dependencies.d.ts +26 -26
  154. package/dist/esm/dependencies.js +166 -166
  155. package/dist/esm/featureServiceHelpers.d.ts +791 -791
  156. package/dist/esm/featureServiceHelpers.js +2336 -2336
  157. package/dist/esm/generalHelpers.d.ts +392 -385
  158. package/dist/esm/generalHelpers.js +810 -808
  159. package/dist/esm/generalHelpers.js.map +1 -1
  160. package/dist/esm/get-subscription-info.d.ts +27 -27
  161. package/dist/esm/get-subscription-info.js +34 -34
  162. package/dist/esm/getDeletableSolutionInfo.d.ts +29 -29
  163. package/dist/esm/getDeletableSolutionInfo.js +47 -47
  164. package/dist/esm/getItemTypeAbbrev.d.ts +19 -19
  165. package/dist/esm/getItemTypeAbbrev.js +180 -180
  166. package/dist/esm/getSolutionSummary.d.ts +27 -27
  167. package/dist/esm/getSolutionSummary.js +95 -95
  168. package/dist/esm/index.d.ts +43 -44
  169. package/dist/esm/index.js +43 -44
  170. package/dist/esm/index.js.map +1 -1
  171. package/dist/esm/interfaces.d.ts +1334 -1334
  172. package/dist/esm/interfaces.js +70 -70
  173. package/dist/esm/libConnectors.d.ts +73 -73
  174. package/dist/esm/libConnectors.js +104 -104
  175. package/dist/esm/migrations/apply-schema.d.ts +24 -24
  176. package/dist/esm/migrations/apply-schema.js +31 -31
  177. package/dist/esm/migrations/is-legacy-solution.d.ts +24 -24
  178. package/dist/esm/migrations/is-legacy-solution.js +35 -35
  179. package/dist/esm/migrations/upgrade-three-dot-one.d.ts +27 -27
  180. package/dist/esm/migrations/upgrade-three-dot-one.js +44 -44
  181. package/dist/esm/migrations/upgrade-three-dot-zero.d.ts +27 -27
  182. package/dist/esm/migrations/upgrade-three-dot-zero.js +38 -38
  183. package/dist/esm/migrations/upgrade-two-dot-five.d.ts +24 -24
  184. package/dist/esm/migrations/upgrade-two-dot-five.js +68 -68
  185. package/dist/esm/migrations/upgrade-two-dot-four.d.ts +24 -24
  186. package/dist/esm/migrations/upgrade-two-dot-four.js +67 -67
  187. package/dist/esm/migrations/upgrade-two-dot-one.d.ts +7 -7
  188. package/dist/esm/migrations/upgrade-two-dot-one.js +34 -34
  189. package/dist/esm/migrations/upgrade-two-dot-seven.d.ts +23 -23
  190. package/dist/esm/migrations/upgrade-two-dot-seven.js +53 -53
  191. package/dist/esm/migrations/upgrade-two-dot-six.d.ts +27 -27
  192. package/dist/esm/migrations/upgrade-two-dot-six.js +56 -56
  193. package/dist/esm/migrations/upgrade-two-dot-three.d.ts +23 -23
  194. package/dist/esm/migrations/upgrade-two-dot-three.js +50 -50
  195. package/dist/esm/migrations/upgrade-two-dot-two.d.ts +23 -23
  196. package/dist/esm/migrations/upgrade-two-dot-two.js +53 -53
  197. package/dist/esm/migrations/upgrade-two-dot-zero.d.ts +44 -44
  198. package/dist/esm/migrations/upgrade-two-dot-zero.js +87 -87
  199. package/dist/esm/migrator.d.ts +25 -25
  200. package/dist/esm/migrator.js +72 -72
  201. package/dist/esm/resourceHelpers.d.ts +191 -191
  202. package/dist/esm/resourceHelpers.js +364 -371
  203. package/dist/esm/resourceHelpers.js.map +1 -1
  204. package/dist/esm/resources/add-resource-from-blob.d.ts +26 -26
  205. package/dist/esm/resources/add-resource-from-blob.js +47 -47
  206. package/dist/esm/resources/addMetadataFromBlob.d.ts +25 -25
  207. package/dist/esm/resources/addMetadataFromBlob.js +38 -38
  208. package/dist/esm/resources/convert-item-resource-to-storage-resource.d.ts +32 -32
  209. package/dist/esm/resources/convert-item-resource-to-storage-resource.js +65 -65
  210. package/dist/esm/resources/convert-storage-resource-to-item-resource.d.ts +29 -29
  211. package/dist/esm/resources/convert-storage-resource-to-item-resource.js +65 -65
  212. package/dist/esm/resources/copyAssociatedFiles.d.ts +67 -67
  213. package/dist/esm/resources/copyAssociatedFiles.js +293 -293
  214. package/dist/esm/resources/copyDataIntoItem.d.ts +33 -33
  215. package/dist/esm/resources/copyDataIntoItem.js +56 -57
  216. package/dist/esm/resources/copyDataIntoItem.js.map +1 -1
  217. package/dist/esm/resources/copyMetadataIntoItem.d.ts +26 -26
  218. package/dist/esm/resources/copyMetadataIntoItem.js +41 -41
  219. package/dist/esm/resources/copyResourceIntoZip.d.ts +33 -33
  220. package/dist/esm/resources/copyResourceIntoZip.js +72 -72
  221. package/dist/esm/resources/copyZipIntoItem.d.ts +25 -25
  222. package/dist/esm/resources/copyZipIntoItem.js +49 -49
  223. package/dist/esm/resources/createCopyResults.d.ts +25 -25
  224. package/dist/esm/resources/createCopyResults.js +31 -31
  225. package/dist/esm/resources/get-blob.d.ts +26 -26
  226. package/dist/esm/resources/get-blob.js +22 -22
  227. package/dist/esm/resources/getItemResourcesFilesFromPaths.d.ts +24 -24
  228. package/dist/esm/resources/getItemResourcesFilesFromPaths.js +44 -44
  229. package/dist/esm/resources/getItemResourcesPaths.d.ts +26 -26
  230. package/dist/esm/resources/getItemResourcesPaths.js +68 -68
  231. package/dist/esm/resources/index.d.ts +29 -29
  232. package/dist/esm/resources/index.js +29 -29
  233. package/dist/esm/resources/solution-resource.d.ts +35 -35
  234. package/dist/esm/resources/solution-resource.js +27 -27
  235. package/dist/esm/resources/transform-resource-paths-to-solution-resources.d.ts +56 -56
  236. package/dist/esm/resources/transform-resource-paths-to-solution-resources.js +137 -137
  237. package/dist/esm/restHelpers.d.ts +586 -585
  238. package/dist/esm/restHelpers.js +1827 -1823
  239. package/dist/esm/restHelpers.js.map +1 -1
  240. package/dist/esm/restHelpersGet.d.ts +288 -288
  241. package/dist/esm/restHelpersGet.js +763 -763
  242. package/dist/esm/sharing/index.d.ts +16 -16
  243. package/dist/esm/sharing/index.js +16 -16
  244. package/dist/esm/sharing/share-item-to-groups.d.ts +26 -26
  245. package/dist/esm/sharing/share-item-to-groups.js +39 -39
  246. package/dist/esm/templatization.d.ts +139 -139
  247. package/dist/esm/templatization.js +293 -293
  248. package/dist/esm/trackingHelpers.d.ts +116 -116
  249. package/dist/esm/trackingHelpers.js +204 -204
  250. package/dist/esm/velocityHelpers.d.ts +57 -57
  251. package/dist/esm/velocityHelpers.js +128 -128
  252. package/dist/esm/workforceHelpers.d.ts +115 -115
  253. package/dist/esm/workforceHelpers.js +717 -717
  254. package/dist/esm/workforceHelpers.js.map +1 -1
  255. package/package.json +2 -2
  256. package/dist/cjs/polyfills.d.ts +0 -40
  257. package/dist/cjs/polyfills.js +0 -98
  258. package/dist/cjs/polyfills.js.map +0 -1
  259. package/dist/esm/polyfills.d.ts +0 -40
  260. package/dist/esm/polyfills.js +0 -93
  261. package/dist/esm/polyfills.js.map +0 -1
@@ -1,1884 +1,1889 @@
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._getContingentValuesUpdates = exports._getRelationshipUpdates = exports._getFallbackExtent = exports._getCreateServiceOptions = exports._countRelationships = exports._addItemMetadataFile = exports._addItemDataFile = exports.updateItemURL = exports.updateItemTemplateFromDictionary = exports.updateItemExtended = exports.updateGroup = exports.updateItem = exports.shareItem = exports.removeUsers = exports.reassignGroup = exports.searchGroupContents = exports.searchGroupAllContents = exports.searchAllGroups = exports.searchGroups = exports.searchAllItems = exports.searchItems = exports.removeItemOrGroup = exports.removeItem = exports.removeGroup = exports.removeFolder = exports.hasInvalidGroupDesignations = exports._parseAdminServiceData = exports.getFeatureServiceProperties = exports.getServiceLayersAndTables = exports.getRequest = exports._sortRelationships = exports.getLayerUpdates = exports.getLayers = exports.extractDependencies = exports.createUniqueGroup = exports.createUniqueFolder = exports.createItemWithData = exports.createFullItem = exports.createFeatureService = exports.convertExtent = exports.convertExtentWithFallback = exports._validateExtent = exports.convertToISearchOptions = exports.checkRequestStatus = exports.addToServiceDefinition = exports.addTokenToUrl = exports.addForwardItemRelationships = exports.addForwardItemRelationship = exports.getUserSession = exports.rest_request = void 0;
19
- exports._updateItemURL = exports._updateIndexesForRelationshipKeyFields = exports._setItemProperties = exports._reportVariablesInItem = exports._lowercaseDomain = exports._getUpdate = void 0;
20
- /**
21
- * Provides common functions involving the arcgis-rest-js library.
22
- *
23
- * @module restHelpers
24
- */
25
- const featureServiceHelpers_1 = require("./featureServiceHelpers");
26
- const generalHelpers_1 = require("./generalHelpers");
27
- const interfaces_1 = require("./interfaces");
28
- const libConnectors_1 = require("./libConnectors");
29
- const restHelpersGet_1 = require("./restHelpersGet");
30
- const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
31
- const arcgis_rest_request_1 = require("@esri/arcgis-rest-request");
32
- const arcgis_rest_service_admin_1 = require("@esri/arcgis-rest-service-admin");
33
- const workforceHelpers_1 = require("./workforceHelpers");
34
- const templatization_1 = require("./templatization");
35
- const trackingHelpers_1 = require("./trackingHelpers");
36
- // ------------------------------------------------------------------------------------------------------------------ //
37
- var arcgis_rest_request_2 = require("@esri/arcgis-rest-request");
38
- Object.defineProperty(exports, "rest_request", { enumerable: true, get: function () { return arcgis_rest_request_2.request; } });
39
- // ------------------------------------------------------------------------------------------------------------------ //
40
- /**
41
- * Creates a UserSession via a function so that the global arcgisSolution variable can access authentication.
42
- *
43
- * @param options See https://esri.github.io/arcgis-rest-js/api/auth/IUserSessionOptions/
44
- * @returns UserSession
45
- */
46
- function getUserSession(options = {}) {
47
- return new interfaces_1.UserSession(options);
48
- }
49
- exports.getUserSession = getUserSession;
50
- /**
51
- * Adds a forward relationship between two items.
52
- *
53
- * @param originItemId Origin of relationship
54
- * @param destinationItemId Destination of relationship
55
- * @param relationshipType Type of relationship
56
- * @param authentication Credentials for the request
57
- * @returns A Promise to add item resources.
58
- */
59
- function addForwardItemRelationship(originItemId, destinationItemId, relationshipType, authentication) {
60
- return new Promise(resolve => {
61
- const requestOptions = {
62
- originItemId,
63
- destinationItemId,
64
- relationshipType,
65
- authentication
66
- };
67
- (0, arcgis_rest_portal_1.addItemRelationship)(requestOptions).then(response => {
68
- resolve({
69
- success: response.success,
70
- itemId: originItemId
71
- });
72
- }, () => {
73
- resolve({
74
- success: false,
75
- itemId: originItemId
76
- });
77
- });
78
- });
79
- }
80
- exports.addForwardItemRelationship = addForwardItemRelationship;
81
- /**
82
- * Adds forward relationships for an item.
83
- *
84
- * @param originItemId Origin of relationship
85
- * @param destinationRelationships Destinations
86
- * @param authentication Credentials for the request
87
- * @returns A Promise to add item resources.
88
- */
89
- function addForwardItemRelationships(originItemId, destinationRelationships, authentication) {
90
- return new Promise(resolve => {
91
- // Set up relationships using updated relationship information
92
- const relationshipPromises = new Array();
93
- destinationRelationships.forEach(relationship => {
94
- relationship.relatedItemIds.forEach(relatedItemId => {
95
- relationshipPromises.push(addForwardItemRelationship(originItemId, relatedItemId, relationship.relationshipType, authentication));
96
- });
97
- });
98
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
99
- Promise.all(relationshipPromises).then((responses) => resolve(responses));
100
- });
101
- }
102
- exports.addForwardItemRelationships = addForwardItemRelationships;
103
- /**
104
- * Adds a token to the query parameters of a URL.
105
- *
106
- * @param url URL to use as base
107
- * @param authentication Credentials to be used to generate token for URL
108
- * @returns A promise that will resolve with the supplied URL with `token=<token>` added to its query params
109
- * unless either the URL doesn't exist or the token can't be generated
110
- */
111
- function addTokenToUrl(url, authentication) {
112
- return new Promise(resolve => {
113
- if (!url || !authentication) {
114
- resolve(url);
115
- }
116
- else {
117
- authentication.getToken(url).then(token => {
118
- /* istanbul ignore else */
119
- if (token) {
120
- url = (0, generalHelpers_1.appendQueryParam)(url, "token=" + token);
121
- }
122
- resolve(url);
123
- }, () => resolve(url));
124
- }
125
- });
126
- }
127
- exports.addTokenToUrl = addTokenToUrl;
128
- /**
129
- * Calls addToDefinition for the service.
130
- *
131
- * Added retry due to some solutions failing to deploy in specific orgs/hives due to timeouts.
132
- * On the first pass we will use the quicker sync request to add.
133
- * If it fails we will use an async request that will avoid the timeout errors.
134
- *
135
- * @param url URL to use as base
136
- * @param options the info to add to the services definition
137
- * @param skipRetry a boolean to control if retry logic will be used. Defaults to false.
138
- * @param useAsync a boolean to control if we will use an async request
139
- * @returns A promise that will resolve when the request has completed
140
- */
141
- function addToServiceDefinition(url, options, skipRetry = false, useAsync = false) {
142
- /* istanbul ignore else */
143
- if (useAsync) {
144
- options.params = { ...options.params, async: true };
145
- }
146
- return new Promise((resolve, reject) => {
147
- (0, arcgis_rest_service_admin_1.addToServiceDefinition)(url, options).then((result) => {
148
- checkRequestStatus(result, options.authentication).then(() => resolve(null), e => reject((0, generalHelpers_1.fail)(e)));
149
- }, e => {
150
- if (!skipRetry) {
151
- addToServiceDefinition(url, options, true, true).then(() => resolve(null), e => reject(e));
152
- }
153
- else {
154
- reject((0, generalHelpers_1.fail)(e));
155
- }
156
- });
157
- });
158
- }
159
- exports.addToServiceDefinition = addToServiceDefinition;
160
- /**
161
- * When using an async request we need to poll the status url to know when the request has completed or failed.
162
- *
163
- * @param result the result returned from the addToDefinition request.
164
- * This will contain a status url or the standard sync result.
165
- * @param authentication Credentials to be used to generate token for URL
166
- * @returns A promise that will resolve when the request has completed
167
- */
168
- function checkRequestStatus(result, authentication) {
169
- return new Promise((resolve, reject) => {
170
- if (result.statusURL) {
171
- const checkStatus = setInterval(() => {
172
- (0, arcgis_rest_request_1.request)(result.statusURL, { authentication }).then(r => {
173
- /* istanbul ignore else */
174
- if (r.status === "Completed") {
175
- clearInterval(checkStatus);
176
- resolve();
177
- }
178
- else if (r.status === "Failed") {
179
- clearInterval(checkStatus);
180
- reject(r);
181
- }
182
- }, e => {
183
- clearInterval(checkStatus);
184
- reject(e);
185
- });
186
- }, 2000);
187
- }
188
- else {
189
- resolve();
190
- }
191
- });
192
- }
193
- exports.checkRequestStatus = checkRequestStatus;
194
- /**
195
- * Converts a general search into an ISearchOptions structure.
196
- *
197
- * @param search Search specified in one of three ways
198
- * @returns Recast search
199
- */
200
- function convertToISearchOptions(search) {
201
- // Convert the search into an ISearchOptions
202
- let searchOptions = {
203
- q: "",
204
- start: 1,
205
- num: 100
206
- };
207
- if (typeof search === "string") {
208
- // Insert query into defaults
209
- searchOptions.q = search;
210
- }
211
- else if (search instanceof arcgis_rest_portal_1.SearchQueryBuilder) {
212
- // Insert query into defaults
213
- searchOptions.q = search.toParam();
214
- }
215
- else { // search is ISearchOptions
216
- searchOptions = {
217
- ...searchOptions,
218
- ...search // request
219
- };
220
- }
221
- return searchOptions;
222
- }
223
- exports.convertToISearchOptions = convertToISearchOptions;
224
- /**
225
- * Simple validate function to ensure all coordinates are numbers
226
- * In some cases orgs can have null or undefined coordinate values associated with the org extent
227
- *
228
- * @param extent the extent to validate
229
- * @returns the provided extent or a default global extent if some coordinates are not numbers
230
- * @private
231
- */
232
- function _validateExtent(extent) {
233
- // in some cases orgs can have invalid extents defined
234
- // this is a simple validate function that will ensure coordiantes are numbers
235
- // using -179,-89,179,89 because the project call is returning "NaN" when using -180,-90,180,90
236
- const hasInvalid = typeof extent.xmin !== "number" ||
237
- typeof extent.xmax !== "number" ||
238
- typeof extent.ymax !== "number" ||
239
- typeof extent.ymin !== "number";
240
- if (hasInvalid) {
241
- extent.xmin = -179;
242
- extent.xmax = 179;
243
- extent.ymax = 89;
244
- extent.ymin = -89;
245
- extent.spatialReference = { wkid: 4326 };
246
- }
247
- return extent;
248
- }
249
- exports._validateExtent = _validateExtent;
250
- /**
251
- * If the request to convert the extent fails it has commonly been due to an invalid extent.
252
- * This function will first attempt to use the provided extent. If it fails it will default to
253
- * the source items extent and if that fails it will then use a default global extent.
254
- *
255
- * @param extent the extent to convert
256
- * @param fallbackExtent the extent to convert if the main extent does not project to the outSR
257
- * @param outSR the spatial reference to project to
258
- * @param geometryServiceUrl the service url for the geometry service to use
259
- * @param authentication the credentials for the requests
260
- * @returns the extent projected to the provided spatial reference
261
- * or the world extent projected to the provided spatial reference
262
- * @private
263
- */
264
- function convertExtentWithFallback(extent, fallbackExtent, outSR, geometryServiceUrl, authentication) {
265
- return new Promise((resolve, reject) => {
266
- const defaultExtent = {
267
- xmin: -179,
268
- xmax: 179,
269
- ymin: -89,
270
- ymax: 89,
271
- spatialReference: { wkid: 4326 }
272
- };
273
- convertExtent(_validateExtent(extent), outSR, geometryServiceUrl, authentication).then(extentResponse => {
274
- // in some cases project will complete successfully but return "NaN" values
275
- // check for this and call convert again if it does
276
- const extentResponseString = JSON.stringify(extentResponse);
277
- const validatedExtent = JSON.stringify(_validateExtent(extentResponse));
278
- if (extentResponseString === validatedExtent) {
279
- resolve(extentResponse);
280
- }
281
- else {
282
- convertExtent(fallbackExtent || defaultExtent, outSR, geometryServiceUrl, authentication).then(resolve, e => reject((0, generalHelpers_1.fail)(e)));
283
- }
284
- },
285
- // if convert fails try again with default global extent
286
- () => {
287
- convertExtent(defaultExtent, outSR, geometryServiceUrl, authentication).then(resolve, e => reject((0, generalHelpers_1.fail)(e)));
288
- });
289
- });
290
- }
291
- exports.convertExtentWithFallback = convertExtentWithFallback;
292
- /**
293
- * Converts an extent to a specified spatial reference.
294
- *
295
- * @param extent Extent object to check and (possibly) to project
296
- * @param outSR Desired spatial reference
297
- * @param geometryServiceUrl Path to geometry service providing `findTransformations` and `project` services
298
- * @param authentication Credentials for the request
299
- * @returns Original extent if it's already using outSR or the extents projected into the outSR
300
- */
301
- function convertExtent(extent, outSR, geometryServiceUrl, authentication) {
302
- const _requestOptions = { authentication };
303
- return new Promise((resolve, reject) => {
304
- if (extent.spatialReference.wkid === outSR?.wkid || !outSR) {
305
- resolve(extent);
306
- }
307
- else {
308
- _requestOptions.params = {
309
- f: "json",
310
- inSR: extent.spatialReference.wkid,
311
- outSR: outSR.wkid,
312
- extentOfInterest: JSON.stringify(extent)
313
- };
314
- (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(geometryServiceUrl) + "findTransformations", _requestOptions).then(response => {
315
- const transformations = response && response.transformations
316
- ? response.transformations
317
- : undefined;
318
- let transformation;
319
- if (transformations && transformations.length > 0) {
320
- // if a forward single transformation is found use that...otherwise check for and use composite
321
- transformation = transformations[0].wkid
322
- ? transformations[0].wkid
323
- : transformations[0].geoTransforms
324
- ? transformations[0]
325
- : undefined;
326
- }
327
- _requestOptions.params = {
328
- f: "json",
329
- outSR: outSR.wkid,
330
- inSR: extent.spatialReference.wkid,
331
- geometries: {
332
- geometryType: "esriGeometryPoint",
333
- geometries: [
334
- { x: extent.xmin, y: extent.ymin },
335
- { x: extent.xmax, y: extent.ymax }
336
- ]
337
- },
338
- transformation: transformation
339
- };
340
- (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(geometryServiceUrl) + "project", _requestOptions).then(projectResponse => {
341
- const projectGeom = projectResponse.geometries.length === 2
342
- ? projectResponse.geometries
343
- : undefined;
344
- if (projectGeom) {
345
- resolve({
346
- xmin: projectGeom[0].x,
347
- ymin: projectGeom[0].y,
348
- xmax: projectGeom[1].x,
349
- ymax: projectGeom[1].y,
350
- spatialReference: outSR
351
- });
352
- }
353
- else {
354
- resolve(undefined);
355
- }
356
- }, e => reject((0, generalHelpers_1.fail)(e)));
357
- }, e => reject((0, generalHelpers_1.fail)(e)));
358
- }
359
- });
360
- }
361
- exports.convertExtent = convertExtent;
362
- /**
363
- * Publishes a feature service as an AGOL item; it does not include its layers and tables
364
- *
365
- * @param newItemTemplate Template of item to be created
366
- * @param authentication Credentials for the request
367
- * @param templateDictionary Hash of facts: org URL, adlib replacements, user; .user.folders property contains a list
368
- * @returns A promise that will resolve with an object reporting success and the Solution id
369
- */
370
- function createFeatureService(newItemTemplate, authentication, templateDictionary) {
371
- return new Promise((resolve, reject) => {
372
- // Create item
373
- _getCreateServiceOptions(newItemTemplate, authentication, templateDictionary).then(createOptions => {
374
- (0, arcgis_rest_service_admin_1.createFeatureService)(createOptions).then(createResponse => {
375
- // Federated servers may have inconsistent casing, so lowerCase it
376
- createResponse.encodedServiceURL = _lowercaseDomain(createResponse.encodedServiceURL);
377
- createResponse.serviceurl = _lowercaseDomain(createResponse.serviceurl);
378
- resolve(createResponse);
379
- }, e => reject((0, generalHelpers_1.fail)(e)));
380
- }, e => reject((0, generalHelpers_1.fail)(e)));
381
- });
382
- }
383
- exports.createFeatureService = createFeatureService;
384
- /**
385
- * Publishes an item and its data, metadata, and resources as an AGOL item.
386
- *
387
- * @param itemInfo Item's `item` section
388
- * @param folderId Id of folder to receive item; null indicates that the item goes into the root
389
- * folder; ignored for Group item type
390
- * @param destinationAuthentication Credentials for for requests to where the item is to be created
391
- * @param itemThumbnailUrl URL to image to use for item thumbnail
392
- * @param itemThumbnailAuthentication Credentials for requests to the thumbnail source
393
- * @param dataFile Item's `data` section
394
- * @param metadataFile Item's metadata file
395
- * @param resourcesFiles Item's resources
396
- * @param access Access to set for item: "public", "org", "private"
397
- * @returns A promise that will resolve with an object reporting success or failure and the Solution id
398
- */
399
- function createFullItem(itemInfo, folderId, destinationAuthentication, itemThumbnailUrl, itemThumbnailAuthentication, dataFile, metadataFile, resourcesFiles, access = "private") {
400
- return new Promise((resolve, reject) => {
401
- // Create item
402
- const createOptions = {
403
- item: {
404
- ...itemInfo
405
- },
406
- folderId,
407
- authentication: destinationAuthentication
408
- };
409
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
410
- addTokenToUrl(itemThumbnailUrl, itemThumbnailAuthentication).then(updatedThumbnailUrl => {
411
- /* istanbul ignore else */
412
- if (updatedThumbnailUrl) {
413
- createOptions.item.thumbnailUrl = (0, generalHelpers_1.appendQueryParam)(updatedThumbnailUrl, "w=400");
414
- }
415
- (0, arcgis_rest_portal_1.createItemInFolder)(createOptions).then(createResponse => {
416
- if (createResponse.success) {
417
- let accessDef;
418
- // Set access if it is not AGOL default
419
- // Set the access manually since the access value in createItem appears to be ignored
420
- // Need to run serially; will not work reliably if done in parallel with adding the data section
421
- if (access !== "private") {
422
- const accessOptions = {
423
- id: createResponse.id,
424
- access: access === "public" ? "public" : "org",
425
- authentication: destinationAuthentication
426
- };
427
- accessDef = (0, arcgis_rest_portal_1.setItemAccess)(accessOptions);
428
- }
429
- else {
430
- accessDef = Promise.resolve({
431
- itemId: createResponse.id
432
- });
433
- }
434
- // Now add attached items
435
- accessDef.then(() => {
436
- const updateDefs = [];
437
- // Add the data section
438
- if (dataFile) {
439
- updateDefs.push(_addItemDataFile(createResponse.id, dataFile, destinationAuthentication));
440
- }
441
- // Add the resources via a zip because AGO sometimes loses resources if many are added at the
442
- // same time to the same item
443
- if (Array.isArray(resourcesFiles) &&
444
- resourcesFiles.length > 0) {
445
- updateDefs.push(new Promise((rsrcResolve, rsrcReject) => {
446
- (0, libConnectors_1.createZip)("resources.zip", resourcesFiles).then((zipfile) => {
447
- const addResourceOptions = {
448
- id: createResponse.id,
449
- resource: zipfile,
450
- authentication: destinationAuthentication,
451
- params: {
452
- archive: true
453
- }
454
- };
455
- (0, arcgis_rest_portal_1.addItemResource)(addResourceOptions).then(rsrcResolve, rsrcReject);
456
- }, rsrcReject);
457
- }));
458
- }
459
- // Add the metadata section
460
- if (metadataFile) {
461
- updateDefs.push(_addItemMetadataFile(createResponse.id, metadataFile, destinationAuthentication));
462
- }
463
- // Wait until all adds are done
464
- Promise.all(updateDefs).then(() => resolve(createResponse), e => reject((0, generalHelpers_1.fail)(e)));
465
- }, e => reject((0, generalHelpers_1.fail)(e)));
466
- }
467
- else {
468
- reject((0, generalHelpers_1.fail)());
469
- }
470
- }, e => reject((0, generalHelpers_1.fail)(e)));
471
- });
472
- });
473
- }
474
- exports.createFullItem = createFullItem;
475
- /**
476
- * Publishes an item and its data as an AGOL item.
477
- *
478
- * @param itemInfo Item's `item` section
479
- * @param dataInfo Item's `data` section
480
- * @param authentication Credentials for the request
481
- * @param folderId Id of folder to receive item; null indicates that the item goes into the root
482
- * folder; ignored for Group item type
483
- * @param access Access to set for item: "public", "org", "private"
484
- * @returns A promise that will resolve with an object reporting success and the Solution id
485
- */
486
- function createItemWithData(itemInfo, dataInfo, authentication, folderId, access = "private") {
487
- return new Promise((resolve, reject) => {
488
- // Create item
489
- const createOptions = {
490
- item: {
491
- title: "_",
492
- ...itemInfo,
493
- data: dataInfo
494
- },
495
- folderId,
496
- authentication: authentication
497
- };
498
- if (itemInfo.thumbnail) {
499
- createOptions.params = {
500
- // Pass thumbnail file in via params because item property is serialized, which discards a blob
501
- thumbnail: itemInfo.thumbnail
502
- };
503
- delete createOptions.item.thumbnail;
504
- }
505
- (0, arcgis_rest_portal_1.createItemInFolder)(createOptions).then(createResponse => {
506
- if (createResponse.success) {
507
- if (access !== "private") {
508
- // Set access if it is not AGOL default
509
- // Set the access manually since the access value in createItem appears to be ignored
510
- const accessOptions = {
511
- id: createResponse.id,
512
- access: access === "public" ? "public" : "org",
513
- authentication: authentication
514
- };
515
- (0, arcgis_rest_portal_1.setItemAccess)(accessOptions).then(() => {
516
- resolve({
517
- folder: createResponse.folder,
518
- id: createResponse.id,
519
- success: true
520
- });
521
- }, e => reject((0, generalHelpers_1.fail)(e)));
522
- }
523
- else {
524
- resolve({
525
- folder: createResponse.folder,
526
- id: createResponse.id,
527
- success: true
528
- });
529
- }
530
- }
531
- else {
532
- reject((0, generalHelpers_1.fail)());
533
- }
534
- }, e => reject((0, generalHelpers_1.fail)(e)));
535
- });
536
- }
537
- exports.createItemWithData = createItemWithData;
538
- /**
539
- * Creates a folder using a numeric suffix to ensure uniqueness if necessary.
540
- *
541
- * @param title Folder title, used as-is if possible and with suffix otherwise
542
- * @param templateDictionary Hash of facts: org URL, adlib replacements, user; .user.folders property contains a list
543
- * of known folder names; function updates list with existing names not yet known, and creates .user.folders if it
544
- * doesn't exist in the dictionary
545
- * @param authentication Credentials for creating folder
546
- * @returns Id of created folder
547
- */
548
- function createUniqueFolder(title, templateDictionary, authentication) {
549
- return new Promise((resolve, reject) => {
550
- // Get a title that is not already in use
551
- const folderTitle = (0, generalHelpers_1.getUniqueTitle)(title, templateDictionary, "user.folders");
552
- const folderCreationParam = {
553
- title: folderTitle,
554
- authentication: authentication
555
- };
556
- (0, arcgis_rest_portal_1.createFolder)(folderCreationParam).then(ok => resolve(ok), err => {
557
- // If the name already exists, we'll try again
558
- const errorDetails = (0, generalHelpers_1.getProp)(err, "response.error.details");
559
- if (Array.isArray(errorDetails) && errorDetails.length > 0) {
560
- const nameNotAvailMsg = "Folder title '" + folderTitle + "' not available.";
561
- if (errorDetails.indexOf(nameNotAvailMsg) >= 0) {
562
- // Create the user.folders property if it doesn't exist
563
- /* istanbul ignore else */
564
- if (!(0, generalHelpers_1.getProp)(templateDictionary, "user.folders")) {
565
- (0, generalHelpers_1.setCreateProp)(templateDictionary, "user.folders", []);
566
- }
567
- templateDictionary.user.folders.push({
568
- title: folderTitle
569
- });
570
- createUniqueFolder(title, templateDictionary, authentication).then(resolve, reject);
571
- }
572
- else {
573
- reject(err);
574
- }
575
- }
576
- else {
577
- // Otherwise, error out
578
- reject(err);
579
- }
580
- });
581
- });
582
- }
583
- exports.createUniqueFolder = createUniqueFolder;
584
- /**
585
- * Creates a group using numeric suffix to ensure uniqueness.
586
- *
587
- * @param title Group title, used as-is if possible and with suffix otherwise
588
- * @param templateDictionary Hash of facts: org URL, adlib replacements, user
589
- * @param authentication Credentials for creating group
590
- * @param owner Optional arg for the Tracking owner
591
- * If the tracking owner is not the one deploying the solution
592
- * tracker groups will be created under the deployment user but
593
- * will be reassigned to the tracking owner.
594
- * @returns Information about created group
595
- */
596
- function createUniqueGroup(title, groupItem, templateDictionary, authentication, owner) {
597
- return new Promise((resolve, reject) => {
598
- let groupsPromise;
599
- // when working with tracker we need to consider the groups of the deploying user as well as the groups
600
- // of the tracking user...must be unique for both
601
- if (owner && owner !== authentication.username) {
602
- groupsPromise = searchAllGroups(`(owner:${owner}) orgid:${templateDictionary.organization.id}`, authentication);
603
- }
604
- else {
605
- groupsPromise = Promise.resolve([]);
606
- }
607
- // first get the tracker owner groups
608
- groupsPromise.then(groups => {
609
- templateDictionary["allGroups"] =
610
- groups.concat((0, generalHelpers_1.getProp)(templateDictionary, "user.groups"));
611
- // Get a title that is not already in use
612
- groupItem.title = (0, generalHelpers_1.getUniqueTitle)(title, templateDictionary, "allGroups");
613
- const groupCreationParam = {
614
- group: groupItem,
615
- authentication: authentication
616
- };
617
- (0, arcgis_rest_portal_1.createGroup)(groupCreationParam).then(resolve, err => {
618
- // If the name already exists, we'll try again
619
- const errorDetails = (0, generalHelpers_1.getProp)(err, "response.error.details");
620
- if (Array.isArray(errorDetails) && errorDetails.length > 0) {
621
- const nameNotAvailMsg = "You already have a group named '" +
622
- groupItem.title +
623
- "'. Try a different name.";
624
- if (errorDetails.indexOf(nameNotAvailMsg) >= 0) {
625
- templateDictionary.user.groups.push({
626
- title: groupItem.title
627
- });
628
- createUniqueGroup(title, groupItem, templateDictionary, authentication).then(resolve, reject);
629
- }
630
- else {
631
- reject(err);
632
- }
633
- }
634
- else {
635
- // Otherwise, error out
636
- reject(err);
637
- }
638
- });
639
- }, e => reject(e));
640
- });
641
- }
642
- exports.createUniqueGroup = createUniqueGroup;
643
- /**
644
- * Gets the ids of the dependencies of an AGOL feature service item.
645
- * Dependencies will only exist when the service is a view.
646
- *
647
- * @param itemTemplate Template of item to be created
648
- * @param authentication Credentials for the request
649
- * @returns A promise that will resolve a list of dependencies
650
- */
651
- function extractDependencies(itemTemplate, authentication) {
652
- const dependencies = [];
653
- return new Promise((resolve, reject) => {
654
- // Get service dependencies when the item is a view
655
- // This step is skipped for tracker views as they will already have a source service in the org
656
- if (itemTemplate.properties.service.isView && itemTemplate.item.url && !(0, trackingHelpers_1.isTrackingViewTemplate)(itemTemplate)) {
657
- (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(itemTemplate.item.url) + "sources?f=json", {
658
- authentication: authentication
659
- }).then(response => {
660
- /* istanbul ignore else */
661
- if (response && response.services) {
662
- response.services.forEach((layer) => {
663
- dependencies.push({
664
- id: layer.serviceItemId,
665
- name: layer.name
666
- });
667
- });
668
- }
669
- resolve(dependencies);
670
- }, e => reject((0, generalHelpers_1.fail)(e)));
671
- }
672
- else if ((0, workforceHelpers_1.isWorkforceProject)(itemTemplate)) {
673
- resolve((0, workforceHelpers_1.getWorkforceDependencies)(itemTemplate, dependencies));
674
- }
675
- else {
676
- resolve(dependencies);
677
- }
678
- });
679
- }
680
- exports.extractDependencies = extractDependencies;
681
- /**
682
- * Get json info for the services layers
683
- *
684
- * @param serviceUrl the url for the service
685
- * @param layerList list of base layer info
686
- * @param authentication Credentials for the request
687
- * @returns A promise that will resolve a list of dependencies
688
- */
689
- function getLayers(serviceUrl, layerList, authentication) {
690
- return new Promise((resolve, reject) => {
691
- if (layerList.length === 0) {
692
- resolve([]);
693
- }
694
- // get the admin URL
695
- serviceUrl = serviceUrl.replace("/rest/services", "/rest/admin/services");
696
- const requestsDfd = [];
697
- layerList.forEach(layer => {
698
- const requestOptions = {
699
- authentication: authentication
700
- };
701
- requestsDfd.push((0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(serviceUrl) + layer["id"] + "?f=json", requestOptions));
702
- });
703
- // Wait until all layers are heard from
704
- Promise.all(requestsDfd).then(layers => resolve(layers), e => reject((0, generalHelpers_1.fail)(e)));
705
- });
706
- }
707
- exports.getLayers = getLayers;
708
- /**
709
- * Add additional options to a layers definition.
710
- *
711
- * @param args The IPostProcessArgs for the request(s)
712
- * @param isPortal boolean to indicate if we are deploying to portal
713
- *
714
- * @returns An array of update instructions
715
- * @private
716
- */
717
- function getLayerUpdates(args, isPortal) {
718
- const adminUrl = args.itemTemplate.item.url.replace("rest/services", "rest/admin/services");
719
- const updates = [];
720
- const refresh = _getUpdate(adminUrl, null, null, args, "refresh");
721
- updates.push(refresh);
722
- Object.keys(args.objects).forEach(id => {
723
- const obj = Object.assign({}, args.objects[id]);
724
- // These properties cannot be set in the update definition when working with portal
725
- if (isPortal) {
726
- (0, generalHelpers_1.deleteProps)(obj, ["type", "id", "relationships", "sourceServiceFields"]);
727
- }
728
- // handle definition deletes
729
- // removes previous editFieldsInfo fields if their names were changed
730
- if (obj.hasOwnProperty("deleteFields")) {
731
- updates.push(_getUpdate(adminUrl, id, obj, args, "delete"));
732
- (0, generalHelpers_1.deleteProp)(obj, "deleteFields");
733
- updates.push(_getUpdate(adminUrl, null, null, args, "refresh"));
734
- }
735
- });
736
- // issue: #706
737
- // Add source service relationships
738
- // views will now always add all layers in a single call and will inherit the relationships from the source service
739
- if (!args.itemTemplate.properties.service.isView) {
740
- const relUpdates = _getRelationshipUpdates({
741
- message: "updated layer relationships",
742
- objects: args.objects,
743
- itemTemplate: args.itemTemplate,
744
- authentication: args.authentication
745
- });
746
- // issue: #724
747
- // In portal the order the relationships are added needs to follow the layer order
748
- // otherwise the relationship IDs will be reset
749
- relUpdates.layers = _sortRelationships(args.itemTemplate.properties.layers, args.itemTemplate.properties.tables, relUpdates);
750
- /* istanbul ignore else */
751
- if (relUpdates.layers.length > 0) {
752
- updates.push(_getUpdate(adminUrl, null, relUpdates, args, "add"));
753
- updates.push(refresh);
754
- }
755
- // handle contingent values
756
- const contingentValuesUpdates = _getContingentValuesUpdates({
757
- message: "add layer contingent values",
758
- objects: args.objects,
759
- itemTemplate: args.itemTemplate,
760
- authentication: args.authentication
761
- });
762
- /* istanbul ignore else */
763
- if (contingentValuesUpdates.length > 0) {
764
- contingentValuesUpdates.forEach(conUpdate => {
765
- updates.push(_getUpdate(adminUrl + conUpdate.id, null, conUpdate.contingentValues, args, "add"));
766
- });
767
- }
768
- }
769
- return updates.length === 1 ? [] : updates;
770
- }
771
- exports.getLayerUpdates = getLayerUpdates;
772
- /**
773
- * Sorts relationships based on order of supporting layers and tables in the service definition
774
- *
775
- * @param layers the layers from the service
776
- * @param tables the tables from the service
777
- * @param relUpdates the relationships to add for the service
778
- *
779
- * @returns An array with relationships that have been sorted
780
- * @private
781
- */
782
- function _sortRelationships(layers, tables, relUpdates) {
783
- const ids = [].concat(layers.map((l) => l.id), tables.map((t) => t.id));
784
- // In portal the order the relationships are added needs to follow the layer order
785
- // otherwise the relationship IDs will be reset
786
- const _relUpdateLayers = [];
787
- ids.forEach(id => {
788
- relUpdates.layers.some((relUpdate) => {
789
- if (id === relUpdate.id) {
790
- _relUpdateLayers.push(relUpdate);
791
- return true;
792
- }
793
- else {
794
- return false;
795
- }
796
- });
797
- });
798
- return _relUpdateLayers;
799
- }
800
- exports._sortRelationships = _sortRelationships;
801
- /**
802
- * Add additional options to a layers definition
803
- *
804
- * Added retry due to some solutions failing to deploy in specific orgs/hives
805
- *
806
- *
807
- * @param Update will contain either add, update, or delete from service definition call
808
- * @param skipRetry defaults to false. when true the retry logic will be ignored
809
- * @returns A promise that will resolve when service definition call has completed
810
- * @private
811
- */
812
- /* istanbul ignore else */
813
- function getRequest(update, skipRetry = false, useAsync = false) {
814
- return new Promise((resolve, reject) => {
815
- const options = {
816
- params: update.params,
817
- authentication: update.args.authentication
818
- };
819
- /* istanbul ignore else */
820
- if ((useAsync && update.url.indexOf("addToDefinition") > -1) ||
821
- update.url.indexOf("updateDefinition") > -1 ||
822
- update.url.indexOf("deleteFromDefinition") > -1) {
823
- options.params = { ...options.params, async: true };
824
- }
825
- (0, arcgis_rest_request_1.request)(update.url, options).then(result => {
826
- checkRequestStatus(result, options.authentication).then(() => resolve(null), e => reject((0, generalHelpers_1.fail)(e)));
827
- }, (e) => {
828
- if (!skipRetry) {
829
- getRequest(update, true, true).then(() => resolve(), e => reject(e));
830
- }
831
- else {
832
- reject(e);
833
- }
834
- });
835
- });
836
- }
837
- exports.getRequest = getRequest;
838
- /**
839
- * Fills in missing data, including full layer and table definitions, in a feature services' definition.
840
- *
841
- * @param itemTemplate Feature service item, data, dependencies definition to be modified
842
- * @param authentication Credentials for the request to AGOL
843
- * @returns A promise that will resolve when fullItem has been updated
844
- * @private
845
- */
846
- function getServiceLayersAndTables(itemTemplate, authentication) {
847
- return new Promise((resolve, reject) => {
848
- // To have enough information for reconstructing the service, we'll supplement
849
- // the item and data sections with sections for the service, full layers, and
850
- // full tables
851
- // Extra steps must be taken for workforce version 2
852
- const isWorkforceService = (0, workforceHelpers_1.isWorkforceProject)(itemTemplate);
853
- // Get the service description
854
- if (itemTemplate.item.url) {
855
- getFeatureServiceProperties(itemTemplate.item.url, authentication, isWorkforceService).then(properties => {
856
- itemTemplate.properties = properties;
857
- resolve(itemTemplate);
858
- }, e => reject((0, generalHelpers_1.fail)(e)));
859
- }
860
- else {
861
- resolve(itemTemplate);
862
- }
863
- });
864
- }
865
- exports.getServiceLayersAndTables = getServiceLayersAndTables;
866
- /**
867
- * Get service properties for the given url and update key props
868
- *
869
- * @param serviceUrl the feature service url
870
- * @param authentication Credentials for the request to AGOL
871
- * @param workforceService boolean to indicate if extra workforce service steps should be handled
872
- * @returns A promise that will resolve with the service properties
873
- * @private
874
- */
875
- function getFeatureServiceProperties(serviceUrl, authentication, workforceService = false) {
876
- return new Promise((resolve, reject) => {
877
- const properties = {
878
- service: {},
879
- layers: [],
880
- tables: []
881
- };
882
- // get the admin URL
883
- serviceUrl = serviceUrl.replace("/rest/services", "/rest/admin/services");
884
- // Get the service description
885
- (0, arcgis_rest_request_1.request)(serviceUrl + "?f=json", {
886
- authentication: authentication
887
- }).then(serviceData => {
888
- properties.service = _parseAdminServiceData(serviceData);
889
- // Copy cacheMaxAge to top level so that AGO sees it when deploying the service
890
- // serviceData may have set it if there isn't an adminServiceInfo
891
- /* istanbul ignore else */
892
- if (serviceData.adminServiceInfo?.cacheMaxAge) {
893
- properties.service.cacheMaxAge =
894
- serviceData.adminServiceInfo.cacheMaxAge;
895
- }
896
- // Move the layers and tables out of the service's data section
897
- /* istanbul ignore else */
898
- if (serviceData.layers) {
899
- properties.layers = serviceData.layers;
900
- // Fill in properties that the service layer doesn't provide
901
- // and remove properties that should not exist in the template
902
- properties.layers.forEach(layer => {
903
- layer.serviceItemId = properties.service.serviceItemId;
904
- layer.extent = null;
905
- (0, featureServiceHelpers_1.removeLayerOptimization)(layer);
906
- });
907
- }
908
- delete serviceData.layers;
909
- /* istanbul ignore else */
910
- if (serviceData.tables) {
911
- properties.tables = serviceData.tables;
912
- // Fill in properties that the service layer doesn't provide
913
- properties.tables.forEach(table => {
914
- table.serviceItemId = properties.service.serviceItemId;
915
- table.extent = null;
916
- });
917
- }
918
- delete serviceData.tables;
919
- // Ensure solution items have unique indexes on relationship key fields
920
- _updateIndexesForRelationshipKeyFields(properties);
921
- (0, featureServiceHelpers_1.processContingentValues)(properties, serviceUrl, authentication).then(() => {
922
- if (workforceService) {
923
- (0, workforceHelpers_1.getWorkforceServiceInfo)(properties, serviceUrl, authentication).then(resolve, reject);
924
- }
925
- else {
926
- resolve(properties);
927
- }
928
- }, (e) => reject((0, generalHelpers_1.fail)(e)));
929
- }, (e) => reject((0, generalHelpers_1.fail)(e)));
930
- });
931
- }
932
- exports.getFeatureServiceProperties = getFeatureServiceProperties;
933
- /**
934
- * Parses the layers array and will filter subsets of Layers and Tables
935
- * Layers and Tables are both returned in the layers array when we access a feature service from the admin api.
936
- *
937
- * @param adminData The data of the feature service
938
- * @returns A mutated version of the provided adminData
939
- * @private
940
- */
941
- function _parseAdminServiceData(adminData) {
942
- const layers = adminData.layers || [];
943
- const tables = adminData.tables || [];
944
- (0, generalHelpers_1.setCreateProp)(adminData, "layers", layers.filter(l => l.type === "Feature Layer"));
945
- // TODO understand if the concat is necessary.
946
- // Not sure if the admin api will ever actually return a tables collection here.
947
- (0, generalHelpers_1.setCreateProp)(adminData, "tables", tables.concat(layers.filter(l => l.type === "Table")));
948
- return adminData;
949
- }
950
- exports._parseAdminServiceData = _parseAdminServiceData;
951
- /**
952
- * livingatlas designation test.
953
- * These layers should not be templatized or depolyed
954
- *
955
- * @param groupDesignations the items group designations to evaluate
956
- * @returns A boolean indicating if the invalid designation is found in the item info
957
- */
958
- function hasInvalidGroupDesignations(groupDesignations) {
959
- const invalidGroupDesignations = ["livingatlas"];
960
- return groupDesignations
961
- ? invalidGroupDesignations.indexOf(groupDesignations) > -1
962
- : false;
963
- }
964
- exports.hasInvalidGroupDesignations = hasInvalidGroupDesignations;
965
- /**
966
- * Removes a folder from AGO.
967
- *
968
- * @param folderId Id of a folder to delete
969
- * @param authentication Credentials for the request to AGO
970
- * @returns A promise that will resolve with the result of the request
971
- */
972
- function removeFolder(folderId, authentication) {
973
- return new Promise((resolve, reject) => {
974
- const requestOptions = {
975
- folderId: folderId,
976
- authentication: authentication
977
- };
978
- (0, arcgis_rest_portal_1.removeFolder)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
979
- });
980
- }
981
- exports.removeFolder = removeFolder;
982
- /**
983
- * Removes a group from AGO.
984
- *
985
- * @param groupId Id of a group to delete
986
- * @param authentication Credentials for the request to AGO
987
- * @returns A promise that will resolve with the result of the request
988
- */
989
- function removeGroup(groupId, authentication) {
990
- return new Promise((resolve, reject) => {
991
- const requestOptions = {
992
- id: groupId,
993
- authentication: authentication
994
- };
995
- (0, arcgis_rest_portal_1.removeGroup)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
996
- });
997
- }
998
- exports.removeGroup = removeGroup;
999
- /**
1000
- * Removes an item from AGO.
1001
- *
1002
- * @param itemId Id of an item to delete
1003
- * @param authentication Credentials for the request to AGO
1004
- * @returns A promise that will resolve with the result of the request
1005
- */
1006
- function removeItem(itemId, authentication) {
1007
- return new Promise((resolve, reject) => {
1008
- const requestOptions = {
1009
- id: itemId,
1010
- authentication: authentication
1011
- };
1012
- (0, arcgis_rest_portal_1.removeItem)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
1013
- });
1014
- }
1015
- exports.removeItem = removeItem;
1016
- /**
1017
- * Removes an item or group from AGO.
1018
- *
1019
- * @param itemId Id of an item or group to delete
1020
- * @param authentication Credentials for the request to AGO
1021
- * @returns A promise that will resolve with the result of the request
1022
- */
1023
- function removeItemOrGroup(itemId, authentication) {
1024
- return new Promise((resolve, reject) => {
1025
- removeItem(itemId, authentication).then(resolve, error => {
1026
- removeGroup(itemId, authentication).then(resolve, () => reject(error));
1027
- });
1028
- });
1029
- }
1030
- exports.removeItemOrGroup = removeItemOrGroup;
1031
- /**
1032
- * Searches for items matching a query and that the caller has access to.
1033
- *
1034
- * @param search Search string (e.g., "q=redlands+map") or a more detailed structure that can include authentication
1035
- * @returns Promise resolving with search results
1036
- * @see https://developers.arcgis.com/rest/users-groups-and-items/search.htm
1037
- */
1038
- function searchItems(search) {
1039
- return (0, arcgis_rest_portal_1.searchItems)(search);
1040
- }
1041
- exports.searchItems = searchItems;
1042
- /**
1043
- * Searches for items matching a query and that the caller has access to, continuing recursively until done.
1044
- *
1045
- * @param search Search string (e.g., "q=redlands+map") or a more detailed structure that can include authentication
1046
- * @param accumulatedResponse Response built from previous requests
1047
- * @returns Promise resolving with search results
1048
- * @see https://developers.arcgis.com/rest/users-groups-and-items/search.htm
1049
- */
1050
- function searchAllItems(search, accumulatedResponse) {
1051
- // Convert the search into an ISearchOptions
1052
- const searchOptions = convertToISearchOptions(search);
1053
- // Provide a base into which results can be concatenated
1054
- const completeResponse = accumulatedResponse ? accumulatedResponse : {
1055
- query: searchOptions.q,
1056
- start: 1,
1057
- num: 100,
1058
- nextStart: -1,
1059
- total: 0,
1060
- results: []
1061
- };
1062
- return new Promise((resolve, reject) => {
1063
- searchItems(search).then(response => {
1064
- completeResponse.results = completeResponse.results.concat(response.results);
1065
- completeResponse.num = completeResponse.total = completeResponse.results.length;
1066
- if (response.nextStart > 0) {
1067
- // Insert nextStart into next query
1068
- searchOptions.start = response.nextStart;
1069
- resolve(searchAllItems(searchOptions, completeResponse));
1070
- }
1071
- else {
1072
- resolve(completeResponse);
1073
- }
1074
- }, e => reject(e));
1075
- });
1076
- }
1077
- exports.searchAllItems = searchAllItems;
1078
- /**
1079
- * Searches for groups matching criteria.
1080
- *
1081
- * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1082
- * @param authentication Credentials for the request to AGO
1083
- * @param additionalSearchOptions Adjustments to search, such as tranche size
1084
- * @returns A promise that will resolve with a structure with a tranche of results and
1085
- * describing how many items are available
1086
- * @see https://developers.arcgis.com/rest/users-groups-and-items/group-search.htm
1087
- * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1088
- */
1089
- function searchGroups(searchString, authentication, additionalSearchOptions) {
1090
- const searchOptions = {
1091
- q: searchString,
1092
- params: {
1093
- ...additionalSearchOptions
1094
- },
1095
- authentication: authentication
1096
- };
1097
- return (0, arcgis_rest_portal_1.searchGroups)(searchOptions);
1098
- }
1099
- exports.searchGroups = searchGroups;
1100
- /**
1101
- * Searches for groups matching criteria recurusively.
1102
- *
1103
- * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1104
- * @param authentication Credentials for the request to AGO
1105
- * @param groups List of groups that have been found from previous requests
1106
- * @param inPagingParams The paging params for the recurisve searching
1107
- *
1108
- * @returns A promise that will resolve with all groups that meet the search criteria
1109
- */
1110
- function searchAllGroups(searchString, authentication, groups, inPagingParams) {
1111
- const pagingParams = inPagingParams ? inPagingParams : {
1112
- start: 1,
1113
- num: 24
1114
- };
1115
- const additionalSearchOptions = {
1116
- sortField: "title",
1117
- sortOrder: "asc",
1118
- ...pagingParams
1119
- };
1120
- // Provide a base onto which results can be concatenated
1121
- let finalResults = groups ? groups : [];
1122
- return new Promise((resolve, reject) => {
1123
- searchGroups(searchString, authentication, additionalSearchOptions).then(response => {
1124
- finalResults = finalResults.concat(response.results);
1125
- if (response.nextStart > 0) {
1126
- pagingParams.start = response.nextStart;
1127
- resolve(searchAllGroups(searchString, authentication, finalResults, pagingParams));
1128
- }
1129
- else {
1130
- resolve(finalResults);
1131
- }
1132
- }, e => reject(e));
1133
- });
1134
- }
1135
- exports.searchAllGroups = searchAllGroups;
1136
- /**
1137
- * Searches for group contents matching criteria recursively.
1138
- *
1139
- * @param groupId Group whose contents are to be searched
1140
- * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1141
- * @param authentication Credentials for the request to AGO
1142
- * @param additionalSearchOptions Adjustments to search, such as tranche size and categories of interest; categories
1143
- * are supplied as an array: each array element consists of one or more categories to be ORed; array elements are ANDed
1144
- * @param portalUrl Rest Url of the portal to perform the search
1145
- * @param accumulatedResponse Response built from previous requests
1146
- * @returns A promise that will resolve with a structure with a tranche of results and
1147
- * describing how many items are available
1148
- * @see https://developers.arcgis.com/rest/users-groups-and-items/group-content-search.htm
1149
- * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1150
- */
1151
- function searchGroupAllContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl, accumulatedResponse) {
1152
- additionalSearchOptions = additionalSearchOptions ? additionalSearchOptions : {};
1153
- // Provide a base into which results can be concatenated
1154
- const completeResponse = accumulatedResponse ? accumulatedResponse : {
1155
- query: searchString,
1156
- start: 1,
1157
- num: 100,
1158
- nextStart: -1,
1159
- total: 0,
1160
- results: []
1161
- };
1162
- return new Promise((resolve, reject) => {
1163
- searchGroupContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl).then(response => {
1164
- completeResponse.results = completeResponse.results.concat(response.results);
1165
- completeResponse.num = completeResponse.total = completeResponse.results.length;
1166
- if (response.nextStart > 0) {
1167
- additionalSearchOptions.start = response.nextStart;
1168
- resolve(searchGroupAllContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl, completeResponse));
1169
- }
1170
- else {
1171
- resolve(completeResponse);
1172
- }
1173
- }, e => reject(e));
1174
- });
1175
- }
1176
- exports.searchGroupAllContents = searchGroupAllContents;
1177
- /**
1178
- * Searches for group contents matching criteria.
1179
- *
1180
- * @param groupId Group whose contents are to be searched
1181
- * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1182
- * @param authentication Credentials for the request to AGO
1183
- * @param additionalSearchOptions Adjustments to search, such as tranche size and categories of interest; categories
1184
- * are supplied as an array: each array element consists of one or more categories to be ORed; array elements are ANDed
1185
- * @param portalUrl Rest Url of the portal to perform the search
1186
- * @returns A promise that will resolve with a structure with a tranche of results and
1187
- * describing how many items are available
1188
- * @see https://developers.arcgis.com/rest/users-groups-and-items/group-content-search.htm
1189
- * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1190
- */
1191
- function searchGroupContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl) {
1192
- const searchOptions = {
1193
- groupId,
1194
- q: searchString,
1195
- params: Object.assign({
1196
- num: 100
1197
- }, additionalSearchOptions),
1198
- authentication: authentication,
1199
- portal: portalUrl
1200
- };
1201
- // If search options include `categories`, switch to new arcgis-rest-js format
1202
- /* istanbul ignore else */
1203
- if (Array.isArray(searchOptions.params.categories)) {
1204
- searchOptions.params.categories = searchOptions.params.categories.map(andGroup => andGroup.split(","));
1205
- }
1206
- return (0, arcgis_rest_portal_1.searchGroupContent)(searchOptions);
1207
- }
1208
- exports.searchGroupContents = searchGroupContents;
1209
- /**
1210
- * Reassign ownership of a group
1211
- *
1212
- * @param groupId Group to remove users from
1213
- * @param userName The new owner for the group
1214
- * @param authentication Credentials for the request to
1215
- *
1216
- * @returns A promise that will resolve after the group ownership has been assigned
1217
- *
1218
- */
1219
- function reassignGroup(groupId, userName, authentication) {
1220
- const requestOptions = {
1221
- authentication: authentication,
1222
- params: {
1223
- targetUsername: userName
1224
- }
1225
- };
1226
- return (0, arcgis_rest_request_1.request)(`${authentication.portal}/community/groups/${groupId}/reassign`, requestOptions);
1227
- }
1228
- exports.reassignGroup = reassignGroup;
1229
- /**
1230
- * Remove users from a group
1231
- *
1232
- * @param groupId Group to remove users from
1233
- * @param users List of users to remove from the group
1234
- * @param authentication Credentials for the request to
1235
- *
1236
- * @returns A promise that will resolve after the users have been removed
1237
- *
1238
- */
1239
- function removeUsers(groupId, users, authentication) {
1240
- return (0, arcgis_rest_portal_1.removeGroupUsers)({
1241
- id: groupId,
1242
- users,
1243
- authentication
1244
- });
1245
- }
1246
- exports.removeUsers = removeUsers;
1247
- /**
1248
- * Shares an item to the defined group
1249
- *
1250
- * @param groupId Group to share with
1251
- * @param id the item id to share with the group
1252
- * @param destinationAuthentication Credentials for the request to AGO
1253
- * @param owner owner of the group when sharing tracking items (can be different from the deploying user)
1254
- *
1255
- * @returns A promise that will resolve after the item has been shared
1256
- *
1257
- */
1258
- function shareItem(groupId, id, destinationAuthentication, owner) {
1259
- return new Promise((resolve, reject) => {
1260
- const shareOptions = {
1261
- groupId,
1262
- id,
1263
- authentication: destinationAuthentication
1264
- };
1265
- /* istanbul ignore else */
1266
- if (owner) {
1267
- shareOptions.owner = owner;
1268
- }
1269
- (0, arcgis_rest_portal_1.shareItemWithGroup)(shareOptions).then(() => resolve(null), (e) => reject((0, generalHelpers_1.fail)(e)));
1270
- });
1271
- }
1272
- exports.shareItem = shareItem;
1273
- /**
1274
- * Updates an item.
1275
- *
1276
- * @param itemInfo The base info of an item; note that this content will be serialized, which doesn't work
1277
- * for binary content
1278
- * @param authentication Credentials for request
1279
- * @param folderId Item's folder
1280
- * @param additionalParams Updates that are put under the `params` property, which is not serialized
1281
- * @return
1282
- */
1283
- function updateItem(itemInfo, authentication, folderId, additionalParams) {
1284
- return new Promise((resolve, reject) => {
1285
- const updateOptions = {
1286
- item: itemInfo,
1287
- folderId: folderId,
1288
- authentication: authentication,
1289
- params: {
1290
- ...(additionalParams ?? {})
1291
- }
1292
- };
1293
- (0, arcgis_rest_portal_1.updateItem)(updateOptions).then(response => (response.success ? resolve(response) : reject(response)), err => reject(err));
1294
- });
1295
- }
1296
- exports.updateItem = updateItem;
1297
- /**
1298
- * Updates a group.
1299
- *
1300
- * @param groupInfo The base info of a group; note that this content will be serialized, which doesn't work
1301
- * for binary content
1302
- * @param authentication Credentials for request
1303
- * @param additionalParams Updates that are put under the `params` property, which is not serialized
1304
- * @returns A Promise that will resolve with the success/failure status of the request
1305
- */
1306
- function updateGroup(groupInfo, authentication, additionalParams) {
1307
- return new Promise((resolve, reject) => {
1308
- const updateOptions = {
1309
- group: groupInfo,
1310
- authentication,
1311
- params: {
1312
- ...(additionalParams ?? {})
1313
- }
1314
- };
1315
- (0, arcgis_rest_portal_1.updateGroup)(updateOptions).then(response => (response.success ? resolve(response) : reject(response)), err => reject(err));
1316
- });
1317
- }
1318
- exports.updateGroup = updateGroup;
1319
- /**
1320
- * Updates an item.
1321
- *
1322
- * @param itemInfo The base info of an item
1323
- * @param data The items data section
1324
- * @param authentication Credentials for requests
1325
- * @param thumbnail optional thumbnail to update
1326
- * @param access "public" or "org"
1327
- * @return
1328
- */
1329
- function updateItemExtended(itemInfo, data, authentication, thumbnail, access, templateDictionary) {
1330
- return new Promise((resolve, reject) => {
1331
- const updateOptions = {
1332
- item: itemInfo,
1333
- params: {
1334
- text: data || {} // AGO ignores update if `data` is empty
1335
- },
1336
- authentication: authentication
1337
- };
1338
- if (thumbnail) {
1339
- updateOptions.params.thumbnail = thumbnail;
1340
- }
1341
- if ((0, trackingHelpers_1.isTrackingViewTemplate)(undefined, itemInfo) && templateDictionary) {
1342
- updateOptions.owner = templateDictionary.locationTracking.owner;
1343
- }
1344
- (0, arcgis_rest_portal_1.updateItem)(updateOptions).then(result => {
1345
- if (access && access !== "private") {
1346
- // Set access if it is not AGOL default
1347
- // Set the access manually since the access value in createItem appears to be ignored
1348
- const accessOptions = {
1349
- id: itemInfo.id,
1350
- access: access === "public" ? "public" : "org",
1351
- authentication: authentication
1352
- };
1353
- (0, arcgis_rest_portal_1.setItemAccess)(accessOptions).then(() => resolve(result), e => reject((0, generalHelpers_1.fail)(e)));
1354
- }
1355
- else {
1356
- resolve(result);
1357
- }
1358
- }, e => reject((0, generalHelpers_1.fail)(e)));
1359
- });
1360
- }
1361
- exports.updateItemExtended = updateItemExtended;
1362
- /**
1363
- * Update an item's base and data using a dictionary.
1364
- *
1365
- * @param {string} itemId The item ID
1366
- * @param {any} templateDictionary The template dictionary
1367
- * @param {UserSession} authentication The destination session info
1368
- * @returns Promise resolving to successfulness of update
1369
- */
1370
- function updateItemTemplateFromDictionary(itemId, templateDictionary, authentication) {
1371
- return new Promise((resolve, reject) => {
1372
- // Fetch the items as stored in AGO
1373
- Promise.all([
1374
- (0, restHelpersGet_1.getItemBase)(itemId, authentication),
1375
- (0, restHelpersGet_1.getItemDataAsJson)(itemId, authentication)
1376
- ])
1377
- .then(([item, data]) => {
1378
- // Do they have any variables?
1379
- if ((0, templatization_1.hasUnresolvedVariables)(item) || (0, templatization_1.hasUnresolvedVariables)(data)) {
1380
- // Update if so
1381
- const { item: updatedItem, data: updatedData } = (0, templatization_1.replaceInTemplate)({ item, data }, templateDictionary);
1382
- _reportVariablesInItem(itemId, item.type, updatedItem, updatedData);
1383
- return updateItemExtended(updatedItem, updatedData, authentication);
1384
- }
1385
- else {
1386
- // Shortcut out if not
1387
- return Promise.resolve({
1388
- success: true,
1389
- id: itemId
1390
- });
1391
- }
1392
- })
1393
- .then(result => resolve(result))
1394
- .catch(error => reject(error));
1395
- });
1396
- }
1397
- exports.updateItemTemplateFromDictionary = updateItemTemplateFromDictionary;
1398
- /**
1399
- * Updates the URL of an item.
1400
- *
1401
- * @param id AGOL id of item to update
1402
- * @param url URL to assign to item's base section
1403
- * @param authentication Credentials for the request
1404
- * @returns A promise that will resolve with the item id when the item has been updated or an AGO-style JSON failure
1405
- * response
1406
- */
1407
- function updateItemURL(id, url, authentication) {
1408
- const numAttempts = 3;
1409
- return _updateItemURL(id, url, authentication, numAttempts);
1410
- }
1411
- exports.updateItemURL = updateItemURL;
1412
- // ------------------------------------------------------------------------------------------------------------------ //
1413
- /**
1414
- * Adds a data section to an item.
1415
- *
1416
- * @param itemId Id of item to receive data file
1417
- * @param dataFile Data to be added
1418
- * @param authentication Credentials for the request
1419
- * @returns Promise reporting success or failure
1420
- * @private
1421
- */
1422
- function _addItemDataFile(itemId, dataFile, authentication) {
1423
- return new Promise((resolve, reject) => {
1424
- const addItemData = (data) => {
1425
- const addDataOptions = {
1426
- id: itemId,
1427
- data: data,
1428
- authentication: authentication
1429
- };
1430
- (0, arcgis_rest_portal_1.addItemData)(addDataOptions).then(resolve, reject);
1431
- };
1432
- // Item data has to be submitted as text or JSON for those file types
1433
- if (dataFile.type.startsWith("text/plain")) {
1434
- (0, generalHelpers_1.blobToText)(dataFile).then(addItemData, reject);
1435
- }
1436
- else if (dataFile.type === "application/json") {
1437
- (0, generalHelpers_1.blobToJson)(dataFile).then(addItemData, reject);
1438
- }
1439
- else {
1440
- addItemData(dataFile);
1441
- }
1442
- });
1443
- }
1444
- exports._addItemDataFile = _addItemDataFile;
1445
- /**
1446
- * Adds a metadata file to an item.
1447
- *
1448
- * @param itemId Id of item to receive data file
1449
- * @param metadataFile Metadata to be added
1450
- * @param authentication Credentials for the request
1451
- * @returns Promise reporting success or failure
1452
- * @private
1453
- */
1454
- function _addItemMetadataFile(itemId, metadataFile, authentication) {
1455
- return new Promise((resolve, reject) => {
1456
- const addMetadataOptions = {
1457
- item: {
1458
- id: itemId
1459
- },
1460
- params: {
1461
- // Pass metadata in via params because item property is serialized, which discards a blob
1462
- metadata: metadataFile
1463
- },
1464
- authentication: authentication
1465
- };
1466
- (0, arcgis_rest_portal_1.updateItem)(addMetadataOptions).then(resolve, reject);
1467
- });
1468
- }
1469
- exports._addItemMetadataFile = _addItemMetadataFile;
1470
- /**
1471
- * Accumulates the number of relationships in a collection of layers.
1472
- *
1473
- * @param List of layers to examine
1474
- * @returns The number of relationships
1475
- * @private
1476
- */
1477
- function _countRelationships(layers) {
1478
- const reducer = (accumulator, currentLayer) => accumulator +
1479
- (currentLayer.relationships ? currentLayer.relationships.length : 0);
1480
- return layers.reduce(reducer, 0);
1481
- }
1482
- exports._countRelationships = _countRelationships;
1483
- /**
1484
- * Gets the full definitions of the layers affiliated with a hosted service.
1485
- *
1486
- * @param serviceUrl URL to hosted service
1487
- * @param layerList List of layers at that service...must contain id
1488
- * @param authentication Credentials for the request
1489
- * @returns A promise that will resolve with a list of the layers from the admin api
1490
- * @private
1491
- */
1492
- function _getCreateServiceOptions(newItemTemplate, authentication, templateDictionary) {
1493
- return new Promise((resolve, reject) => {
1494
- const serviceInfo = newItemTemplate.properties;
1495
- const folderId = templateDictionary.folderId;
1496
- const isPortal = templateDictionary.isPortal;
1497
- const itemId = newItemTemplate.itemId;
1498
- (0, featureServiceHelpers_1.validateSpatialReferenceAndExtent)(serviceInfo, newItemTemplate, templateDictionary);
1499
- const fallbackExtent = _getFallbackExtent(serviceInfo, templateDictionary);
1500
- const params = {};
1501
- const itemInfo = {
1502
- title: newItemTemplate.item.title,
1503
- name: newItemTemplate.item.name
1504
- };
1505
- const _item = {
1506
- ...itemInfo,
1507
- preserveLayerIds: true
1508
- };
1509
- const createOptions = {
1510
- item: _item,
1511
- folderId,
1512
- params,
1513
- authentication: authentication
1514
- };
1515
- createOptions.item = !(0, trackingHelpers_1.isTrackingViewTemplate)(newItemTemplate) ?
1516
- _setItemProperties(createOptions.item, newItemTemplate, serviceInfo, params, isPortal) :
1517
- (0, trackingHelpers_1.setTrackingOptions)(newItemTemplate, createOptions, templateDictionary);
1518
- // project the portals extent to match that of the service
1519
- convertExtentWithFallback(templateDictionary.organization.defaultExtent, fallbackExtent, serviceInfo.service.spatialReference, templateDictionary.organization.helperServices.geometry.url, authentication).then(extent => {
1520
- templateDictionary[itemId].solutionExtent = extent;
1521
- (0, featureServiceHelpers_1.setDefaultSpatialReference)(templateDictionary, itemId, extent.spatialReference);
1522
- createOptions.item = (0, templatization_1.replaceInTemplate)(createOptions.item, templateDictionary);
1523
- createOptions.params = (0, templatization_1.replaceInTemplate)(createOptions.params, templateDictionary);
1524
- if (newItemTemplate.item.thumbnail) {
1525
- // Pass thumbnail file in via params because item property is serialized, which discards a blob
1526
- createOptions.params.thumbnail = newItemTemplate.item.thumbnail;
1527
- }
1528
- resolve(createOptions);
1529
- }, e => reject((0, generalHelpers_1.fail)(e)));
1530
- });
1531
- }
1532
- exports._getCreateServiceOptions = _getCreateServiceOptions;
1533
- /**
1534
- * When the services spatial reference does not match that of it's default extent
1535
- * use the out SRs default extent if it exists in the templateDictionary
1536
- * this should be set when adding a custom out wkid to the params before calling deploy
1537
- * this will help avoid situations where the orgs default extent and default world extent
1538
- * will not project successfully to the out SR
1539
- *
1540
- * @param serviceInfo the object that contains the spatial reference to evaluate
1541
- * @param templateDictionary the template dictionary
1542
- * @returns the extent to use as the fallback
1543
- * @private
1544
- */
1545
- function _getFallbackExtent(serviceInfo, templateDictionary) {
1546
- const serviceSR = serviceInfo.service.spatialReference;
1547
- const serviceInfoWkid = (0, generalHelpers_1.getProp)(serviceInfo, "defaultExtent.spatialReference.wkid");
1548
- const customDefaultExtent = (0, generalHelpers_1.getProp)(templateDictionary, "params.defaultExtent");
1549
- return serviceInfoWkid && serviceInfoWkid === serviceSR.wkid
1550
- ? serviceInfo.defaultExtent
1551
- : customDefaultExtent
1552
- ? customDefaultExtent
1553
- : serviceInfo.defaultExtent;
1554
- }
1555
- exports._getFallbackExtent = _getFallbackExtent;
1556
- /**
1557
- * Add relationships to all layers in one call to retain fully functioning composite relationships
1558
- *
1559
- * @param args The IPostProcessArgs for the request(s)
1560
- * @returns Any relationships that should be updated for the service
1561
- * @private
1562
- */
1563
- function _getRelationshipUpdates(args) {
1564
- const rels = {
1565
- layers: []
1566
- };
1567
- Object.keys(args.objects).forEach((k) => {
1568
- const obj = args.objects[k];
1569
- /* istanbul ignore else */
1570
- if (obj.relationships && obj.relationships.length > 0) {
1571
- rels.layers.push({
1572
- id: obj.id,
1573
- relationships: obj.relationships
1574
- });
1575
- }
1576
- (0, generalHelpers_1.deleteProp)(obj, "relationships");
1577
- });
1578
- return rels;
1579
- }
1580
- exports._getRelationshipUpdates = _getRelationshipUpdates;
1581
- /**
1582
- * Get the stored contingent values and structure them to be added to the services layers.
1583
- *
1584
- * @param args The IPostProcessArgs for the request(s)
1585
- * @returns Any contingent values that should be added to the service.
1586
- * @private
1587
- */
1588
- function _getContingentValuesUpdates(args) {
1589
- const contingentValues = [];
1590
- Object.keys(args.objects).forEach((k) => {
1591
- const obj = args.objects[k];
1592
- /* istanbul ignore else */
1593
- if (obj.contingentValues) {
1594
- contingentValues.push({
1595
- id: obj.id,
1596
- contingentValues: obj.contingentValues
1597
- });
1598
- }
1599
- (0, generalHelpers_1.deleteProp)(obj, "contingentValues");
1600
- });
1601
- return contingentValues;
1602
- }
1603
- exports._getContingentValuesUpdates = _getContingentValuesUpdates;
1604
- /**
1605
- * Get refresh, add, update, or delete definition info
1606
- *
1607
- * @param url the base admin url for the service
1608
- * @param id the id of the layer
1609
- * @param obj parameters for the request
1610
- * @param args various arguments to help support the request
1611
- * @param type type of update the request will handle
1612
- * @returns IUpdate that has the request url and arguments
1613
- * @private
1614
- */
1615
- function _getUpdate(url, id, obj, args, type) {
1616
- const ops = {
1617
- delete: {
1618
- url: (0, generalHelpers_1.checkUrlPathTermination)(url) + id + "/deleteFromDefinition",
1619
- params: {
1620
- deleteFromDefinition: {
1621
- fields: obj && obj.hasOwnProperty("deleteFields") ? obj.deleteFields : []
1622
- }
1623
- }
1624
- },
1625
- update: {
1626
- url: (0, generalHelpers_1.checkUrlPathTermination)(url) +
1627
- (id ? `${id}/updateDefinition` : "updateDefinition"),
1628
- params: {
1629
- updateDefinition: obj
1630
- }
1631
- },
1632
- add: {
1633
- url: (0, generalHelpers_1.checkUrlPathTermination)(url) + "addToDefinition",
1634
- params: {
1635
- addToDefinition: obj
1636
- }
1637
- },
1638
- refresh: {
1639
- url: (0, generalHelpers_1.checkUrlPathTermination)(url) + "refresh",
1640
- params: {
1641
- f: "json"
1642
- }
1643
- }
1644
- };
1645
- return {
1646
- url: ops[type].url,
1647
- params: ops[type].params,
1648
- args: args
1649
- };
1650
- }
1651
- exports._getUpdate = _getUpdate;
1652
- /**
1653
- * Changes just the domain part of a URL to lowercase.
1654
- *
1655
- * @param url URL to modify
1656
- * @return Adjusted URL
1657
- * @see From `getServerRootUrl` in arcgis-rest-js' ArcGISIdentityManager.ts
1658
- * @private
1659
- */
1660
- function _lowercaseDomain(url) {
1661
- if (!url) {
1662
- return url;
1663
- }
1664
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1665
- const [_, protocol, domainAndPath] = url.match(/(https?:\/\/)(.+)/);
1666
- const [domain, ...path] = domainAndPath.split("/");
1667
- // Only the domain is lowercased because in some cases an org id might be
1668
- // in the path which cannot be lowercased.
1669
- return `${protocol}${domain.toLowerCase()}/${path.join("/")}`;
1670
- }
1671
- exports._lowercaseDomain = _lowercaseDomain;
1672
- /**
1673
- * Checks the two main parts of an item for unresolved variables and reports any found.
1674
- *
1675
- * @param base Item's base section
1676
- * @param data Item's data section
1677
- * @private
1678
- */
1679
- function _reportVariablesInItem(itemId, itemType, base, data) {
1680
- const getUnresolved = (v) => {
1681
- return JSON.stringify(v).match(/{{.+?}}/gim);
1682
- };
1683
- // Provide feedback about any remaining unresolved variables
1684
- /* istanbul ignore else */
1685
- if (base && (0, templatization_1.hasUnresolvedVariables)(base)) {
1686
- console.log(itemId +
1687
- " (" +
1688
- itemType +
1689
- ") contains variables in base: " +
1690
- JSON.stringify(getUnresolved(base)));
1691
- }
1692
- /* istanbul ignore else */
1693
- if (data && (0, templatization_1.hasUnresolvedVariables)(data)) {
1694
- console.log(itemId +
1695
- " (" +
1696
- itemType +
1697
- ") contains variables in data: " +
1698
- JSON.stringify(getUnresolved(data)));
1699
- }
1700
- }
1701
- exports._reportVariablesInItem = _reportVariablesInItem;
1702
- /**
1703
- * Updates a feature service item.
1704
- *
1705
- * @param item Item to update
1706
- * @param itemTemplate item template for the new item
1707
- * @param serviceInfo Service information
1708
- * @param params arcgis-rest-js params to update
1709
- * @param isPortal Is the service hosted in a portal?
1710
- * @returns Updated item
1711
- * @private
1712
- */
1713
- function _setItemProperties(item, itemTemplate, serviceInfo, params, isPortal) {
1714
- // Set the capabilities
1715
- const portalCapabilities = [
1716
- "Create",
1717
- "Query",
1718
- "Editing",
1719
- "Update",
1720
- "Delete",
1721
- "Uploads",
1722
- "Sync",
1723
- "Extract"
1724
- ];
1725
- const capabilities = (0, generalHelpers_1.getProp)(serviceInfo, "service.capabilities") || (isPortal ? "" : []);
1726
- item.capabilities = isPortal
1727
- ? capabilities
1728
- .split(",")
1729
- .filter((c) => portalCapabilities.indexOf(c) > -1)
1730
- .join(",")
1731
- : capabilities;
1732
- if (serviceInfo.service.capabilities) {
1733
- serviceInfo.service.capabilities = item.capabilities;
1734
- }
1735
- // Handle index update for any pre-published solution items that
1736
- // have non-unique indexes on relationship key fields
1737
- _updateIndexesForRelationshipKeyFields(serviceInfo);
1738
- // set create options item properties
1739
- const keyProperties = [
1740
- "isView",
1741
- "sourceSchemaChangesAllowed",
1742
- "isUpdatableView",
1743
- "capabilities",
1744
- "isMultiServicesView"
1745
- ];
1746
- const deleteKeys = ["layers", "tables"];
1747
- /* istanbul ignore else */
1748
- if (isPortal) {
1749
- // removed for issue #423 causing FS to fail to create
1750
- deleteKeys.push("adminServiceInfo");
1751
- }
1752
- const itemKeys = Object.keys(item);
1753
- const serviceKeys = Object.keys(serviceInfo.service);
1754
- serviceKeys.forEach(k => {
1755
- /* istanbul ignore else */
1756
- if (itemKeys.indexOf(k) === -1 && deleteKeys.indexOf(k) < 0) {
1757
- item[k] = serviceInfo.service[k];
1758
- // These need to be included via params otherwise...
1759
- // addToDef calls fail when adding adminLayerInfo
1760
- /* istanbul ignore else */
1761
- if (serviceInfo.service.isView && keyProperties.indexOf(k) > -1) {
1762
- params[k] = serviceInfo.service[k];
1763
- }
1764
- }
1765
- });
1766
- // Enable editor tracking on layer with related tables is not supported.
1767
- /* istanbul ignore else */
1768
- if (item.isMultiServicesView &&
1769
- (0, generalHelpers_1.getProp)(item, "editorTrackingInfo.enableEditorTracking")) {
1770
- item.editorTrackingInfo.enableEditorTracking = false;
1771
- params["editorTrackingInfo"] = item.editorTrackingInfo;
1772
- }
1773
- /* istanbul ignore else */
1774
- if (isPortal) {
1775
- // portal will fail when initialExtent is defined but null
1776
- // removed for issue #449 causing FS to fail to create on portal
1777
- /* istanbul ignore else */
1778
- if (Object.keys(item).indexOf("initialExtent") > -1 &&
1779
- !item.initialExtent) {
1780
- (0, generalHelpers_1.deleteProp)(item, "initialExtent");
1781
- }
1782
- }
1783
- return item;
1784
- }
1785
- exports._setItemProperties = _setItemProperties;
1786
- /**
1787
- * Set isUnique as true for indexes that reference origin relationship keyFields.
1788
- *
1789
- * @param serviceInfo Service information
1790
- * @private
1791
- */
1792
- function _updateIndexesForRelationshipKeyFields(serviceInfo) {
1793
- const layersAndTables = (serviceInfo.layers || []).concat(serviceInfo.tables || []);
1794
- layersAndTables.forEach(item => {
1795
- const relationships = item.relationships;
1796
- const indexes = item.indexes;
1797
- /* istanbul ignore else */
1798
- if (relationships &&
1799
- relationships.length > 0 &&
1800
- indexes &&
1801
- indexes.length > 0) {
1802
- const keyFields = relationships.reduce((acc, v) => {
1803
- /* istanbul ignore else */
1804
- if (v.role === "esriRelRoleOrigin" &&
1805
- v.keyField &&
1806
- acc.indexOf(v.keyField) < 0) {
1807
- acc.push(v.keyField);
1808
- }
1809
- return acc;
1810
- }, []);
1811
- indexes.map(i => {
1812
- /* istanbul ignore else */
1813
- if (keyFields.some(k => {
1814
- const regEx = new RegExp(`\\b${k}\\b`);
1815
- return regEx.test(i.fields);
1816
- })) {
1817
- i.isUnique = true;
1818
- }
1819
- return i;
1820
- });
1821
- }
1822
- });
1823
- }
1824
- exports._updateIndexesForRelationshipKeyFields = _updateIndexesForRelationshipKeyFields;
1825
- /**
1826
- * Updates the URL of an item.
1827
- *
1828
- * @param id AGOL id of item to update
1829
- * @param url URL to assign to item's base section
1830
- * @param authentication Credentials for the request
1831
- * @param numAttempts Number of times to try to set the URL if AGO says that it updated the URL, but really didn't
1832
- * @returns A promise that will resolve with the item id when the item has been updated or an AGO-style JSON failure
1833
- * response
1834
- * @private
1835
- */
1836
- function _updateItemURL(id, url, authentication, numAttempts = 1) {
1837
- // Introduce a lag because AGO update appears to choke with rapid subsequent calls
1838
- const msLag = 1000;
1839
- return new Promise((resolve, reject) => {
1840
- // Update the item's URL
1841
- const options = { item: { id, url }, authentication: authentication };
1842
- (0, arcgis_rest_portal_1.updateItem)(options).then(result => {
1843
- if (!result.success) {
1844
- reject((0, generalHelpers_1.fail)(result));
1845
- }
1846
- else {
1847
- // Get the item to see if the URL really changed; we'll delay a bit before testing because AGO
1848
- // has a timing problem with URL updates
1849
- setTimeout(() => {
1850
- (0, arcgis_rest_portal_1.getItem)(id, { authentication: authentication }).then(item => {
1851
- const iBrace = item.url.indexOf("{");
1852
- if (iBrace > -1) {
1853
- console.warn(id + " has template variable: " + item.url.substr(iBrace));
1854
- }
1855
- if (url === item.url) {
1856
- resolve(id);
1857
- }
1858
- else {
1859
- // If it fails, try again if we have sufficient attempts remaining
1860
- const errorMsg = "URL not updated for " +
1861
- item.type +
1862
- " " +
1863
- item.id +
1864
- ": " +
1865
- item.url +
1866
- " (" +
1867
- numAttempts +
1868
- ")";
1869
- if (--numAttempts > 0) {
1870
- _updateItemURL(id, url, authentication, numAttempts).then(resolve, reject);
1871
- }
1872
- else {
1873
- console.error(id + ": " + errorMsg + "; FAILED");
1874
- reject(errorMsg);
1875
- }
1876
- }
1877
- }, e => reject((0, generalHelpers_1.fail)(e)));
1878
- }, msLag);
1879
- }
1880
- }, e => reject((0, generalHelpers_1.fail)(e)));
1881
- });
1882
- }
1883
- exports._updateItemURL = _updateItemURL;
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._getRelationshipUpdates = exports._getFallbackExtent = exports._getCreateServiceOptions = exports._countRelationships = exports._addItemMetadataFile = exports._addItemDataFile = exports.updateItemURL = exports.updateItemTemplateFromDictionary = exports.updateItemExtended = exports.updateGroup = exports.updateItem = exports.shareItem = exports.removeUsers = exports.reassignGroup = exports.searchGroupContents = exports.searchGroupAllContents = exports.searchAllGroups = exports.searchGroups = exports.searchAllItems = exports.searchItems = exports.removeItemOrGroup = exports.removeItem = exports.removeGroup = exports.removeFolder = exports.hasInvalidGroupDesignations = exports._parseAdminServiceData = exports.getFeatureServiceProperties = exports.getServiceLayersAndTables = exports.getRequest = exports._sortRelationships = exports.getLayerUpdates = exports.getLayers = exports.extractDependencies = exports.createUniqueGroup = exports.createUniqueFolder = exports.createItemWithData = exports.createFullItem = exports.createFeatureService = exports.convertExtent = exports.convertExtentWithFallback = exports._validateExtent = exports.convertToISearchOptions = exports.checkRequestStatus = exports.addToServiceDefinition = exports.addTokenToUrl = exports.addForwardItemRelationships = exports.addForwardItemRelationship = exports.getUserSession = exports.addItemData = exports.rest_request = void 0;
19
+ exports._updateItemURL = exports._updateIndexesForRelationshipKeyFields = exports._setItemProperties = exports._reportVariablesInItem = exports._lowercaseDomain = exports._getUpdate = exports._getContingentValuesUpdates = void 0;
20
+ /**
21
+ * Provides common functions involving the arcgis-rest-js library.
22
+ *
23
+ * @module restHelpers
24
+ */
25
+ const featureServiceHelpers_1 = require("./featureServiceHelpers");
26
+ const generalHelpers_1 = require("./generalHelpers");
27
+ const interfaces_1 = require("./interfaces");
28
+ const libConnectors_1 = require("./libConnectors");
29
+ const restHelpersGet_1 = require("./restHelpersGet");
30
+ const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
31
+ const arcgis_rest_request_1 = require("@esri/arcgis-rest-request");
32
+ const arcgis_rest_service_admin_1 = require("@esri/arcgis-rest-service-admin");
33
+ const workforceHelpers_1 = require("./workforceHelpers");
34
+ const templatization_1 = require("./templatization");
35
+ const trackingHelpers_1 = require("./trackingHelpers");
36
+ // ------------------------------------------------------------------------------------------------------------------ //
37
+ var arcgis_rest_request_2 = require("@esri/arcgis-rest-request");
38
+ Object.defineProperty(exports, "rest_request", { enumerable: true, get: function () { return arcgis_rest_request_2.request; } });
39
+ // ------------------------------------------------------------------------------------------------------------------ //
40
+ function addItemData(id, data, authentication) {
41
+ const addDataOptions = {
42
+ id,
43
+ data,
44
+ authentication
45
+ };
46
+ return (0, arcgis_rest_portal_1.addItemData)(addDataOptions);
47
+ }
48
+ exports.addItemData = addItemData;
49
+ ;
50
+ /**
51
+ * Creates a UserSession via a function so that the global arcgisSolution variable can access authentication.
52
+ *
53
+ * @param options See https://esri.github.io/arcgis-rest-js/api/auth/IUserSessionOptions/
54
+ * @returns UserSession
55
+ */
56
+ function getUserSession(options = {}) {
57
+ return new interfaces_1.UserSession(options);
58
+ }
59
+ exports.getUserSession = getUserSession;
60
+ /**
61
+ * Adds a forward relationship between two items.
62
+ *
63
+ * @param originItemId Origin of relationship
64
+ * @param destinationItemId Destination of relationship
65
+ * @param relationshipType Type of relationship
66
+ * @param authentication Credentials for the request
67
+ * @returns A Promise to add item resources.
68
+ */
69
+ function addForwardItemRelationship(originItemId, destinationItemId, relationshipType, authentication) {
70
+ return new Promise(resolve => {
71
+ const requestOptions = {
72
+ originItemId,
73
+ destinationItemId,
74
+ relationshipType,
75
+ authentication
76
+ };
77
+ (0, arcgis_rest_portal_1.addItemRelationship)(requestOptions).then(response => {
78
+ resolve({
79
+ success: response.success,
80
+ itemId: originItemId
81
+ });
82
+ }, () => {
83
+ resolve({
84
+ success: false,
85
+ itemId: originItemId
86
+ });
87
+ });
88
+ });
89
+ }
90
+ exports.addForwardItemRelationship = addForwardItemRelationship;
91
+ /**
92
+ * Adds forward relationships for an item.
93
+ *
94
+ * @param originItemId Origin of relationship
95
+ * @param destinationRelationships Destinations
96
+ * @param authentication Credentials for the request
97
+ * @returns A Promise to add item resources.
98
+ */
99
+ function addForwardItemRelationships(originItemId, destinationRelationships, authentication) {
100
+ return new Promise(resolve => {
101
+ // Set up relationships using updated relationship information
102
+ const relationshipPromises = new Array();
103
+ destinationRelationships.forEach(relationship => {
104
+ relationship.relatedItemIds.forEach(relatedItemId => {
105
+ relationshipPromises.push(addForwardItemRelationship(originItemId, relatedItemId, relationship.relationshipType, authentication));
106
+ });
107
+ });
108
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
109
+ Promise.all(relationshipPromises).then((responses) => resolve(responses));
110
+ });
111
+ }
112
+ exports.addForwardItemRelationships = addForwardItemRelationships;
113
+ /**
114
+ * Adds a token to the query parameters of a URL.
115
+ *
116
+ * @param url URL to use as base
117
+ * @param authentication Credentials to be used to generate token for URL
118
+ * @returns A promise that will resolve with the supplied URL with `token=&lt;token&gt;` added to its query params
119
+ * unless either the URL doesn't exist or the token can't be generated
120
+ */
121
+ function addTokenToUrl(url, authentication) {
122
+ return new Promise(resolve => {
123
+ if (!url || !authentication) {
124
+ resolve(url);
125
+ }
126
+ else {
127
+ authentication.getToken(url).then(token => {
128
+ /* istanbul ignore else */
129
+ if (token) {
130
+ url = (0, generalHelpers_1.appendQueryParam)(url, "token=" + token);
131
+ }
132
+ resolve(url);
133
+ }, () => resolve(url));
134
+ }
135
+ });
136
+ }
137
+ exports.addTokenToUrl = addTokenToUrl;
138
+ /**
139
+ * Calls addToDefinition for the service.
140
+ *
141
+ * Added retry due to some solutions failing to deploy in specific orgs/hives due to timeouts.
142
+ * On the first pass we will use the quicker sync request to add.
143
+ * If it fails we will use an async request that will avoid the timeout errors.
144
+ *
145
+ * @param url URL to use as base
146
+ * @param options the info to add to the services definition
147
+ * @param skipRetry a boolean to control if retry logic will be used. Defaults to false.
148
+ * @param useAsync a boolean to control if we will use an async request
149
+ * @returns A promise that will resolve when the request has completed
150
+ */
151
+ function addToServiceDefinition(url, options, skipRetry = false, useAsync = false) {
152
+ /* istanbul ignore else */
153
+ if (useAsync) {
154
+ options.params = { ...options.params, async: true };
155
+ }
156
+ return new Promise((resolve, reject) => {
157
+ (0, arcgis_rest_service_admin_1.addToServiceDefinition)(url, options).then((result) => {
158
+ checkRequestStatus(result, options.authentication).then(() => resolve(null), e => reject((0, generalHelpers_1.fail)(e)));
159
+ }, e => {
160
+ if (!skipRetry) {
161
+ addToServiceDefinition(url, options, true, true).then(() => resolve(null), e => reject(e));
162
+ }
163
+ else {
164
+ reject((0, generalHelpers_1.fail)(e));
165
+ }
166
+ });
167
+ });
168
+ }
169
+ exports.addToServiceDefinition = addToServiceDefinition;
170
+ /**
171
+ * When using an async request we need to poll the status url to know when the request has completed or failed.
172
+ *
173
+ * @param result the result returned from the addToDefinition request.
174
+ * This will contain a status url or the standard sync result.
175
+ * @param authentication Credentials to be used to generate token for URL
176
+ * @returns A promise that will resolve when the request has completed
177
+ */
178
+ function checkRequestStatus(result, authentication) {
179
+ return new Promise((resolve, reject) => {
180
+ if (result.statusURL) {
181
+ const checkStatus = setInterval(() => {
182
+ (0, arcgis_rest_request_1.request)(result.statusURL, { authentication }).then(r => {
183
+ /* istanbul ignore else */
184
+ if (r.status === "Completed") {
185
+ clearInterval(checkStatus);
186
+ resolve();
187
+ }
188
+ else if (r.status === "Failed") {
189
+ clearInterval(checkStatus);
190
+ reject(r);
191
+ }
192
+ }, e => {
193
+ clearInterval(checkStatus);
194
+ reject(e);
195
+ });
196
+ }, 2000);
197
+ }
198
+ else {
199
+ resolve();
200
+ }
201
+ });
202
+ }
203
+ exports.checkRequestStatus = checkRequestStatus;
204
+ /**
205
+ * Converts a general search into an ISearchOptions structure.
206
+ *
207
+ * @param search Search specified in one of three ways
208
+ * @returns Recast search
209
+ */
210
+ function convertToISearchOptions(search) {
211
+ // Convert the search into an ISearchOptions
212
+ let searchOptions = {
213
+ q: "",
214
+ start: 1,
215
+ num: 100
216
+ };
217
+ if (typeof search === "string") {
218
+ // Insert query into defaults
219
+ searchOptions.q = search;
220
+ }
221
+ else if (search instanceof arcgis_rest_portal_1.SearchQueryBuilder) {
222
+ // Insert query into defaults
223
+ searchOptions.q = search.toParam();
224
+ }
225
+ else { // search is ISearchOptions
226
+ searchOptions = {
227
+ ...searchOptions,
228
+ ...search // request
229
+ };
230
+ }
231
+ return searchOptions;
232
+ }
233
+ exports.convertToISearchOptions = convertToISearchOptions;
234
+ /**
235
+ * Simple validate function to ensure all coordinates are numbers
236
+ * In some cases orgs can have null or undefined coordinate values associated with the org extent
237
+ *
238
+ * @param extent the extent to validate
239
+ * @returns the provided extent or a default global extent if some coordinates are not numbers
240
+ * @private
241
+ */
242
+ function _validateExtent(extent) {
243
+ // in some cases orgs can have invalid extents defined
244
+ // this is a simple validate function that will ensure coordiantes are numbers
245
+ // using -179,-89,179,89 because the project call is returning "NaN" when using -180,-90,180,90
246
+ const hasInvalid = typeof extent.xmin !== "number" ||
247
+ typeof extent.xmax !== "number" ||
248
+ typeof extent.ymax !== "number" ||
249
+ typeof extent.ymin !== "number";
250
+ if (hasInvalid) {
251
+ extent.xmin = -179;
252
+ extent.xmax = 179;
253
+ extent.ymax = 89;
254
+ extent.ymin = -89;
255
+ extent.spatialReference = { wkid: 4326 };
256
+ }
257
+ return extent;
258
+ }
259
+ exports._validateExtent = _validateExtent;
260
+ /**
261
+ * If the request to convert the extent fails it has commonly been due to an invalid extent.
262
+ * This function will first attempt to use the provided extent. If it fails it will default to
263
+ * the source items extent and if that fails it will then use a default global extent.
264
+ *
265
+ * @param extent the extent to convert
266
+ * @param fallbackExtent the extent to convert if the main extent does not project to the outSR
267
+ * @param outSR the spatial reference to project to
268
+ * @param geometryServiceUrl the service url for the geometry service to use
269
+ * @param authentication the credentials for the requests
270
+ * @returns the extent projected to the provided spatial reference
271
+ * or the world extent projected to the provided spatial reference
272
+ * @private
273
+ */
274
+ function convertExtentWithFallback(extent, fallbackExtent, outSR, geometryServiceUrl, authentication) {
275
+ return new Promise((resolve, reject) => {
276
+ const defaultExtent = {
277
+ xmin: -179,
278
+ xmax: 179,
279
+ ymin: -89,
280
+ ymax: 89,
281
+ spatialReference: { wkid: 4326 }
282
+ };
283
+ convertExtent(_validateExtent(extent), outSR, geometryServiceUrl, authentication).then(extentResponse => {
284
+ // in some cases project will complete successfully but return "NaN" values
285
+ // check for this and call convert again if it does
286
+ const extentResponseString = JSON.stringify(extentResponse);
287
+ const validatedExtent = JSON.stringify(_validateExtent(extentResponse));
288
+ if (extentResponseString === validatedExtent) {
289
+ resolve(extentResponse);
290
+ }
291
+ else {
292
+ convertExtent(fallbackExtent || defaultExtent, outSR, geometryServiceUrl, authentication).then(resolve, e => reject((0, generalHelpers_1.fail)(e)));
293
+ }
294
+ },
295
+ // if convert fails try again with default global extent
296
+ () => {
297
+ convertExtent(defaultExtent, outSR, geometryServiceUrl, authentication).then(resolve, e => reject((0, generalHelpers_1.fail)(e)));
298
+ });
299
+ });
300
+ }
301
+ exports.convertExtentWithFallback = convertExtentWithFallback;
302
+ /**
303
+ * Converts an extent to a specified spatial reference.
304
+ *
305
+ * @param extent Extent object to check and (possibly) to project
306
+ * @param outSR Desired spatial reference
307
+ * @param geometryServiceUrl Path to geometry service providing `findTransformations` and `project` services
308
+ * @param authentication Credentials for the request
309
+ * @returns Original extent if it's already using outSR or the extents projected into the outSR
310
+ */
311
+ function convertExtent(extent, outSR, geometryServiceUrl, authentication) {
312
+ const _requestOptions = { authentication };
313
+ return new Promise((resolve, reject) => {
314
+ if (extent.spatialReference.wkid === outSR?.wkid || !outSR) {
315
+ resolve(extent);
316
+ }
317
+ else {
318
+ _requestOptions.params = {
319
+ f: "json",
320
+ inSR: extent.spatialReference.wkid,
321
+ outSR: outSR.wkid,
322
+ extentOfInterest: JSON.stringify(extent)
323
+ };
324
+ (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(geometryServiceUrl) + "findTransformations", _requestOptions).then(response => {
325
+ const transformations = response && response.transformations
326
+ ? response.transformations
327
+ : undefined;
328
+ let transformation;
329
+ if (transformations && transformations.length > 0) {
330
+ // if a forward single transformation is found use that...otherwise check for and use composite
331
+ transformation = transformations[0].wkid
332
+ ? transformations[0].wkid
333
+ : transformations[0].geoTransforms
334
+ ? transformations[0]
335
+ : undefined;
336
+ }
337
+ _requestOptions.params = {
338
+ f: "json",
339
+ outSR: outSR.wkid,
340
+ inSR: extent.spatialReference.wkid,
341
+ geometries: {
342
+ geometryType: "esriGeometryPoint",
343
+ geometries: [
344
+ { x: extent.xmin, y: extent.ymin },
345
+ { x: extent.xmax, y: extent.ymax }
346
+ ]
347
+ },
348
+ transformation: transformation
349
+ };
350
+ (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(geometryServiceUrl) + "project", _requestOptions).then(projectResponse => {
351
+ const projectGeom = projectResponse.geometries.length === 2
352
+ ? projectResponse.geometries
353
+ : undefined;
354
+ if (projectGeom) {
355
+ resolve({
356
+ xmin: projectGeom[0].x,
357
+ ymin: projectGeom[0].y,
358
+ xmax: projectGeom[1].x,
359
+ ymax: projectGeom[1].y,
360
+ spatialReference: outSR
361
+ });
362
+ }
363
+ else {
364
+ resolve(undefined);
365
+ }
366
+ }, e => reject((0, generalHelpers_1.fail)(e)));
367
+ }, e => reject((0, generalHelpers_1.fail)(e)));
368
+ }
369
+ });
370
+ }
371
+ exports.convertExtent = convertExtent;
372
+ /**
373
+ * Publishes a feature service as an AGOL item; it does not include its layers and tables
374
+ *
375
+ * @param newItemTemplate Template of item to be created
376
+ * @param authentication Credentials for the request
377
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, user; .user.folders property contains a list
378
+ * @returns A promise that will resolve with an object reporting success and the Solution id
379
+ */
380
+ function createFeatureService(newItemTemplate, authentication, templateDictionary) {
381
+ return new Promise((resolve, reject) => {
382
+ // Create item
383
+ _getCreateServiceOptions(newItemTemplate, authentication, templateDictionary).then(createOptions => {
384
+ (0, arcgis_rest_service_admin_1.createFeatureService)(createOptions).then(createResponse => {
385
+ // Federated servers may have inconsistent casing, so lowerCase it
386
+ createResponse.encodedServiceURL = _lowercaseDomain(createResponse.encodedServiceURL);
387
+ createResponse.serviceurl = _lowercaseDomain(createResponse.serviceurl);
388
+ resolve(createResponse);
389
+ }, e => reject((0, generalHelpers_1.fail)(e)));
390
+ }, e => reject((0, generalHelpers_1.fail)(e)));
391
+ });
392
+ }
393
+ exports.createFeatureService = createFeatureService;
394
+ /**
395
+ * Publishes an item and its data, metadata, and resources as an AGOL item.
396
+ *
397
+ * @param itemInfo Item's `item` section
398
+ * @param folderId Id of folder to receive item; null indicates that the item goes into the root
399
+ * folder; ignored for Group item type
400
+ * @param destinationAuthentication Credentials for for requests to where the item is to be created
401
+ * @param itemThumbnailUrl URL to image to use for item thumbnail
402
+ * @param itemThumbnailAuthentication Credentials for requests to the thumbnail source
403
+ * @param dataFile Item's `data` section
404
+ * @param metadataFile Item's metadata file
405
+ * @param resourcesFiles Item's resources
406
+ * @param access Access to set for item: "public", "org", "private"
407
+ * @returns A promise that will resolve with an object reporting success or failure and the Solution id
408
+ */
409
+ function createFullItem(itemInfo, folderId, destinationAuthentication, itemThumbnailUrl, itemThumbnailAuthentication, dataFile, metadataFile, resourcesFiles, access = "private") {
410
+ return new Promise((resolve, reject) => {
411
+ // Create item
412
+ const createOptions = {
413
+ item: {
414
+ ...itemInfo
415
+ },
416
+ folderId,
417
+ authentication: destinationAuthentication
418
+ };
419
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
420
+ addTokenToUrl(itemThumbnailUrl, itemThumbnailAuthentication).then(updatedThumbnailUrl => {
421
+ /* istanbul ignore else */
422
+ if (updatedThumbnailUrl) {
423
+ createOptions.item.thumbnailUrl = (0, generalHelpers_1.appendQueryParam)(updatedThumbnailUrl, "w=400");
424
+ }
425
+ (0, arcgis_rest_portal_1.createItemInFolder)(createOptions).then(createResponse => {
426
+ if (createResponse.success) {
427
+ let accessDef;
428
+ // Set access if it is not AGOL default
429
+ // Set the access manually since the access value in createItem appears to be ignored
430
+ // Need to run serially; will not work reliably if done in parallel with adding the data section
431
+ if (access !== "private") {
432
+ const accessOptions = {
433
+ id: createResponse.id,
434
+ access: access === "public" ? "public" : "org",
435
+ authentication: destinationAuthentication
436
+ };
437
+ accessDef = (0, arcgis_rest_portal_1.setItemAccess)(accessOptions);
438
+ }
439
+ else {
440
+ accessDef = Promise.resolve({
441
+ itemId: createResponse.id
442
+ });
443
+ }
444
+ // Now add attached items
445
+ accessDef.then(() => {
446
+ const updateDefs = [];
447
+ // Add the data section
448
+ if (dataFile) {
449
+ updateDefs.push(_addItemDataFile(createResponse.id, dataFile, destinationAuthentication));
450
+ }
451
+ // Add the resources via a zip because AGO sometimes loses resources if many are added at the
452
+ // same time to the same item
453
+ if (Array.isArray(resourcesFiles) &&
454
+ resourcesFiles.length > 0) {
455
+ updateDefs.push(new Promise((rsrcResolve, rsrcReject) => {
456
+ (0, libConnectors_1.createZip)("resources.zip", resourcesFiles).then((zipfile) => {
457
+ const addResourceOptions = {
458
+ id: createResponse.id,
459
+ resource: zipfile,
460
+ authentication: destinationAuthentication,
461
+ params: {
462
+ archive: true
463
+ }
464
+ };
465
+ (0, arcgis_rest_portal_1.addItemResource)(addResourceOptions).then(rsrcResolve, rsrcReject);
466
+ }, rsrcReject);
467
+ }));
468
+ }
469
+ // Add the metadata section
470
+ if (metadataFile) {
471
+ updateDefs.push(_addItemMetadataFile(createResponse.id, metadataFile, destinationAuthentication));
472
+ }
473
+ // Wait until all adds are done
474
+ Promise.all(updateDefs).then(() => resolve(createResponse), e => reject((0, generalHelpers_1.fail)(e)));
475
+ }, e => reject((0, generalHelpers_1.fail)(e)));
476
+ }
477
+ else {
478
+ reject((0, generalHelpers_1.fail)());
479
+ }
480
+ }, e => reject((0, generalHelpers_1.fail)(e)));
481
+ });
482
+ });
483
+ }
484
+ exports.createFullItem = createFullItem;
485
+ /**
486
+ * Publishes an item and its data as an AGOL item.
487
+ *
488
+ * @param itemInfo Item's `item` section
489
+ * @param dataInfo Item's `data` section
490
+ * @param authentication Credentials for the request
491
+ * @param folderId Id of folder to receive item; null indicates that the item goes into the root
492
+ * folder; ignored for Group item type
493
+ * @param access Access to set for item: "public", "org", "private"
494
+ * @returns A promise that will resolve with an object reporting success and the Solution id
495
+ */
496
+ function createItemWithData(itemInfo, dataInfo, authentication, folderId, access = "private") {
497
+ return new Promise((resolve, reject) => {
498
+ // Create item
499
+ const createOptions = {
500
+ item: {
501
+ title: "_",
502
+ ...itemInfo,
503
+ data: dataInfo
504
+ },
505
+ folderId,
506
+ authentication: authentication
507
+ };
508
+ if (itemInfo.thumbnail) {
509
+ createOptions.params = {
510
+ // Pass thumbnail file in via params because item property is serialized, which discards a blob
511
+ thumbnail: itemInfo.thumbnail
512
+ };
513
+ delete createOptions.item.thumbnail;
514
+ }
515
+ (0, arcgis_rest_portal_1.createItemInFolder)(createOptions).then(createResponse => {
516
+ if (createResponse.success) {
517
+ if (access !== "private") {
518
+ // Set access if it is not AGOL default
519
+ // Set the access manually since the access value in createItem appears to be ignored
520
+ const accessOptions = {
521
+ id: createResponse.id,
522
+ access: access === "public" ? "public" : "org",
523
+ authentication: authentication
524
+ };
525
+ (0, arcgis_rest_portal_1.setItemAccess)(accessOptions).then(() => {
526
+ resolve({
527
+ folder: createResponse.folder,
528
+ id: createResponse.id,
529
+ success: true
530
+ });
531
+ }, e => reject((0, generalHelpers_1.fail)(e)));
532
+ }
533
+ else {
534
+ resolve({
535
+ folder: createResponse.folder,
536
+ id: createResponse.id,
537
+ success: true
538
+ });
539
+ }
540
+ }
541
+ else {
542
+ reject((0, generalHelpers_1.fail)());
543
+ }
544
+ }, e => reject((0, generalHelpers_1.fail)(e)));
545
+ });
546
+ }
547
+ exports.createItemWithData = createItemWithData;
548
+ /**
549
+ * Creates a folder using a numeric suffix to ensure uniqueness if necessary.
550
+ *
551
+ * @param title Folder title, used as-is if possible and with suffix otherwise
552
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, user; .user.folders property contains a list
553
+ * of known folder names; function updates list with existing names not yet known, and creates .user.folders if it
554
+ * doesn't exist in the dictionary
555
+ * @param authentication Credentials for creating folder
556
+ * @returns Id of created folder
557
+ */
558
+ function createUniqueFolder(title, templateDictionary, authentication) {
559
+ return new Promise((resolve, reject) => {
560
+ // Get a title that is not already in use
561
+ const folderTitle = (0, generalHelpers_1.getUniqueTitle)(title, templateDictionary, "user.folders");
562
+ const folderCreationParam = {
563
+ title: folderTitle,
564
+ authentication: authentication
565
+ };
566
+ (0, arcgis_rest_portal_1.createFolder)(folderCreationParam).then(ok => resolve(ok), err => {
567
+ // If the name already exists, we'll try again
568
+ const errorDetails = (0, generalHelpers_1.getProp)(err, "response.error.details");
569
+ if (Array.isArray(errorDetails) && errorDetails.length > 0) {
570
+ const nameNotAvailMsg = "Folder title '" + folderTitle + "' not available.";
571
+ if (errorDetails.indexOf(nameNotAvailMsg) >= 0) {
572
+ // Create the user.folders property if it doesn't exist
573
+ /* istanbul ignore else */
574
+ if (!(0, generalHelpers_1.getProp)(templateDictionary, "user.folders")) {
575
+ (0, generalHelpers_1.setCreateProp)(templateDictionary, "user.folders", []);
576
+ }
577
+ templateDictionary.user.folders.push({
578
+ title: folderTitle
579
+ });
580
+ createUniqueFolder(title, templateDictionary, authentication).then(resolve, reject);
581
+ }
582
+ else {
583
+ reject(err);
584
+ }
585
+ }
586
+ else {
587
+ // Otherwise, error out
588
+ reject(err);
589
+ }
590
+ });
591
+ });
592
+ }
593
+ exports.createUniqueFolder = createUniqueFolder;
594
+ /**
595
+ * Creates a group using numeric suffix to ensure uniqueness.
596
+ *
597
+ * @param title Group title, used as-is if possible and with suffix otherwise
598
+ * @param templateDictionary Hash of facts: org URL, adlib replacements, user
599
+ * @param authentication Credentials for creating group
600
+ * @param owner Optional arg for the Tracking owner
601
+ * If the tracking owner is not the one deploying the solution
602
+ * tracker groups will be created under the deployment user but
603
+ * will be reassigned to the tracking owner.
604
+ * @returns Information about created group
605
+ */
606
+ function createUniqueGroup(title, groupItem, templateDictionary, authentication, owner) {
607
+ return new Promise((resolve, reject) => {
608
+ let groupsPromise;
609
+ // when working with tracker we need to consider the groups of the deploying user as well as the groups
610
+ // of the tracking user...must be unique for both
611
+ if (owner && owner !== authentication.username) {
612
+ groupsPromise = searchAllGroups(`(owner:${owner}) orgid:${templateDictionary.organization.id}`, authentication);
613
+ }
614
+ else {
615
+ groupsPromise = Promise.resolve([]);
616
+ }
617
+ // first get the tracker owner groups
618
+ groupsPromise.then(groups => {
619
+ templateDictionary["allGroups"] =
620
+ groups.concat((0, generalHelpers_1.getProp)(templateDictionary, "user.groups"));
621
+ // Get a title that is not already in use
622
+ groupItem.title = (0, generalHelpers_1.getUniqueTitle)(title, templateDictionary, "allGroups");
623
+ const groupCreationParam = {
624
+ group: groupItem,
625
+ authentication: authentication
626
+ };
627
+ (0, arcgis_rest_portal_1.createGroup)(groupCreationParam).then(resolve, err => {
628
+ // If the name already exists, we'll try again
629
+ const errorDetails = (0, generalHelpers_1.getProp)(err, "response.error.details");
630
+ if (Array.isArray(errorDetails) && errorDetails.length > 0) {
631
+ const nameNotAvailMsg = "You already have a group named '" +
632
+ groupItem.title +
633
+ "'. Try a different name.";
634
+ if (errorDetails.indexOf(nameNotAvailMsg) >= 0) {
635
+ templateDictionary.user.groups.push({
636
+ title: groupItem.title
637
+ });
638
+ createUniqueGroup(title, groupItem, templateDictionary, authentication).then(resolve, reject);
639
+ }
640
+ else {
641
+ reject(err);
642
+ }
643
+ }
644
+ else {
645
+ // Otherwise, error out
646
+ reject(err);
647
+ }
648
+ });
649
+ }, e => reject(e));
650
+ });
651
+ }
652
+ exports.createUniqueGroup = createUniqueGroup;
653
+ /**
654
+ * Gets the ids of the dependencies of an AGOL feature service item.
655
+ * Dependencies will only exist when the service is a view.
656
+ *
657
+ * @param itemTemplate Template of item to be created
658
+ * @param authentication Credentials for the request
659
+ * @returns A promise that will resolve a list of dependencies
660
+ */
661
+ function extractDependencies(itemTemplate, authentication) {
662
+ const dependencies = [];
663
+ return new Promise((resolve, reject) => {
664
+ // Get service dependencies when the item is a view
665
+ // This step is skipped for tracker views as they will already have a source service in the org
666
+ if (itemTemplate.properties.service.isView && itemTemplate.item.url && !(0, trackingHelpers_1.isTrackingViewTemplate)(itemTemplate)) {
667
+ (0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(itemTemplate.item.url) + "sources?f=json", {
668
+ authentication: authentication
669
+ }).then(response => {
670
+ /* istanbul ignore else */
671
+ if (response && response.services) {
672
+ response.services.forEach((layer) => {
673
+ dependencies.push({
674
+ id: layer.serviceItemId,
675
+ name: layer.name
676
+ });
677
+ });
678
+ }
679
+ resolve(dependencies);
680
+ }, e => reject((0, generalHelpers_1.fail)(e)));
681
+ }
682
+ else if ((0, workforceHelpers_1.isWorkforceProject)(itemTemplate)) {
683
+ resolve((0, workforceHelpers_1.getWorkforceDependencies)(itemTemplate, dependencies));
684
+ }
685
+ else {
686
+ resolve(dependencies);
687
+ }
688
+ });
689
+ }
690
+ exports.extractDependencies = extractDependencies;
691
+ /**
692
+ * Get json info for the services layers
693
+ *
694
+ * @param serviceUrl the url for the service
695
+ * @param layerList list of base layer info
696
+ * @param authentication Credentials for the request
697
+ * @returns A promise that will resolve a list of dependencies
698
+ */
699
+ function getLayers(serviceUrl, layerList, authentication) {
700
+ return new Promise((resolve, reject) => {
701
+ if (layerList.length === 0) {
702
+ resolve([]);
703
+ }
704
+ // get the admin URL
705
+ serviceUrl = serviceUrl.replace("/rest/services", "/rest/admin/services");
706
+ const requestsDfd = [];
707
+ layerList.forEach(layer => {
708
+ const requestOptions = {
709
+ authentication: authentication
710
+ };
711
+ requestsDfd.push((0, arcgis_rest_request_1.request)((0, generalHelpers_1.checkUrlPathTermination)(serviceUrl) + layer["id"] + "?f=json", requestOptions));
712
+ });
713
+ // Wait until all layers are heard from
714
+ Promise.all(requestsDfd).then(layers => resolve(layers), e => reject((0, generalHelpers_1.fail)(e)));
715
+ });
716
+ }
717
+ exports.getLayers = getLayers;
718
+ /**
719
+ * Add additional options to a layers definition.
720
+ *
721
+ * @param args The IPostProcessArgs for the request(s)
722
+ * @param isPortal boolean to indicate if we are deploying to portal
723
+ *
724
+ * @returns An array of update instructions
725
+ * @private
726
+ */
727
+ function getLayerUpdates(args, isPortal) {
728
+ const adminUrl = args.itemTemplate.item.url.replace("rest/services", "rest/admin/services");
729
+ const updates = [];
730
+ const refresh = _getUpdate(adminUrl, null, null, args, "refresh");
731
+ updates.push(refresh);
732
+ Object.keys(args.objects).forEach(id => {
733
+ const obj = Object.assign({}, args.objects[id]);
734
+ // These properties cannot be set in the update definition when working with portal
735
+ if (isPortal) {
736
+ (0, generalHelpers_1.deleteProps)(obj, ["type", "id", "relationships", "sourceServiceFields"]);
737
+ }
738
+ // handle definition deletes
739
+ // removes previous editFieldsInfo fields if their names were changed
740
+ if (obj.hasOwnProperty("deleteFields")) {
741
+ updates.push(_getUpdate(adminUrl, id, obj, args, "delete"));
742
+ (0, generalHelpers_1.deleteProp)(obj, "deleteFields");
743
+ updates.push(_getUpdate(adminUrl, null, null, args, "refresh"));
744
+ }
745
+ });
746
+ // issue: #706
747
+ // Add source service relationships
748
+ // views will now always add all layers in a single call and will inherit the relationships from the source service
749
+ if (!args.itemTemplate.properties.service.isView) {
750
+ const relUpdates = _getRelationshipUpdates({
751
+ message: "updated layer relationships",
752
+ objects: args.objects,
753
+ itemTemplate: args.itemTemplate,
754
+ authentication: args.authentication
755
+ });
756
+ // issue: #724
757
+ // In portal the order the relationships are added needs to follow the layer order
758
+ // otherwise the relationship IDs will be reset
759
+ relUpdates.layers = _sortRelationships(args.itemTemplate.properties.layers, args.itemTemplate.properties.tables, relUpdates);
760
+ /* istanbul ignore else */
761
+ if (relUpdates.layers.length > 0) {
762
+ updates.push(_getUpdate(adminUrl, null, relUpdates, args, "add"));
763
+ updates.push(refresh);
764
+ }
765
+ // handle contingent values
766
+ const contingentValuesUpdates = _getContingentValuesUpdates({
767
+ message: "add layer contingent values",
768
+ objects: args.objects,
769
+ itemTemplate: args.itemTemplate,
770
+ authentication: args.authentication
771
+ });
772
+ /* istanbul ignore else */
773
+ if (contingentValuesUpdates.length > 0) {
774
+ contingentValuesUpdates.forEach(conUpdate => {
775
+ updates.push(_getUpdate(adminUrl + conUpdate.id, null, conUpdate.contingentValues, args, "add"));
776
+ });
777
+ }
778
+ }
779
+ return updates.length === 1 ? [] : updates;
780
+ }
781
+ exports.getLayerUpdates = getLayerUpdates;
782
+ /**
783
+ * Sorts relationships based on order of supporting layers and tables in the service definition
784
+ *
785
+ * @param layers the layers from the service
786
+ * @param tables the tables from the service
787
+ * @param relUpdates the relationships to add for the service
788
+ *
789
+ * @returns An array with relationships that have been sorted
790
+ * @private
791
+ */
792
+ function _sortRelationships(layers, tables, relUpdates) {
793
+ const ids = [].concat(layers.map((l) => l.id), tables.map((t) => t.id));
794
+ // In portal the order the relationships are added needs to follow the layer order
795
+ // otherwise the relationship IDs will be reset
796
+ const _relUpdateLayers = [];
797
+ ids.forEach(id => {
798
+ relUpdates.layers.some((relUpdate) => {
799
+ if (id === relUpdate.id) {
800
+ _relUpdateLayers.push(relUpdate);
801
+ return true;
802
+ }
803
+ else {
804
+ return false;
805
+ }
806
+ });
807
+ });
808
+ return _relUpdateLayers;
809
+ }
810
+ exports._sortRelationships = _sortRelationships;
811
+ /**
812
+ * Add additional options to a layers definition
813
+ *
814
+ * Added retry due to some solutions failing to deploy in specific orgs/hives
815
+ *
816
+ *
817
+ * @param Update will contain either add, update, or delete from service definition call
818
+ * @param skipRetry defaults to false. when true the retry logic will be ignored
819
+ * @returns A promise that will resolve when service definition call has completed
820
+ * @private
821
+ */
822
+ /* istanbul ignore else */
823
+ function getRequest(update, skipRetry = false, useAsync = false) {
824
+ return new Promise((resolve, reject) => {
825
+ const options = {
826
+ params: update.params,
827
+ authentication: update.args.authentication
828
+ };
829
+ /* istanbul ignore else */
830
+ if ((useAsync && update.url.indexOf("addToDefinition") > -1) ||
831
+ update.url.indexOf("updateDefinition") > -1 ||
832
+ update.url.indexOf("deleteFromDefinition") > -1) {
833
+ options.params = { ...options.params, async: true };
834
+ }
835
+ (0, arcgis_rest_request_1.request)(update.url, options).then(result => {
836
+ checkRequestStatus(result, options.authentication).then(() => resolve(null), e => reject((0, generalHelpers_1.fail)(e)));
837
+ }, (e) => {
838
+ if (!skipRetry) {
839
+ getRequest(update, true, true).then(() => resolve(), e => reject(e));
840
+ }
841
+ else {
842
+ reject(e);
843
+ }
844
+ });
845
+ });
846
+ }
847
+ exports.getRequest = getRequest;
848
+ /**
849
+ * Fills in missing data, including full layer and table definitions, in a feature services' definition.
850
+ *
851
+ * @param itemTemplate Feature service item, data, dependencies definition to be modified
852
+ * @param authentication Credentials for the request to AGOL
853
+ * @returns A promise that will resolve when fullItem has been updated
854
+ * @private
855
+ */
856
+ function getServiceLayersAndTables(itemTemplate, authentication) {
857
+ return new Promise((resolve, reject) => {
858
+ // To have enough information for reconstructing the service, we'll supplement
859
+ // the item and data sections with sections for the service, full layers, and
860
+ // full tables
861
+ // Extra steps must be taken for workforce version 2
862
+ const isWorkforceService = (0, workforceHelpers_1.isWorkforceProject)(itemTemplate);
863
+ // Get the service description
864
+ if (itemTemplate.item.url) {
865
+ getFeatureServiceProperties(itemTemplate.item.url, authentication, isWorkforceService).then(properties => {
866
+ itemTemplate.properties = properties;
867
+ resolve(itemTemplate);
868
+ }, e => reject((0, generalHelpers_1.fail)(e)));
869
+ }
870
+ else {
871
+ resolve(itemTemplate);
872
+ }
873
+ });
874
+ }
875
+ exports.getServiceLayersAndTables = getServiceLayersAndTables;
876
+ /**
877
+ * Get service properties for the given url and update key props
878
+ *
879
+ * @param serviceUrl the feature service url
880
+ * @param authentication Credentials for the request to AGOL
881
+ * @param workforceService boolean to indicate if extra workforce service steps should be handled
882
+ * @returns A promise that will resolve with the service properties
883
+ * @private
884
+ */
885
+ function getFeatureServiceProperties(serviceUrl, authentication, workforceService = false) {
886
+ return new Promise((resolve, reject) => {
887
+ const properties = {
888
+ service: {},
889
+ layers: [],
890
+ tables: []
891
+ };
892
+ // get the admin URL
893
+ serviceUrl = serviceUrl.replace("/rest/services", "/rest/admin/services");
894
+ // Get the service description
895
+ (0, arcgis_rest_request_1.request)(serviceUrl + "?f=json", {
896
+ authentication: authentication
897
+ }).then(serviceData => {
898
+ properties.service = _parseAdminServiceData(serviceData);
899
+ // Copy cacheMaxAge to top level so that AGO sees it when deploying the service
900
+ // serviceData may have set it if there isn't an adminServiceInfo
901
+ /* istanbul ignore else */
902
+ if (serviceData.adminServiceInfo?.cacheMaxAge) {
903
+ properties.service.cacheMaxAge =
904
+ serviceData.adminServiceInfo.cacheMaxAge;
905
+ }
906
+ // Move the layers and tables out of the service's data section
907
+ /* istanbul ignore else */
908
+ if (serviceData.layers) {
909
+ properties.layers = serviceData.layers;
910
+ // Fill in properties that the service layer doesn't provide
911
+ // and remove properties that should not exist in the template
912
+ properties.layers.forEach(layer => {
913
+ layer.serviceItemId = properties.service.serviceItemId;
914
+ layer.extent = null;
915
+ (0, featureServiceHelpers_1.removeLayerOptimization)(layer);
916
+ });
917
+ }
918
+ delete serviceData.layers;
919
+ /* istanbul ignore else */
920
+ if (serviceData.tables) {
921
+ properties.tables = serviceData.tables;
922
+ // Fill in properties that the service layer doesn't provide
923
+ properties.tables.forEach(table => {
924
+ table.serviceItemId = properties.service.serviceItemId;
925
+ table.extent = null;
926
+ });
927
+ }
928
+ delete serviceData.tables;
929
+ // Ensure solution items have unique indexes on relationship key fields
930
+ _updateIndexesForRelationshipKeyFields(properties);
931
+ (0, featureServiceHelpers_1.processContingentValues)(properties, serviceUrl, authentication).then(() => {
932
+ if (workforceService) {
933
+ (0, workforceHelpers_1.getWorkforceServiceInfo)(properties, serviceUrl, authentication).then(resolve, reject);
934
+ }
935
+ else {
936
+ resolve(properties);
937
+ }
938
+ }, (e) => reject((0, generalHelpers_1.fail)(e)));
939
+ }, (e) => reject((0, generalHelpers_1.fail)(e)));
940
+ });
941
+ }
942
+ exports.getFeatureServiceProperties = getFeatureServiceProperties;
943
+ /**
944
+ * Parses the layers array and will filter subsets of Layers and Tables
945
+ * Layers and Tables are both returned in the layers array when we access a feature service from the admin api.
946
+ *
947
+ * @param adminData The data of the feature service
948
+ * @returns A mutated version of the provided adminData
949
+ * @private
950
+ */
951
+ function _parseAdminServiceData(adminData) {
952
+ const layers = adminData.layers || [];
953
+ const tables = adminData.tables || [];
954
+ (0, generalHelpers_1.setCreateProp)(adminData, "layers", layers.filter(l => l.type === "Feature Layer"));
955
+ // TODO understand if the concat is necessary.
956
+ // Not sure if the admin api will ever actually return a tables collection here.
957
+ (0, generalHelpers_1.setCreateProp)(adminData, "tables", tables.concat(layers.filter(l => l.type === "Table")));
958
+ return adminData;
959
+ }
960
+ exports._parseAdminServiceData = _parseAdminServiceData;
961
+ /**
962
+ * livingatlas designation test.
963
+ * These layers should not be templatized or depolyed
964
+ *
965
+ * @param groupDesignations the items group designations to evaluate
966
+ * @returns A boolean indicating if the invalid designation is found in the item info
967
+ */
968
+ function hasInvalidGroupDesignations(groupDesignations) {
969
+ const invalidGroupDesignations = ["livingatlas"];
970
+ return groupDesignations
971
+ ? invalidGroupDesignations.indexOf(groupDesignations) > -1
972
+ : false;
973
+ }
974
+ exports.hasInvalidGroupDesignations = hasInvalidGroupDesignations;
975
+ /**
976
+ * Removes a folder from AGO.
977
+ *
978
+ * @param folderId Id of a folder to delete
979
+ * @param authentication Credentials for the request to AGO
980
+ * @returns A promise that will resolve with the result of the request
981
+ */
982
+ function removeFolder(folderId, authentication) {
983
+ return new Promise((resolve, reject) => {
984
+ const requestOptions = {
985
+ folderId: folderId,
986
+ authentication: authentication
987
+ };
988
+ (0, arcgis_rest_portal_1.removeFolder)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
989
+ });
990
+ }
991
+ exports.removeFolder = removeFolder;
992
+ /**
993
+ * Removes a group from AGO.
994
+ *
995
+ * @param groupId Id of a group to delete
996
+ * @param authentication Credentials for the request to AGO
997
+ * @returns A promise that will resolve with the result of the request
998
+ */
999
+ function removeGroup(groupId, authentication) {
1000
+ return new Promise((resolve, reject) => {
1001
+ const requestOptions = {
1002
+ id: groupId,
1003
+ authentication: authentication
1004
+ };
1005
+ (0, arcgis_rest_portal_1.removeGroup)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
1006
+ });
1007
+ }
1008
+ exports.removeGroup = removeGroup;
1009
+ /**
1010
+ * Removes an item from AGO.
1011
+ *
1012
+ * @param itemId Id of an item to delete
1013
+ * @param authentication Credentials for the request to AGO
1014
+ * @returns A promise that will resolve with the result of the request
1015
+ */
1016
+ function removeItem(itemId, authentication) {
1017
+ return new Promise((resolve, reject) => {
1018
+ const requestOptions = {
1019
+ id: itemId,
1020
+ authentication: authentication
1021
+ };
1022
+ (0, arcgis_rest_portal_1.removeItem)(requestOptions).then(result => (result.success ? resolve(result) : reject(result)), reject);
1023
+ });
1024
+ }
1025
+ exports.removeItem = removeItem;
1026
+ /**
1027
+ * Removes an item or group from AGO.
1028
+ *
1029
+ * @param itemId Id of an item or group to delete
1030
+ * @param authentication Credentials for the request to AGO
1031
+ * @returns A promise that will resolve with the result of the request
1032
+ */
1033
+ function removeItemOrGroup(itemId, authentication) {
1034
+ return new Promise((resolve, reject) => {
1035
+ removeItem(itemId, authentication).then(resolve, error => {
1036
+ removeGroup(itemId, authentication).then(resolve, () => reject(error));
1037
+ });
1038
+ });
1039
+ }
1040
+ exports.removeItemOrGroup = removeItemOrGroup;
1041
+ /**
1042
+ * Searches for items matching a query and that the caller has access to.
1043
+ *
1044
+ * @param search Search string (e.g., "q=redlands+map") or a more detailed structure that can include authentication
1045
+ * @returns Promise resolving with search results
1046
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/search.htm
1047
+ */
1048
+ function searchItems(search) {
1049
+ return (0, arcgis_rest_portal_1.searchItems)(search);
1050
+ }
1051
+ exports.searchItems = searchItems;
1052
+ /**
1053
+ * Searches for items matching a query and that the caller has access to, continuing recursively until done.
1054
+ *
1055
+ * @param search Search string (e.g., "q=redlands+map") or a more detailed structure that can include authentication
1056
+ * @param accumulatedResponse Response built from previous requests
1057
+ * @returns Promise resolving with search results
1058
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/search.htm
1059
+ */
1060
+ function searchAllItems(search, accumulatedResponse) {
1061
+ // Convert the search into an ISearchOptions
1062
+ const searchOptions = convertToISearchOptions(search);
1063
+ // Provide a base into which results can be concatenated
1064
+ const completeResponse = accumulatedResponse ? accumulatedResponse : {
1065
+ query: searchOptions.q,
1066
+ start: 1,
1067
+ num: 100,
1068
+ nextStart: -1,
1069
+ total: 0,
1070
+ results: []
1071
+ };
1072
+ return new Promise((resolve, reject) => {
1073
+ searchItems(search).then(response => {
1074
+ completeResponse.results = completeResponse.results.concat(response.results);
1075
+ completeResponse.num = completeResponse.total = completeResponse.results.length;
1076
+ if (response.nextStart > 0) {
1077
+ // Insert nextStart into next query
1078
+ searchOptions.start = response.nextStart;
1079
+ resolve(searchAllItems(searchOptions, completeResponse));
1080
+ }
1081
+ else {
1082
+ resolve(completeResponse);
1083
+ }
1084
+ }, e => reject(e));
1085
+ });
1086
+ }
1087
+ exports.searchAllItems = searchAllItems;
1088
+ /**
1089
+ * Searches for groups matching criteria.
1090
+ *
1091
+ * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1092
+ * @param authentication Credentials for the request to AGO
1093
+ * @param additionalSearchOptions Adjustments to search, such as tranche size
1094
+ * @returns A promise that will resolve with a structure with a tranche of results and
1095
+ * describing how many items are available
1096
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/group-search.htm
1097
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1098
+ */
1099
+ function searchGroups(searchString, authentication, additionalSearchOptions) {
1100
+ const searchOptions = {
1101
+ q: searchString,
1102
+ params: {
1103
+ ...additionalSearchOptions
1104
+ },
1105
+ authentication: authentication
1106
+ };
1107
+ return (0, arcgis_rest_portal_1.searchGroups)(searchOptions);
1108
+ }
1109
+ exports.searchGroups = searchGroups;
1110
+ /**
1111
+ * Searches for groups matching criteria recurusively.
1112
+ *
1113
+ * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1114
+ * @param authentication Credentials for the request to AGO
1115
+ * @param groups List of groups that have been found from previous requests
1116
+ * @param inPagingParams The paging params for the recurisve searching
1117
+ *
1118
+ * @returns A promise that will resolve with all groups that meet the search criteria
1119
+ */
1120
+ function searchAllGroups(searchString, authentication, groups, inPagingParams) {
1121
+ const pagingParams = inPagingParams ? inPagingParams : {
1122
+ start: 1,
1123
+ num: 24
1124
+ };
1125
+ const additionalSearchOptions = {
1126
+ sortField: "title",
1127
+ sortOrder: "asc",
1128
+ ...pagingParams
1129
+ };
1130
+ // Provide a base onto which results can be concatenated
1131
+ let finalResults = groups ? groups : [];
1132
+ return new Promise((resolve, reject) => {
1133
+ searchGroups(searchString, authentication, additionalSearchOptions).then(response => {
1134
+ finalResults = finalResults.concat(response.results);
1135
+ if (response.nextStart > 0) {
1136
+ pagingParams.start = response.nextStart;
1137
+ resolve(searchAllGroups(searchString, authentication, finalResults, pagingParams));
1138
+ }
1139
+ else {
1140
+ resolve(finalResults);
1141
+ }
1142
+ }, e => reject(e));
1143
+ });
1144
+ }
1145
+ exports.searchAllGroups = searchAllGroups;
1146
+ /**
1147
+ * Searches for group contents matching criteria recursively.
1148
+ *
1149
+ * @param groupId Group whose contents are to be searched
1150
+ * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1151
+ * @param authentication Credentials for the request to AGO
1152
+ * @param additionalSearchOptions Adjustments to search, such as tranche size and categories of interest; categories
1153
+ * are supplied as an array: each array element consists of one or more categories to be ORed; array elements are ANDed
1154
+ * @param portalUrl Rest Url of the portal to perform the search
1155
+ * @param accumulatedResponse Response built from previous requests
1156
+ * @returns A promise that will resolve with a structure with a tranche of results and
1157
+ * describing how many items are available
1158
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/group-content-search.htm
1159
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1160
+ */
1161
+ function searchGroupAllContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl, accumulatedResponse) {
1162
+ additionalSearchOptions = additionalSearchOptions ? additionalSearchOptions : {};
1163
+ // Provide a base into which results can be concatenated
1164
+ const completeResponse = accumulatedResponse ? accumulatedResponse : {
1165
+ query: searchString,
1166
+ start: 1,
1167
+ num: 100,
1168
+ nextStart: -1,
1169
+ total: 0,
1170
+ results: []
1171
+ };
1172
+ return new Promise((resolve, reject) => {
1173
+ searchGroupContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl).then(response => {
1174
+ completeResponse.results = completeResponse.results.concat(response.results);
1175
+ completeResponse.num = completeResponse.total = completeResponse.results.length;
1176
+ if (response.nextStart > 0) {
1177
+ additionalSearchOptions.start = response.nextStart;
1178
+ resolve(searchGroupAllContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl, completeResponse));
1179
+ }
1180
+ else {
1181
+ resolve(completeResponse);
1182
+ }
1183
+ }, e => reject(e));
1184
+ });
1185
+ }
1186
+ exports.searchGroupAllContents = searchGroupAllContents;
1187
+ /**
1188
+ * Searches for group contents matching criteria.
1189
+ *
1190
+ * @param groupId Group whose contents are to be searched
1191
+ * @param searchString Text for which to search, e.g., 'redlands+map', 'type:"Web Map" -type:"Web Mapping Application"'
1192
+ * @param authentication Credentials for the request to AGO
1193
+ * @param additionalSearchOptions Adjustments to search, such as tranche size and categories of interest; categories
1194
+ * are supplied as an array: each array element consists of one or more categories to be ORed; array elements are ANDed
1195
+ * @param portalUrl Rest Url of the portal to perform the search
1196
+ * @returns A promise that will resolve with a structure with a tranche of results and
1197
+ * describing how many items are available
1198
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/group-content-search.htm
1199
+ * @see https://developers.arcgis.com/rest/users-groups-and-items/search-reference.htm
1200
+ */
1201
+ function searchGroupContents(groupId, searchString, authentication, additionalSearchOptions, portalUrl) {
1202
+ const searchOptions = {
1203
+ groupId,
1204
+ q: searchString,
1205
+ params: Object.assign({
1206
+ num: 100
1207
+ }, additionalSearchOptions),
1208
+ authentication: authentication,
1209
+ portal: portalUrl
1210
+ };
1211
+ // If search options include `categories`, switch to new arcgis-rest-js format
1212
+ /* istanbul ignore else */
1213
+ if (Array.isArray(searchOptions.params.categories)) {
1214
+ searchOptions.params.categories = searchOptions.params.categories.map(andGroup => andGroup.split(","));
1215
+ }
1216
+ return (0, arcgis_rest_portal_1.searchGroupContent)(searchOptions);
1217
+ }
1218
+ exports.searchGroupContents = searchGroupContents;
1219
+ /**
1220
+ * Reassign ownership of a group
1221
+ *
1222
+ * @param groupId Group to remove users from
1223
+ * @param userName The new owner for the group
1224
+ * @param authentication Credentials for the request to
1225
+ *
1226
+ * @returns A promise that will resolve after the group ownership has been assigned
1227
+ *
1228
+ */
1229
+ function reassignGroup(groupId, userName, authentication) {
1230
+ const requestOptions = {
1231
+ authentication: authentication,
1232
+ params: {
1233
+ targetUsername: userName
1234
+ }
1235
+ };
1236
+ return (0, arcgis_rest_request_1.request)(`${authentication.portal}/community/groups/${groupId}/reassign`, requestOptions);
1237
+ }
1238
+ exports.reassignGroup = reassignGroup;
1239
+ /**
1240
+ * Remove users from a group
1241
+ *
1242
+ * @param groupId Group to remove users from
1243
+ * @param users List of users to remove from the group
1244
+ * @param authentication Credentials for the request to
1245
+ *
1246
+ * @returns A promise that will resolve after the users have been removed
1247
+ *
1248
+ */
1249
+ function removeUsers(groupId, users, authentication) {
1250
+ return (0, arcgis_rest_portal_1.removeGroupUsers)({
1251
+ id: groupId,
1252
+ users,
1253
+ authentication
1254
+ });
1255
+ }
1256
+ exports.removeUsers = removeUsers;
1257
+ /**
1258
+ * Shares an item to the defined group
1259
+ *
1260
+ * @param groupId Group to share with
1261
+ * @param id the item id to share with the group
1262
+ * @param destinationAuthentication Credentials for the request to AGO
1263
+ * @param owner owner of the group when sharing tracking items (can be different from the deploying user)
1264
+ *
1265
+ * @returns A promise that will resolve after the item has been shared
1266
+ *
1267
+ */
1268
+ function shareItem(groupId, id, destinationAuthentication, owner) {
1269
+ return new Promise((resolve, reject) => {
1270
+ const shareOptions = {
1271
+ groupId,
1272
+ id,
1273
+ authentication: destinationAuthentication
1274
+ };
1275
+ /* istanbul ignore else */
1276
+ if (owner) {
1277
+ shareOptions.owner = owner;
1278
+ }
1279
+ (0, arcgis_rest_portal_1.shareItemWithGroup)(shareOptions).then(() => resolve(null), (e) => reject((0, generalHelpers_1.fail)(e)));
1280
+ });
1281
+ }
1282
+ exports.shareItem = shareItem;
1283
+ /**
1284
+ * Updates an item.
1285
+ *
1286
+ * @param itemInfo The base info of an item; note that this content will be serialized, which doesn't work
1287
+ * for binary content
1288
+ * @param authentication Credentials for request
1289
+ * @param folderId Item's folder
1290
+ * @param additionalParams Updates that are put under the `params` property, which is not serialized
1291
+ * @return
1292
+ */
1293
+ function updateItem(itemInfo, authentication, folderId, additionalParams) {
1294
+ return new Promise((resolve, reject) => {
1295
+ const updateOptions = {
1296
+ item: itemInfo,
1297
+ folderId: folderId,
1298
+ authentication: authentication,
1299
+ params: {
1300
+ ...(additionalParams ?? {})
1301
+ }
1302
+ };
1303
+ (0, arcgis_rest_portal_1.updateItem)(updateOptions).then(response => (response.success ? resolve(response) : reject(response)), err => reject(err));
1304
+ });
1305
+ }
1306
+ exports.updateItem = updateItem;
1307
+ /**
1308
+ * Updates a group.
1309
+ *
1310
+ * @param groupInfo The base info of a group; note that this content will be serialized, which doesn't work
1311
+ * for binary content
1312
+ * @param authentication Credentials for request
1313
+ * @param additionalParams Updates that are put under the `params` property, which is not serialized
1314
+ * @returns A Promise that will resolve with the success/failure status of the request
1315
+ */
1316
+ function updateGroup(groupInfo, authentication, additionalParams) {
1317
+ return new Promise((resolve, reject) => {
1318
+ const updateOptions = {
1319
+ group: groupInfo,
1320
+ authentication,
1321
+ params: {
1322
+ ...(additionalParams ?? {})
1323
+ }
1324
+ };
1325
+ (0, arcgis_rest_portal_1.updateGroup)(updateOptions).then(response => (response.success ? resolve(response) : reject(response)), err => reject(err));
1326
+ });
1327
+ }
1328
+ exports.updateGroup = updateGroup;
1329
+ /**
1330
+ * Updates an item.
1331
+ *
1332
+ * @param itemInfo The base info of an item
1333
+ * @param data The items data section
1334
+ * @param authentication Credentials for requests
1335
+ * @param thumbnail optional thumbnail to update
1336
+ * @param access "public" or "org"
1337
+ * @return
1338
+ */
1339
+ function updateItemExtended(itemInfo, data, authentication, thumbnail, access, templateDictionary) {
1340
+ return new Promise((resolve, reject) => {
1341
+ const updateOptions = {
1342
+ item: itemInfo,
1343
+ params: {
1344
+ text: data || {} // AGO ignores update if `data` is empty
1345
+ },
1346
+ authentication: authentication
1347
+ };
1348
+ if (thumbnail) {
1349
+ updateOptions.params.thumbnail = thumbnail;
1350
+ }
1351
+ if ((0, trackingHelpers_1.isTrackingViewTemplate)(undefined, itemInfo) && templateDictionary) {
1352
+ updateOptions.owner = templateDictionary.locationTracking.owner;
1353
+ }
1354
+ (0, arcgis_rest_portal_1.updateItem)(updateOptions).then(result => {
1355
+ if (access && access !== "private") {
1356
+ // Set access if it is not AGOL default
1357
+ // Set the access manually since the access value in createItem appears to be ignored
1358
+ const accessOptions = {
1359
+ id: itemInfo.id,
1360
+ access: access === "public" ? "public" : "org",
1361
+ authentication: authentication
1362
+ };
1363
+ (0, arcgis_rest_portal_1.setItemAccess)(accessOptions).then(() => resolve(result), e => reject((0, generalHelpers_1.fail)(e)));
1364
+ }
1365
+ else {
1366
+ resolve(result);
1367
+ }
1368
+ }, e => reject((0, generalHelpers_1.fail)(e)));
1369
+ });
1370
+ }
1371
+ exports.updateItemExtended = updateItemExtended;
1372
+ /**
1373
+ * Update an item's base and data using a dictionary.
1374
+ *
1375
+ * @param {string} itemId The item ID
1376
+ * @param {any} templateDictionary The template dictionary
1377
+ * @param {UserSession} authentication The destination session info
1378
+ * @returns Promise resolving to successfulness of update
1379
+ */
1380
+ function updateItemTemplateFromDictionary(itemId, templateDictionary, authentication) {
1381
+ return new Promise((resolve, reject) => {
1382
+ // Fetch the items as stored in AGO
1383
+ Promise.all([
1384
+ (0, restHelpersGet_1.getItemBase)(itemId, authentication),
1385
+ (0, restHelpersGet_1.getItemDataAsJson)(itemId, authentication)
1386
+ ])
1387
+ .then(([item, data]) => {
1388
+ // Do they have any variables?
1389
+ if ((0, templatization_1.hasUnresolvedVariables)(item) || (0, templatization_1.hasUnresolvedVariables)(data)) {
1390
+ // Update if so
1391
+ const { item: updatedItem, data: updatedData } = (0, templatization_1.replaceInTemplate)({ item, data }, templateDictionary);
1392
+ _reportVariablesInItem(itemId, item.type, updatedItem, updatedData);
1393
+ return updateItemExtended(updatedItem, updatedData, authentication);
1394
+ }
1395
+ else {
1396
+ // Shortcut out if not
1397
+ return Promise.resolve({
1398
+ success: true,
1399
+ id: itemId
1400
+ });
1401
+ }
1402
+ })
1403
+ .then(result => resolve(result))
1404
+ .catch(error => reject(error));
1405
+ });
1406
+ }
1407
+ exports.updateItemTemplateFromDictionary = updateItemTemplateFromDictionary;
1408
+ /**
1409
+ * Updates the URL of an item.
1410
+ *
1411
+ * @param id AGOL id of item to update
1412
+ * @param url URL to assign to item's base section
1413
+ * @param authentication Credentials for the request
1414
+ * @returns A promise that will resolve with the item id when the item has been updated or an AGO-style JSON failure
1415
+ * response
1416
+ */
1417
+ function updateItemURL(id, url, authentication) {
1418
+ const numAttempts = 3;
1419
+ return _updateItemURL(id, url, authentication, numAttempts);
1420
+ }
1421
+ exports.updateItemURL = updateItemURL;
1422
+ // ------------------------------------------------------------------------------------------------------------------ //
1423
+ /**
1424
+ * Adds a data section to an item.
1425
+ *
1426
+ * @param itemId Id of item to receive data file
1427
+ * @param dataFile Data to be added
1428
+ * @param authentication Credentials for the request
1429
+ * @returns Promise reporting success or failure
1430
+ * @private
1431
+ */
1432
+ function _addItemDataFile(itemId, dataFile, authentication) {
1433
+ return new Promise((resolve, reject) => {
1434
+ const _addItemData = (data) => {
1435
+ addItemData(itemId, data, authentication).then(resolve, reject);
1436
+ };
1437
+ // Item data has to be submitted as text or JSON for those file types
1438
+ if (dataFile.type.startsWith("text/plain")) {
1439
+ (0, generalHelpers_1.blobToText)(dataFile).then(_addItemData, reject);
1440
+ }
1441
+ else if (dataFile.type === "application/json") {
1442
+ (0, generalHelpers_1.blobToJson)(dataFile).then(_addItemData, reject);
1443
+ }
1444
+ else {
1445
+ _addItemData(dataFile);
1446
+ }
1447
+ });
1448
+ }
1449
+ exports._addItemDataFile = _addItemDataFile;
1450
+ /**
1451
+ * Adds a metadata file to an item.
1452
+ *
1453
+ * @param itemId Id of item to receive data file
1454
+ * @param metadataFile Metadata to be added
1455
+ * @param authentication Credentials for the request
1456
+ * @returns Promise reporting success or failure
1457
+ * @private
1458
+ */
1459
+ function _addItemMetadataFile(itemId, metadataFile, authentication) {
1460
+ return new Promise((resolve, reject) => {
1461
+ const addMetadataOptions = {
1462
+ item: {
1463
+ id: itemId
1464
+ },
1465
+ params: {
1466
+ // Pass metadata in via params because item property is serialized, which discards a blob
1467
+ metadata: metadataFile
1468
+ },
1469
+ authentication: authentication
1470
+ };
1471
+ (0, arcgis_rest_portal_1.updateItem)(addMetadataOptions).then(resolve, reject);
1472
+ });
1473
+ }
1474
+ exports._addItemMetadataFile = _addItemMetadataFile;
1475
+ /**
1476
+ * Accumulates the number of relationships in a collection of layers.
1477
+ *
1478
+ * @param List of layers to examine
1479
+ * @returns The number of relationships
1480
+ * @private
1481
+ */
1482
+ function _countRelationships(layers) {
1483
+ const reducer = (accumulator, currentLayer) => accumulator +
1484
+ (currentLayer.relationships ? currentLayer.relationships.length : 0);
1485
+ return layers.reduce(reducer, 0);
1486
+ }
1487
+ exports._countRelationships = _countRelationships;
1488
+ /**
1489
+ * Gets the full definitions of the layers affiliated with a hosted service.
1490
+ *
1491
+ * @param serviceUrl URL to hosted service
1492
+ * @param layerList List of layers at that service...must contain id
1493
+ * @param authentication Credentials for the request
1494
+ * @returns A promise that will resolve with a list of the layers from the admin api
1495
+ * @private
1496
+ */
1497
+ function _getCreateServiceOptions(newItemTemplate, authentication, templateDictionary) {
1498
+ return new Promise((resolve, reject) => {
1499
+ const serviceInfo = newItemTemplate.properties;
1500
+ const folderId = templateDictionary.folderId;
1501
+ const isPortal = templateDictionary.isPortal;
1502
+ const itemId = newItemTemplate.itemId;
1503
+ (0, featureServiceHelpers_1.validateSpatialReferenceAndExtent)(serviceInfo, newItemTemplate, templateDictionary);
1504
+ const fallbackExtent = _getFallbackExtent(serviceInfo, templateDictionary);
1505
+ const params = {};
1506
+ const itemInfo = {
1507
+ title: newItemTemplate.item.title,
1508
+ name: newItemTemplate.item.name
1509
+ };
1510
+ const _item = {
1511
+ ...itemInfo,
1512
+ preserveLayerIds: true
1513
+ };
1514
+ const createOptions = {
1515
+ item: _item,
1516
+ folderId,
1517
+ params,
1518
+ authentication: authentication
1519
+ };
1520
+ createOptions.item = !(0, trackingHelpers_1.isTrackingViewTemplate)(newItemTemplate) ?
1521
+ _setItemProperties(createOptions.item, newItemTemplate, serviceInfo, params, isPortal) :
1522
+ (0, trackingHelpers_1.setTrackingOptions)(newItemTemplate, createOptions, templateDictionary);
1523
+ // project the portals extent to match that of the service
1524
+ convertExtentWithFallback(templateDictionary.organization.defaultExtent, fallbackExtent, serviceInfo.service.spatialReference, templateDictionary.organization.helperServices.geometry.url, authentication).then(extent => {
1525
+ templateDictionary[itemId].solutionExtent = extent;
1526
+ (0, featureServiceHelpers_1.setDefaultSpatialReference)(templateDictionary, itemId, extent.spatialReference);
1527
+ createOptions.item = (0, templatization_1.replaceInTemplate)(createOptions.item, templateDictionary);
1528
+ createOptions.params = (0, templatization_1.replaceInTemplate)(createOptions.params, templateDictionary);
1529
+ if (newItemTemplate.item.thumbnail) {
1530
+ // Pass thumbnail file in via params because item property is serialized, which discards a blob
1531
+ createOptions.params.thumbnail = newItemTemplate.item.thumbnail;
1532
+ }
1533
+ resolve(createOptions);
1534
+ }, e => reject((0, generalHelpers_1.fail)(e)));
1535
+ });
1536
+ }
1537
+ exports._getCreateServiceOptions = _getCreateServiceOptions;
1538
+ /**
1539
+ * When the services spatial reference does not match that of it's default extent
1540
+ * use the out SRs default extent if it exists in the templateDictionary
1541
+ * this should be set when adding a custom out wkid to the params before calling deploy
1542
+ * this will help avoid situations where the orgs default extent and default world extent
1543
+ * will not project successfully to the out SR
1544
+ *
1545
+ * @param serviceInfo the object that contains the spatial reference to evaluate
1546
+ * @param templateDictionary the template dictionary
1547
+ * @returns the extent to use as the fallback
1548
+ * @private
1549
+ */
1550
+ function _getFallbackExtent(serviceInfo, templateDictionary) {
1551
+ const serviceSR = serviceInfo.service.spatialReference;
1552
+ const serviceInfoWkid = (0, generalHelpers_1.getProp)(serviceInfo, "defaultExtent.spatialReference.wkid");
1553
+ const customDefaultExtent = (0, generalHelpers_1.getProp)(templateDictionary, "params.defaultExtent");
1554
+ return serviceInfoWkid && serviceInfoWkid === serviceSR.wkid
1555
+ ? serviceInfo.defaultExtent
1556
+ : customDefaultExtent
1557
+ ? customDefaultExtent
1558
+ : serviceInfo.defaultExtent;
1559
+ }
1560
+ exports._getFallbackExtent = _getFallbackExtent;
1561
+ /**
1562
+ * Add relationships to all layers in one call to retain fully functioning composite relationships
1563
+ *
1564
+ * @param args The IPostProcessArgs for the request(s)
1565
+ * @returns Any relationships that should be updated for the service
1566
+ * @private
1567
+ */
1568
+ function _getRelationshipUpdates(args) {
1569
+ const rels = {
1570
+ layers: []
1571
+ };
1572
+ Object.keys(args.objects).forEach((k) => {
1573
+ const obj = args.objects[k];
1574
+ /* istanbul ignore else */
1575
+ if (obj.relationships && obj.relationships.length > 0) {
1576
+ rels.layers.push({
1577
+ id: obj.id,
1578
+ relationships: obj.relationships
1579
+ });
1580
+ }
1581
+ (0, generalHelpers_1.deleteProp)(obj, "relationships");
1582
+ });
1583
+ return rels;
1584
+ }
1585
+ exports._getRelationshipUpdates = _getRelationshipUpdates;
1586
+ /**
1587
+ * Get the stored contingent values and structure them to be added to the services layers.
1588
+ *
1589
+ * @param args The IPostProcessArgs for the request(s)
1590
+ * @returns Any contingent values that should be added to the service.
1591
+ * @private
1592
+ */
1593
+ function _getContingentValuesUpdates(args) {
1594
+ const contingentValues = [];
1595
+ Object.keys(args.objects).forEach((k) => {
1596
+ const obj = args.objects[k];
1597
+ /* istanbul ignore else */
1598
+ if (obj.contingentValues) {
1599
+ contingentValues.push({
1600
+ id: obj.id,
1601
+ contingentValues: obj.contingentValues
1602
+ });
1603
+ }
1604
+ (0, generalHelpers_1.deleteProp)(obj, "contingentValues");
1605
+ });
1606
+ return contingentValues;
1607
+ }
1608
+ exports._getContingentValuesUpdates = _getContingentValuesUpdates;
1609
+ /**
1610
+ * Get refresh, add, update, or delete definition info
1611
+ *
1612
+ * @param url the base admin url for the service
1613
+ * @param id the id of the layer
1614
+ * @param obj parameters for the request
1615
+ * @param args various arguments to help support the request
1616
+ * @param type type of update the request will handle
1617
+ * @returns IUpdate that has the request url and arguments
1618
+ * @private
1619
+ */
1620
+ function _getUpdate(url, id, obj, args, type) {
1621
+ const ops = {
1622
+ delete: {
1623
+ url: (0, generalHelpers_1.checkUrlPathTermination)(url) + id + "/deleteFromDefinition",
1624
+ params: {
1625
+ deleteFromDefinition: {
1626
+ fields: obj && obj.hasOwnProperty("deleteFields") ? obj.deleteFields : []
1627
+ }
1628
+ }
1629
+ },
1630
+ update: {
1631
+ url: (0, generalHelpers_1.checkUrlPathTermination)(url) +
1632
+ (id ? `${id}/updateDefinition` : "updateDefinition"),
1633
+ params: {
1634
+ updateDefinition: obj
1635
+ }
1636
+ },
1637
+ add: {
1638
+ url: (0, generalHelpers_1.checkUrlPathTermination)(url) + "addToDefinition",
1639
+ params: {
1640
+ addToDefinition: obj
1641
+ }
1642
+ },
1643
+ refresh: {
1644
+ url: (0, generalHelpers_1.checkUrlPathTermination)(url) + "refresh",
1645
+ params: {
1646
+ f: "json"
1647
+ }
1648
+ }
1649
+ };
1650
+ return {
1651
+ url: ops[type].url,
1652
+ params: ops[type].params,
1653
+ args: args
1654
+ };
1655
+ }
1656
+ exports._getUpdate = _getUpdate;
1657
+ /**
1658
+ * Changes just the domain part of a URL to lowercase.
1659
+ *
1660
+ * @param url URL to modify
1661
+ * @return Adjusted URL
1662
+ * @see From `getServerRootUrl` in arcgis-rest-js' ArcGISIdentityManager.ts
1663
+ * @private
1664
+ */
1665
+ function _lowercaseDomain(url) {
1666
+ if (!url) {
1667
+ return url;
1668
+ }
1669
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1670
+ const [_, protocol, domainAndPath] = url.match(/(https?:\/\/)(.+)/);
1671
+ const [domain, ...path] = domainAndPath.split("/");
1672
+ // Only the domain is lowercased because in some cases an org id might be
1673
+ // in the path which cannot be lowercased.
1674
+ return `${protocol}${domain.toLowerCase()}/${path.join("/")}`;
1675
+ }
1676
+ exports._lowercaseDomain = _lowercaseDomain;
1677
+ /**
1678
+ * Checks the two main parts of an item for unresolved variables and reports any found.
1679
+ *
1680
+ * @param base Item's base section
1681
+ * @param data Item's data section
1682
+ * @private
1683
+ */
1684
+ function _reportVariablesInItem(itemId, itemType, base, data) {
1685
+ const getUnresolved = (v) => {
1686
+ return JSON.stringify(v).match(/{{.+?}}/gim);
1687
+ };
1688
+ // Provide feedback about any remaining unresolved variables
1689
+ /* istanbul ignore else */
1690
+ if (base && (0, templatization_1.hasUnresolvedVariables)(base)) {
1691
+ console.log(itemId +
1692
+ " (" +
1693
+ itemType +
1694
+ ") contains variables in base: " +
1695
+ JSON.stringify(getUnresolved(base)));
1696
+ }
1697
+ /* istanbul ignore else */
1698
+ if (data && (0, templatization_1.hasUnresolvedVariables)(data)) {
1699
+ console.log(itemId +
1700
+ " (" +
1701
+ itemType +
1702
+ ") contains variables in data: " +
1703
+ JSON.stringify(getUnresolved(data)));
1704
+ }
1705
+ }
1706
+ exports._reportVariablesInItem = _reportVariablesInItem;
1707
+ /**
1708
+ * Updates a feature service item.
1709
+ *
1710
+ * @param item Item to update
1711
+ * @param itemTemplate item template for the new item
1712
+ * @param serviceInfo Service information
1713
+ * @param params arcgis-rest-js params to update
1714
+ * @param isPortal Is the service hosted in a portal?
1715
+ * @returns Updated item
1716
+ * @private
1717
+ */
1718
+ function _setItemProperties(item, itemTemplate, serviceInfo, params, isPortal) {
1719
+ // Set the capabilities
1720
+ const portalCapabilities = [
1721
+ "Create",
1722
+ "Query",
1723
+ "Editing",
1724
+ "Update",
1725
+ "Delete",
1726
+ "Uploads",
1727
+ "Sync",
1728
+ "Extract"
1729
+ ];
1730
+ const capabilities = (0, generalHelpers_1.getProp)(serviceInfo, "service.capabilities") || (isPortal ? "" : []);
1731
+ item.capabilities = isPortal
1732
+ ? capabilities
1733
+ .split(",")
1734
+ .filter((c) => portalCapabilities.indexOf(c) > -1)
1735
+ .join(",")
1736
+ : capabilities;
1737
+ if (serviceInfo.service.capabilities) {
1738
+ serviceInfo.service.capabilities = item.capabilities;
1739
+ }
1740
+ // Handle index update for any pre-published solution items that
1741
+ // have non-unique indexes on relationship key fields
1742
+ _updateIndexesForRelationshipKeyFields(serviceInfo);
1743
+ // set create options item properties
1744
+ const keyProperties = [
1745
+ "isView",
1746
+ "sourceSchemaChangesAllowed",
1747
+ "isUpdatableView",
1748
+ "capabilities",
1749
+ "isMultiServicesView"
1750
+ ];
1751
+ const deleteKeys = ["layers", "tables"];
1752
+ /* istanbul ignore else */
1753
+ if (isPortal) {
1754
+ // removed for issue #423 causing FS to fail to create
1755
+ deleteKeys.push("adminServiceInfo");
1756
+ }
1757
+ const itemKeys = Object.keys(item);
1758
+ const serviceKeys = Object.keys(serviceInfo.service);
1759
+ serviceKeys.forEach(k => {
1760
+ /* istanbul ignore else */
1761
+ if (itemKeys.indexOf(k) === -1 && deleteKeys.indexOf(k) < 0) {
1762
+ item[k] = serviceInfo.service[k];
1763
+ // These need to be included via params otherwise...
1764
+ // addToDef calls fail when adding adminLayerInfo
1765
+ /* istanbul ignore else */
1766
+ if (serviceInfo.service.isView && keyProperties.indexOf(k) > -1) {
1767
+ params[k] = serviceInfo.service[k];
1768
+ }
1769
+ }
1770
+ });
1771
+ // Enable editor tracking on layer with related tables is not supported.
1772
+ /* istanbul ignore else */
1773
+ if (item.isMultiServicesView &&
1774
+ (0, generalHelpers_1.getProp)(item, "editorTrackingInfo.enableEditorTracking")) {
1775
+ item.editorTrackingInfo.enableEditorTracking = false;
1776
+ params["editorTrackingInfo"] = item.editorTrackingInfo;
1777
+ }
1778
+ /* istanbul ignore else */
1779
+ if (isPortal) {
1780
+ // portal will fail when initialExtent is defined but null
1781
+ // removed for issue #449 causing FS to fail to create on portal
1782
+ /* istanbul ignore else */
1783
+ if (Object.keys(item).indexOf("initialExtent") > -1 &&
1784
+ !item.initialExtent) {
1785
+ (0, generalHelpers_1.deleteProp)(item, "initialExtent");
1786
+ }
1787
+ }
1788
+ return item;
1789
+ }
1790
+ exports._setItemProperties = _setItemProperties;
1791
+ /**
1792
+ * Set isUnique as true for indexes that reference origin relationship keyFields.
1793
+ *
1794
+ * @param serviceInfo Service information
1795
+ * @private
1796
+ */
1797
+ function _updateIndexesForRelationshipKeyFields(serviceInfo) {
1798
+ const layersAndTables = (serviceInfo.layers || []).concat(serviceInfo.tables || []);
1799
+ layersAndTables.forEach(item => {
1800
+ const relationships = item.relationships;
1801
+ const indexes = item.indexes;
1802
+ /* istanbul ignore else */
1803
+ if (relationships &&
1804
+ relationships.length > 0 &&
1805
+ indexes &&
1806
+ indexes.length > 0) {
1807
+ const keyFields = relationships.reduce((acc, v) => {
1808
+ /* istanbul ignore else */
1809
+ if (v.role === "esriRelRoleOrigin" &&
1810
+ v.keyField &&
1811
+ acc.indexOf(v.keyField) < 0) {
1812
+ acc.push(v.keyField);
1813
+ }
1814
+ return acc;
1815
+ }, []);
1816
+ indexes.map(i => {
1817
+ /* istanbul ignore else */
1818
+ if (keyFields.some(k => {
1819
+ const regEx = new RegExp(`\\b${k}\\b`);
1820
+ return regEx.test(i.fields);
1821
+ })) {
1822
+ i.isUnique = true;
1823
+ }
1824
+ return i;
1825
+ });
1826
+ }
1827
+ });
1828
+ }
1829
+ exports._updateIndexesForRelationshipKeyFields = _updateIndexesForRelationshipKeyFields;
1830
+ /**
1831
+ * Updates the URL of an item.
1832
+ *
1833
+ * @param id AGOL id of item to update
1834
+ * @param url URL to assign to item's base section
1835
+ * @param authentication Credentials for the request
1836
+ * @param numAttempts Number of times to try to set the URL if AGO says that it updated the URL, but really didn't
1837
+ * @returns A promise that will resolve with the item id when the item has been updated or an AGO-style JSON failure
1838
+ * response
1839
+ * @private
1840
+ */
1841
+ function _updateItemURL(id, url, authentication, numAttempts = 1) {
1842
+ // Introduce a lag because AGO update appears to choke with rapid subsequent calls
1843
+ const msLag = 1000;
1844
+ return new Promise((resolve, reject) => {
1845
+ // Update the item's URL
1846
+ const options = { item: { id, url }, authentication: authentication };
1847
+ (0, arcgis_rest_portal_1.updateItem)(options).then(result => {
1848
+ if (!result.success) {
1849
+ reject((0, generalHelpers_1.fail)(result));
1850
+ }
1851
+ else {
1852
+ // Get the item to see if the URL really changed; we'll delay a bit before testing because AGO
1853
+ // has a timing problem with URL updates
1854
+ setTimeout(() => {
1855
+ (0, arcgis_rest_portal_1.getItem)(id, { authentication: authentication }).then(item => {
1856
+ const iBrace = item.url.indexOf("{");
1857
+ if (iBrace > -1) {
1858
+ console.warn(id + " has template variable: " + item.url.substr(iBrace));
1859
+ }
1860
+ if (url === item.url) {
1861
+ resolve(id);
1862
+ }
1863
+ else {
1864
+ // If it fails, try again if we have sufficient attempts remaining
1865
+ const errorMsg = "URL not updated for " +
1866
+ item.type +
1867
+ " " +
1868
+ item.id +
1869
+ ": " +
1870
+ item.url +
1871
+ " (" +
1872
+ numAttempts +
1873
+ ")";
1874
+ if (--numAttempts > 0) {
1875
+ _updateItemURL(id, url, authentication, numAttempts).then(resolve, reject);
1876
+ }
1877
+ else {
1878
+ console.error(id + ": " + errorMsg + "; FAILED");
1879
+ reject(errorMsg);
1880
+ }
1881
+ }
1882
+ }, e => reject((0, generalHelpers_1.fail)(e)));
1883
+ }, msLag);
1884
+ }
1885
+ }, e => reject((0, generalHelpers_1.fail)(e)));
1886
+ });
1887
+ }
1888
+ exports._updateItemURL = _updateItemURL;
1884
1889
  //# sourceMappingURL=restHelpers.js.map