@esri/solution-common 4.1.2 → 5.0.1

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