@esri/solution-common 4.1.2-alpha.0 → 5.0.0

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