@esri/hub-common 8.18.0 → 8.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/es2017/api.js +5 -0
  2. package/dist/es2017/api.js.map +1 -1
  3. package/dist/es2017/content.js +341 -2
  4. package/dist/es2017/content.js.map +1 -1
  5. package/dist/es2017/downloads/build-existing-exports-portal-query.js +187 -0
  6. package/dist/es2017/downloads/build-existing-exports-portal-query.js.map +1 -0
  7. package/dist/es2017/downloads/index.js +2 -0
  8. package/dist/es2017/downloads/index.js.map +1 -0
  9. package/dist/es2017/index.js +2 -0
  10. package/dist/es2017/index.js.map +1 -1
  11. package/dist/es2017/request.js +8 -5
  12. package/dist/es2017/request.js.map +1 -1
  13. package/dist/es2017/sites/domains/_get-domain-service-url.js.map +1 -1
  14. package/dist/es2017/sites/domains/ensure-unique-domain-name.js +2 -1
  15. package/dist/es2017/sites/domains/ensure-unique-domain-name.js.map +1 -1
  16. package/dist/es2017/sites/domains/is-valid-domain.js +2 -1
  17. package/dist/es2017/sites/domains/is-valid-domain.js.map +1 -1
  18. package/dist/es2017/util.js +8 -0
  19. package/dist/es2017/util.js.map +1 -1
  20. package/dist/esm/api.js +5 -0
  21. package/dist/esm/api.js.map +1 -1
  22. package/dist/esm/content.js +342 -2
  23. package/dist/esm/content.js.map +1 -1
  24. package/dist/esm/downloads/build-existing-exports-portal-query.js +187 -0
  25. package/dist/esm/downloads/build-existing-exports-portal-query.js.map +1 -0
  26. package/dist/esm/downloads/index.js +2 -0
  27. package/dist/esm/downloads/index.js.map +1 -0
  28. package/dist/esm/index.js +2 -0
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/request.js +7 -4
  31. package/dist/esm/request.js.map +1 -1
  32. package/dist/esm/sites/domains/_get-domain-service-url.js.map +1 -1
  33. package/dist/esm/sites/domains/ensure-unique-domain-name.js +2 -1
  34. package/dist/esm/sites/domains/ensure-unique-domain-name.js.map +1 -1
  35. package/dist/esm/sites/domains/is-valid-domain.js +2 -1
  36. package/dist/esm/sites/domains/is-valid-domain.js.map +1 -1
  37. package/dist/esm/util.js +8 -0
  38. package/dist/esm/util.js.map +1 -1
  39. package/dist/node/api.js +5 -0
  40. package/dist/node/api.js.map +1 -1
  41. package/dist/node/content.js +346 -1
  42. package/dist/node/content.js.map +1 -1
  43. package/dist/node/downloads/build-existing-exports-portal-query.js +195 -0
  44. package/dist/node/downloads/build-existing-exports-portal-query.js.map +1 -0
  45. package/dist/node/downloads/index.js +5 -0
  46. package/dist/node/downloads/index.js.map +1 -0
  47. package/dist/node/index.js +4 -0
  48. package/dist/node/index.js.map +1 -1
  49. package/dist/node/request.js +8 -5
  50. package/dist/node/request.js.map +1 -1
  51. package/dist/node/sites/domains/_get-domain-service-url.js.map +1 -1
  52. package/dist/node/sites/domains/ensure-unique-domain-name.js +2 -1
  53. package/dist/node/sites/domains/ensure-unique-domain-name.js.map +1 -1
  54. package/dist/node/sites/domains/is-valid-domain.js +2 -1
  55. package/dist/node/sites/domains/is-valid-domain.js.map +1 -1
  56. package/dist/node/util.js +10 -1
  57. package/dist/node/util.js.map +1 -1
  58. package/dist/types/content.d.ts +61 -0
  59. package/dist/types/downloads/build-existing-exports-portal-query.d.ts +86 -0
  60. package/dist/types/downloads/index.d.ts +1 -0
  61. package/dist/types/index.d.ts +2 -0
  62. package/dist/types/sites/domains/_get-domain-service-url.d.ts +1 -1
  63. package/dist/types/types.d.ts +19 -7
  64. package/dist/types/util.d.ts +6 -0
  65. package/dist/umd/common.umd.js +2394 -1685
  66. package/dist/umd/common.umd.js.map +1 -1
  67. package/dist/umd/common.umd.min.js +1 -1
  68. package/dist/umd/common.umd.min.js.map +1 -1
  69. package/package.json +5 -3
@@ -1,5 +1,5 @@
1
1
  /* @preserve
2
- * @esri/hub-common - v8.17.3 - Mon Sep 13 2021 10:26:51 GMT-0700 (Pacific Daylight Time)
2
+ * @esri/hub-common - v8.21.0 - Mon Sep 20 2021 14:32:08 GMT-0700 (Pacific Daylight Time)
3
3
  * Copyright (c) 2021 Environmental Systems Research Institute, Inc.
4
4
  * Apache-2.0
5
5
  */
@@ -507,6 +507,14 @@
507
507
  chars[0] = chars[0].toUpperCase();
508
508
  return chars.join("");
509
509
  };
510
+ /**
511
+ * An IE-compatible stand-in for Javascript's [array.flat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat)
512
+ * @param arr the array
513
+ * @returns an array
514
+ */
515
+ function flattenArray(arr) {
516
+ return arr.reduce(function (acc, val) { return acc.concat(val); }, []);
517
+ }
510
518
 
511
519
  /**
512
520
  * Deep set function. Like Ember.set, but smarter as it will create the path
@@ -2526,14 +2534,14 @@
2526
2534
  this.q += modifier.toUpperCase() + " ";
2527
2535
  return this;
2528
2536
  };
2529
- SearchQueryBuilder.prototype.hasWhiteSpace = function (s) {
2530
- return /\s/g.test(s);
2537
+ SearchQueryBuilder.prototype.needsQuotes = function (s) {
2538
+ return /\s|:/g.test(s);
2531
2539
  };
2532
2540
  SearchQueryBuilder.prototype.formatTerm = function (term) {
2533
2541
  if (term instanceof Date) {
2534
2542
  return term.getTime();
2535
2543
  }
2536
- if (typeof term === "string" && this.hasWhiteSpace(term)) {
2544
+ if (typeof term === "string" && this.needsQuotes(term)) {
2537
2545
  return "\"" + term + "\"";
2538
2546
  }
2539
2547
  return term;
@@ -3681,6 +3689,11 @@
3681
3689
  * @returns the associated Hub API Url as a string.
3682
3690
  */
3683
3691
  function getHubApiUrl(urlOrObject) {
3692
+ var hubApiUrl = urlOrObject && urlOrObject.hubApiUrl;
3693
+ if (hubApiUrl) {
3694
+ // this is request options w/ hubApiUrl already defined
3695
+ return hubApiUrl;
3696
+ }
3684
3697
  return _getHubUrlFromPortalHostname(getPortalApiUrl(urlOrObject));
3685
3698
  }
3686
3699
 
@@ -4945,1891 +4958,2569 @@
4945
4958
  })));
4946
4959
  }
4947
4960
 
4948
- var cache = {};
4949
- // TODO: remove this at next breaking version
4950
- /**
4951
- * ```js
4952
- * import { getCategory } from "@esri/hub-common";
4953
- * //
4954
- * getCategory('Feature Layer')
4955
- * > 'dataset'
4956
- * ```
4957
- * **DEPRECATED: Use getCollection() instead**
4958
- * returns the Hub category for a given item type
4959
- * @param itemType The ArcGIS [item type](https://developers.arcgis.com/rest/users-groups-and-items/items-and-item-types.htm).
4960
- * @returns the category of a given item type.
4961
- */
4962
- function getCategory(itemType) {
4963
- if (itemType === void 0) { itemType = ""; }
4964
- /* tslint:disable no-console */
4965
- console.warn("DEPRECATED: Use getCollection() instead. getCategory will be removed at v9.0.0");
4966
- /* tslint:enable no-console */
4967
- var collection = getCollection(itemType);
4968
- // for backwards compatibility
4969
- return collection === "feedback" ? "app" : collection;
4961
+ function createExtent(xmin, ymin, xmax, ymax, wkid) {
4962
+ if (wkid === void 0) { wkid = 4326; }
4963
+ return {
4964
+ xmin: xmin,
4965
+ ymin: ymin,
4966
+ xmax: xmax,
4967
+ ymax: ymax,
4968
+ // type: 'extent',
4969
+ spatialReference: {
4970
+ wkid: wkid
4971
+ }
4972
+ };
4970
4973
  }
4971
4974
  /**
4972
- * ```js
4973
- * import { getTypes } from "@esri/hub-common";
4974
- * //
4975
- * getTypes('site')
4976
- * > [ 'hub site application' ]
4977
- * ```
4978
- * To do.
4979
- * @param category The ArcGIS Hub category.
4980
- * @returns all the item types for the given category.
4981
- *
4975
+ * Turns an extent into a bbox
4976
+ * @param envelope extent
4982
4977
  */
4983
- function getTypes(category) {
4984
- if (category === void 0) { category = ""; }
4985
- return categories[category.toLowerCase()];
4978
+ function extentToBBox(envelope) {
4979
+ return [[envelope.xmin, envelope.ymin], [envelope.xmax, envelope.ymax]];
4986
4980
  }
4987
- /**
4988
- * ```js
4989
- * import { normalizeItemType } from "@esri/hub-common";
4990
- * //
4991
- * normalizeItemType(item)
4992
- * > [ 'Hub Site Application' ]
4993
- * ```
4994
- * @param item Item object.
4995
- * @returns type of the input item.
4996
- *
4997
- */
4998
- function normalizeItemType(item) {
4999
- if (item === void 0) { item = {}; }
5000
- var ret = item.type;
5001
- var typeKeywords = item.typeKeywords || [];
5002
- if (item.type === "Site Application" ||
5003
- (item.type === "Web Mapping Application" &&
5004
- includes(typeKeywords, "hubSite"))) {
5005
- ret = "Hub Site Application";
5006
- }
5007
- if (item.type === "Site Page" ||
5008
- (item.type === "Web Mapping Application" &&
5009
- includes(typeKeywords, "hubPage"))) {
5010
- ret = "Hub Page";
5011
- }
5012
- if (item.type === "Hub Initiative" &&
5013
- includes(typeKeywords, "hubInitiativeTemplate")) {
5014
- ret = "Hub Initiative Template";
5015
- }
5016
- if (item.type === "Web Mapping Application" &&
5017
- includes(typeKeywords, "hubSolutionTemplate")) {
5018
- ret = "Solution";
4981
+ var GLOBAL_EXTENT = {
4982
+ xmin: -180,
4983
+ ymin: -90,
4984
+ xmax: 180,
4985
+ ymax: 90,
4986
+ spatialReference: {
4987
+ wkid: 4326
5019
4988
  }
5020
- return ret;
5021
- }
4989
+ };
5022
4990
  /**
5023
- * ```js
5024
- * import { getTypeCategories } from "@esri/hub-common";
5025
- * //
5026
- * getTypeCategories(item)
5027
- * > [ 'Hub Site Application' ]
5028
- * ```
5029
- * @param item Item object.
5030
- * @returns typeCategory of the input item.
5031
- *
4991
+ * Gets the geographic extent for an org
4992
+ * @param hubRequestOptions
5032
4993
  */
5033
- function getTypeCategories(item) {
5034
- if (item === void 0) { item = {}; }
5035
- var type = normalizeItemType(item);
5036
- var category = getCategory(type);
5037
- if (category) {
5038
- // upper case first letter and return as element in array for backwards compatibility
5039
- var chars = Array.from(category);
5040
- chars[0] = chars[0].toUpperCase();
5041
- return [chars.join("")];
5042
- }
5043
- else {
5044
- return ["Other"];
4994
+ function getGeographicOrgExtent(hubRequestOptions) {
4995
+ var portal = hubRequestOptions.portalSelf;
4996
+ var orgExtent = portal.defaultExtent;
4997
+ var geometryServiceUrl = getProp(portal, "helperServices.geometry.url");
4998
+ // Define a default global extent object
4999
+ if (!geometryServiceUrl) {
5000
+ return Promise.resolve(GLOBAL_EXTENT);
5045
5001
  }
5046
- }
5047
- /**
5048
- * ```js
5049
- * import { getCollection } from "@esri/hub-common";
5050
- * //
5051
- * getCollection('Feature Layer')
5052
- * > 'dataset'
5053
- * ```
5054
- * Get the Hub collection for a given item type
5055
- * @param itemType The ArcGIS [item type](https://developers.arcgis.com/rest/users-groups-and-items/items-and-item-types.htm).
5056
- * @returns the Hub collection of a given item type.
5057
- */
5058
- function getCollection(itemType) {
5059
- if (itemType === void 0) { itemType = ""; }
5060
- if (cache[itemType]) {
5061
- return cache[itemType];
5002
+ if (!orgExtent) {
5003
+ return Promise.resolve(GLOBAL_EXTENT);
5062
5004
  }
5063
- for (var _i = 0, _a = Object.keys(collections); _i < _a.length; _i++) {
5064
- var collection = _a[_i];
5065
- for (var _b = 0, _c = collections[collection]; _b < _c.length; _b++) {
5066
- var type = _c[_b];
5067
- if (itemType.toLowerCase() === type.toLowerCase()) {
5068
- cache[itemType] = collection;
5069
- return collection;
5070
- }
5005
+ var url = geometryServiceUrl + "/project";
5006
+ // geometry params...
5007
+ var geometryParam = {
5008
+ geometryType: "esriGeometryEnvelope",
5009
+ geometries: [orgExtent]
5010
+ };
5011
+ var options = {
5012
+ httpMethod: "POST",
5013
+ params: {
5014
+ geometries: JSON.stringify(geometryParam),
5015
+ transformForward: false,
5016
+ transformation: "",
5017
+ inSR: orgExtent.spatialReference.wkid,
5018
+ outSR: 4326,
5019
+ f: "json"
5071
5020
  }
5021
+ };
5022
+ // add in auth if it's passed
5023
+ if (hubRequestOptions.authentication) {
5024
+ options.authentication = hubRequestOptions.authentication;
5072
5025
  }
5026
+ return request(url, options)
5027
+ .then(function (response) {
5028
+ var geom = response.geometries[0];
5029
+ return {
5030
+ xmin: geom.xmin,
5031
+ ymin: geom.ymin,
5032
+ xmax: geom.xmax,
5033
+ ymax: geom.ymax,
5034
+ spatialReference: {
5035
+ wkid: 4326
5036
+ }
5037
+ };
5038
+ })
5039
+ .catch(function (ex) {
5040
+ return GLOBAL_EXTENT;
5041
+ });
5073
5042
  }
5074
5043
  /**
5075
- * Case-insensitive check if the type is "Feature Service"
5076
- * @param {string} type - item's type
5077
- * @returns {boolean}
5078
- */
5079
- var isFeatureService = function (type) {
5080
- return type && type.toLowerCase() === "feature service";
5081
- };
5082
- /**
5083
- * parse layer id from a service URL
5084
- * @param {string} url
5085
- * @returns {string} layer id
5086
- */
5087
- var getLayerIdFromUrl = function (url) {
5088
- var endsWithNumberSegmentRegEx = /\/\d+$/;
5089
- var matched = url && url.match(endsWithNumberSegmentRegEx);
5090
- return matched && matched[0].slice(1);
5091
- };
5092
- /**
5093
- * return the layerId if we can tell that item is a single layer service
5094
- * @param {*} item from AGO
5095
- * @returns {string} layer id
5044
+ * Get the default org extent as a bbox for use on item.extent
5045
+ * @param {IHubRequestOptions} hubRequestOptions
5096
5046
  */
5097
- var getItemLayerId = function (item) {
5098
- // try to parse it from the URL, but failing that we check for
5099
- // the Singlelayer typeKeyword, which I think is set when you create the item in AGO
5100
- // but have not verified that, nor that we should alway return '0' in that case
5101
- return (getLayerIdFromUrl(item.url) ||
5102
- (isFeatureService(item.type) &&
5103
- includes(item.typeKeywords, "Singlelayer") &&
5104
- "0"));
5105
- };
5047
+ function getOrgExtentAsBBox(hubRequestOptions) {
5048
+ return getGeographicOrgExtent(hubRequestOptions).then(function (extent) {
5049
+ return extentToBBox(extent);
5050
+ });
5051
+ }
5052
+ function isExtentCoordinateArray(extent) {
5053
+ return (Array.isArray(extent) &&
5054
+ Array.isArray(extent[0]) &&
5055
+ Array.isArray(extent[1]));
5056
+ }
5057
+ function isExtentJSON(extent) {
5058
+ return ["xmin", "ymin", "xmax", "ymax"].every(function (key) { return typeof extent[key] === "number"; });
5059
+ }
5106
5060
  /**
5107
- * given an item, get the id to use w/ the Hub API
5108
- * @param item
5109
- * @returns Hub API id (hubId)
5110
- */
5111
- var getItemHubId = function (item) {
5112
- if (item.access !== "public") {
5113
- // the hub only indexes public items
5114
- return;
5115
- }
5116
- var id = item.id;
5117
- var layerId = getItemLayerId(item);
5118
- return layerId ? id + "_" + layerId : id;
5119
- };
5120
- /**
5121
- * ```js
5122
- * import { getContentIdentifier } from "@esri/hub-common";
5123
- * //
5124
- * getContentIdentifier(content, site)
5125
- * > 'f12hhjk32' // id
5126
- * // OR
5127
- * > 'content-slug' // human-readable slug
5128
- * ```
5129
- * Returns the preferred identifier for a piece of content (determined by content type):
5130
- * - Content from the 'template' and 'feedback' families return the standard id field
5131
- * - Pages that are linked to the site parameter will return the slug defined by the site. Otherwise, the page id will be returned
5132
- * - All other content will return the highest available item in the following hierarchy:
5133
- * 1. slug - includes org prefix if the site parameter is a portal or has an orgKey different from the slug prefix
5134
- * 2. hubId
5135
- * 3. id
5136
- * @param content The IHubContent item
5137
- * @param site The site to compare content against
5138
- * @returns the preferred id for the given content.
5139
- */
5140
- function getContentIdentifier(content, site) {
5141
- // We don't currently support slugs for hub initiative templates, solutions or surveys
5142
- if (includes(["template", "feedback"], content.family)) {
5143
- return content.id;
5144
- }
5145
- // If it is a hub page linked to a site, return the page slug at the
5146
- // site data instead. Because this one is the original one that was used
5147
- // to create the page url (not mutable once created) and the slug (below)
5148
- // generated by the hub-indexer could simply change with page name.
5149
- // TODO: we check both "Hub Page" and "Site Page" because we don't know whether the site is a portal or not
5150
- // In the future, the site object will have a site.isPortal() function that we can leverage
5151
- // instead of hardcoding the types here.
5152
- if (includes(["Hub Page", "Site Page"], content.type)) {
5153
- // check if the page is linked to the current site
5154
- var pages = getProp(site, "data.values.pages") || [];
5155
- var page = pages.find(function (p) { return p.id === content.id; });
5156
- // if so, return the page slug otherwise the page id
5157
- return page ? page.slug : content.id;
5158
- }
5159
- // If a slug is present, always return it
5160
- if (content.slug) {
5161
- var slug = void 0;
5162
- var orgKey = getProp(site, "domainInfo.orgKey");
5163
- // Use namespaced slug when on the umbrella site
5164
- if (getProp(site, "data.values.isUmbrella")) {
5165
- slug = content.slug;
5166
- }
5167
- else {
5168
- // Use shortened slug if the slug's namespace is the same as the orgKey
5169
- slug = removeContextFromSlug(content.slug, orgKey);
5170
- }
5171
- return slug;
5172
- }
5173
- return content.hubId || content.id;
5174
- }
5175
- //////////////////////
5176
- // Slug Helpers
5177
- //////////////////////
5178
- /**
5179
- * Parse item ID and layer ID (if any) from dataset record ID
5180
- *
5181
- * @param datasetId Hub API dataset record id ({itemId}_{layerId} or {itemId})
5182
- * @returns A hash with the `itemId` and `layerId` (if any)
5183
- */
5184
- function parseDatasetId(datasetId) {
5185
- var _a = datasetId ? datasetId.split("_") : [], itemId = _a[0], layerId = _a[1];
5186
- return { itemId: itemId, layerId: layerId };
5187
- }
5188
- /**
5189
- * Determine if an identifier is a Hub API slug
5190
- *
5191
- * @param identifier Hub API slug ({orgKey}::{title-as-slug} or {title-as-slug})
5192
- * or record id ((itemId}_{layerId} or {itemId})
5193
- * @returns true if the identifier is valid _and_ is **not** a record id
5194
- */
5195
- function isSlug(identifier) {
5196
- var itemId = parseDatasetId(identifier).itemId;
5197
- if (!itemId || isGuid(itemId)) {
5198
- // it's either invalid, or an item id, or a dataset id
5199
- return false;
5200
- }
5201
- // otherwise assume it's a slug
5202
- return true;
5203
- }
5204
- /**
5205
- * Add a context (prefix) to slug if it doesn't already have one
5206
- *
5207
- * @param slug Hub API slug (with or without context)
5208
- * @param context usually a portal's orgKey
5209
- * @returns slug with context ({context}::{slug})
5210
- */
5211
- function addContextToSlug(slug, context) {
5212
- // the slug has an org key already e.g. dc::crime-incidents
5213
- if (/.+::.+/.test(slug)) {
5214
- return slug;
5215
- // the slug belongs to the org that owns the site e.g. crime-incidents
5216
- }
5217
- else {
5218
- return context + "::" + slug;
5219
- }
5220
- }
5221
- /**
5222
- * Remove context (prefix) from a slug
5223
- *
5224
- * @param slug Hub API slug with context
5225
- * @param context usually a portal's orgKey
5226
- * @returns slug without context
5227
- */
5228
- function removeContextFromSlug(slug, context) {
5229
- if (context && slug.match(context + "::")) {
5230
- return slug.split(context + "::")[1];
5231
- }
5232
- else {
5233
- return slug;
5234
- }
5235
- }
5236
-
5237
- function createExtent(xmin, ymin, xmax, ymax, wkid) {
5238
- if (wkid === void 0) { wkid = 4326; }
5239
- return {
5240
- xmin: xmin,
5241
- ymin: ymin,
5242
- xmax: xmax,
5243
- ymax: ymax,
5244
- // type: 'extent',
5245
- spatialReference: {
5246
- wkid: wkid
5247
- }
5248
- };
5249
- }
5250
- /**
5251
- * Turns an extent into a bbox
5252
- * @param envelope extent
5253
- */
5254
- function extentToBBox(envelope) {
5255
- return [[envelope.xmin, envelope.ymin], [envelope.xmax, envelope.ymax]];
5256
- }
5257
- var GLOBAL_EXTENT = {
5258
- xmin: -180,
5259
- ymin: -90,
5260
- xmax: 180,
5261
- ymax: 90,
5262
- spatialReference: {
5263
- wkid: 4326
5264
- }
5265
- };
5266
- /**
5267
- * Gets the geographic extent for an org
5268
- * @param hubRequestOptions
5269
- */
5270
- function getGeographicOrgExtent(hubRequestOptions) {
5271
- var portal = hubRequestOptions.portalSelf;
5272
- var orgExtent = portal.defaultExtent;
5273
- var geometryServiceUrl = getProp(portal, "helperServices.geometry.url");
5274
- // Define a default global extent object
5275
- if (!geometryServiceUrl) {
5276
- return Promise.resolve(GLOBAL_EXTENT);
5277
- }
5278
- if (!orgExtent) {
5279
- return Promise.resolve(GLOBAL_EXTENT);
5280
- }
5281
- var url = geometryServiceUrl + "/project";
5282
- // geometry params...
5283
- var geometryParam = {
5284
- geometryType: "esriGeometryEnvelope",
5285
- geometries: [orgExtent]
5286
- };
5287
- var options = {
5288
- httpMethod: "POST",
5289
- params: {
5290
- geometries: JSON.stringify(geometryParam),
5291
- transformForward: false,
5292
- transformation: "",
5293
- inSR: orgExtent.spatialReference.wkid,
5294
- outSR: 4326,
5295
- f: "json"
5296
- }
5297
- };
5298
- // add in auth if it's passed
5299
- if (hubRequestOptions.authentication) {
5300
- options.authentication = hubRequestOptions.authentication;
5301
- }
5302
- return request(url, options)
5303
- .then(function (response) {
5304
- var geom = response.geometries[0];
5305
- return {
5306
- xmin: geom.xmin,
5307
- ymin: geom.ymin,
5308
- xmax: geom.xmax,
5309
- ymax: geom.ymax,
5310
- spatialReference: {
5311
- wkid: 4326
5312
- }
5313
- };
5314
- })
5315
- .catch(function (ex) {
5316
- return GLOBAL_EXTENT;
5317
- });
5318
- }
5319
- /**
5320
- * Get the default org extent as a bbox for use on item.extent
5321
- * @param {IHubRequestOptions} hubRequestOptions
5322
- */
5323
- function getOrgExtentAsBBox(hubRequestOptions) {
5324
- return getGeographicOrgExtent(hubRequestOptions).then(function (extent) {
5325
- return extentToBBox(extent);
5326
- });
5327
- }
5328
- function isExtentCoordinateArray(extent) {
5329
- return (Array.isArray(extent) &&
5330
- Array.isArray(extent[0]) &&
5331
- Array.isArray(extent[1]));
5332
- }
5333
- function isExtentJSON(extent) {
5334
- return ["xmin", "ymin", "xmax", "ymax"].every(function (key) { return typeof extent[key] === "number"; });
5335
- }
5336
- /**
5337
- * Check if the given extent is in a known format
5338
- * @param {Object} extent extent in any format
5339
- * @return {Boolean} indicator
5061
+ * Check if the given extent is in a known format
5062
+ * @param {Object} extent extent in any format
5063
+ * @return {Boolean} indicator
5340
5064
  */
5341
5065
  function isValidExtent(extent) {
5342
5066
  return (!!extent &&
5343
5067
  [isExtentCoordinateArray, isExtentJSON].some(function (test) { return test(extent); }));
5344
5068
  }
5345
5069
 
5070
+ var STANDARD_LICENSES = [
5071
+ {
5072
+ type: "CC0-1.0",
5073
+ abbr: "CC0",
5074
+ name: "Public Domain Dedication",
5075
+ url: "http://creativecommons.org/publicdomain/zero/1.0",
5076
+ },
5077
+ {
5078
+ type: "CC-BY-4.0",
5079
+ abbr: "CC BY",
5080
+ name: "Attribution 4.0 International",
5081
+ url: "http://creativecommons.org/licenses/by/4.0",
5082
+ },
5083
+ {
5084
+ type: "CC-BY-3.0",
5085
+ abbr: "CC BY 3.0",
5086
+ name: "Attribution 3.0 Unported",
5087
+ url: "http://creativecommons.org/licenses/by/3.0",
5088
+ },
5089
+ {
5090
+ type: "CC-BY-2.5",
5091
+ abbr: "CC BY 2.5",
5092
+ name: "Attribution 2.5 Generic",
5093
+ url: "http://creativecommons.org/licenses/by/2.5",
5094
+ },
5095
+ {
5096
+ type: "CC-BY-2.0",
5097
+ abbr: "CC BY 2.0",
5098
+ name: "Attribution 2.0 Generic",
5099
+ url: "http://creativecommons.org/licenses/by/2.0",
5100
+ },
5101
+ {
5102
+ type: "CC-BY-1.0",
5103
+ abbr: "CC BY 1.0",
5104
+ name: "Attribution 1.0 Generic",
5105
+ url: "http://creativecommons.org/licenses/by/1.0",
5106
+ },
5107
+ {
5108
+ type: "CC-BY-SA-4.0",
5109
+ abbr: "CC BY-SA",
5110
+ name: "Attribution-ShareAlike 4.0 International",
5111
+ url: "http://creativecommons.org/licenses/by-sa/4.0",
5112
+ },
5113
+ {
5114
+ type: "CC-BY-SA-3.0",
5115
+ abbr: "CC BY-SA 3.0",
5116
+ name: "Attribution-ShareAlike 3.0 Unported",
5117
+ url: "http://creativecommons.org/licenses/by-sa/3.0",
5118
+ },
5119
+ {
5120
+ type: "CC-BY-SA-2.5",
5121
+ abbr: "CC BY-SA 2.5",
5122
+ name: "Attribution-ShareAlike 2.5 Generic",
5123
+ url: "http://creativecommons.org/licenses/by-sa/2.5",
5124
+ },
5125
+ {
5126
+ type: "CC-BY-SA-2.0",
5127
+ abbr: "CC BY-SA 2.0",
5128
+ name: "Attribution-ShareAlike 2.0 Generic",
5129
+ url: "http://creativecommons.org/licenses/by-sa/2.0",
5130
+ },
5131
+ {
5132
+ type: "CC-BY-SA-1.0",
5133
+ abbr: "CC BY-SA 1.0",
5134
+ name: "Attribution-ShareAlike 1.0 Generic",
5135
+ url: "http://creativecommons.org/licenses/by-sa/1.0",
5136
+ },
5137
+ {
5138
+ type: "CC-BY-ND-4.0",
5139
+ abbr: "CC BY-ND",
5140
+ name: "Attribution-NoDerivatives 4.0 International",
5141
+ url: "http://creativecommons.org/licenses/by-nd/4.0",
5142
+ },
5143
+ {
5144
+ type: "CC-BY-ND-3.0",
5145
+ abbr: "CC BY-ND 3.0",
5146
+ name: "Attribution-NoDerivs 3.0 Unported",
5147
+ url: "http://creativecommons.org/licenses/by-nd/3.0",
5148
+ },
5149
+ {
5150
+ type: "CC-BY-ND-2.5",
5151
+ abbr: "CC BY-ND 2.5",
5152
+ name: "Attribution-NoDerivs 2.5 Generic",
5153
+ url: "http://creativecommons.org/licenses/by-nd/2.5",
5154
+ },
5155
+ {
5156
+ type: "CC-BY-ND-2.0",
5157
+ abbr: "CC BY-ND 2.0",
5158
+ name: "Attribution-NoDerivs 2.0 Generic",
5159
+ url: "http://creativecommons.org/licenses/by-nd/2.0",
5160
+ },
5161
+ {
5162
+ type: "CC-BY-ND-1.0",
5163
+ abbr: "CC BY-ND 1.0",
5164
+ name: "Attribution-NoDerivs 1.0 Generic",
5165
+ url: "http://creativecommons.org/licenses/by-nd/1.0",
5166
+ },
5167
+ {
5168
+ type: "CC-BY-NC-4.0",
5169
+ abbr: "CC BY-NC",
5170
+ name: "Attribution-NonCommercial 4.0 International",
5171
+ url: "https://creativecommons.org/licenses/by-nc/4.0",
5172
+ },
5173
+ {
5174
+ type: "CC-BY-NC-3.0",
5175
+ abbr: "CC BY-NC 3.0",
5176
+ name: "Attribution-NonCommercial 3.0 Unported",
5177
+ url: "https://creativecommons.org/licenses/by-nc/3.0",
5178
+ },
5179
+ {
5180
+ type: "CC-BY-NC-2.5",
5181
+ abbr: "CC BY-NC 2.5",
5182
+ name: "Attribution-NonCommercial 2.5 Generic",
5183
+ url: "https://creativecommons.org/licenses/by-nc/2.5",
5184
+ },
5185
+ {
5186
+ type: "CC-BY-NC-2.0",
5187
+ abbr: "CC BY-NC 2.0",
5188
+ name: "Attribution-NonCommercial 2.0 Generic",
5189
+ url: "https://creativecommons.org/licenses/by-nc/2.0",
5190
+ },
5191
+ {
5192
+ type: "CC-BY-NC-1.0",
5193
+ abbr: "CC BY-NC 1.0",
5194
+ name: "Attribution-NonCommercial 1.0 Generic",
5195
+ url: "https://creativecommons.org/licenses/by-nc/1.0",
5196
+ },
5197
+ {
5198
+ type: "CC-BY-NC-SA-4.0",
5199
+ abbr: "CC BY-NC-SA",
5200
+ name: "Attribution-NonCommercial-ShareAlike 4.0 International",
5201
+ url: "https://creativecommons.org/licenses/by-nc-sa/4.0",
5202
+ },
5203
+ {
5204
+ type: "CC-BY-NC-SA-3.0",
5205
+ abbr: "CC BY-NC-SA 3.0",
5206
+ name: "Attribution-NonCommercial-ShareAlike 3.0 Unported",
5207
+ url: "https://creativecommons.org/licenses/by-nc-sa/3.0",
5208
+ },
5209
+ {
5210
+ type: "CC-BY-NC-SA-2.5",
5211
+ abbr: "CC BY-NC-SA 2.5",
5212
+ name: "Attribution-NonCommercial-ShareAlike 2.5 Generic",
5213
+ url: "https://creativecommons.org/licenses/by-nc-sa/2.5",
5214
+ },
5215
+ {
5216
+ type: "CC-BY-NC-SA-2.0",
5217
+ abbr: "CC BY-NC-SA 2.0",
5218
+ name: "Attribution-NonCommercial-ShareAlike 2.0 Generic",
5219
+ url: "https://creativecommons.org/licenses/by-nc-sa/2.0",
5220
+ },
5221
+ {
5222
+ type: "CC-BY-NC-SA-1.0",
5223
+ abbr: "CC BY-NC-SA 1.0",
5224
+ name: "Attribution-NonCommercial-ShareAlike 1.0 Generic",
5225
+ url: "https://creativecommons.org/licenses/by-nc-sa/1.0",
5226
+ },
5227
+ {
5228
+ type: "CC-BY-NC-ND-4.0",
5229
+ abbr: "CC BY-NC-ND",
5230
+ name: "Attribution-NonCommercial-NoDerivatives 4.0 International",
5231
+ url: "https://creativecommons.org/licenses/by-nc-nd/4.0",
5232
+ },
5233
+ {
5234
+ type: "CC-BY-NC-ND-3.0",
5235
+ abbr: "CC BY-NC-ND 3.0",
5236
+ name: "Attribution-NonCommercial-NoDerivs 3.0 Unported",
5237
+ url: "https://creativecommons.org/licenses/by-nc-nd/3.0",
5238
+ },
5239
+ {
5240
+ type: "CC-BY-NC-ND-2.5",
5241
+ abbr: "CC BY-NC-ND 2.5",
5242
+ name: "Attribution-NonCommercial-NoDerivs 2.5 Generic",
5243
+ url: "https://creativecommons.org/licenses/by-nc-nd/2.5",
5244
+ },
5245
+ {
5246
+ type: "CC-BY-NC-ND-2.0",
5247
+ abbr: "CC BY-NC-ND 2.0",
5248
+ name: "Attribution-NonCommercial-NoDerivs 2.0 Generic",
5249
+ url: "https://creativecommons.org/licenses/by-nc-nd/2.0",
5250
+ },
5251
+ {
5252
+ type: "CC-BY-NC-ND-1.0",
5253
+ abbr: "CC BY-NC-ND 1.0",
5254
+ name: "Attribution-NonCommercial-NoDerivs 1.0 Generic",
5255
+ url: "https://creativecommons.org/licenses/by-nc-nd/1.0",
5256
+ },
5257
+ {
5258
+ type: "PDDL-1.0",
5259
+ abbr: "PDDL",
5260
+ name: "ODC Public Domain Dedication and License",
5261
+ url: "http://opendatacommons.org/licenses/pddl/summary",
5262
+ },
5263
+ {
5264
+ type: "ODbL-1.0",
5265
+ abbr: "ODbL",
5266
+ name: "ODC Open Database License",
5267
+ url: "http://opendatacommons.org/licenses/odbl/summary",
5268
+ },
5269
+ {
5270
+ type: "ODC-BY-1.0",
5271
+ abbr: "ODC BY",
5272
+ name: "ODC Attribution License",
5273
+ url: "http://opendatacommons.org/licenses/by/summary",
5274
+ },
5275
+ ];
5346
5276
  /**
5347
- * Unprotect and Remove a Group.
5348
- * Assumed caller has checked that the current user should be able
5349
- * to unprotect and remove the group. Underlying calls are failsafe
5350
- * so a failure to unprotect or remove the group will not reject
5351
- * @param {IUserGroupOptions} userGroupOptions id and authentication
5352
- * @private
5353
- */
5354
- function _unprotectAndRemoveGroup(userGroupOptions) {
5355
- var failSafeUnprotect = failSafe(unprotectGroup, { success: true });
5356
- var failSafeRemove = failSafe(removeGroup, { success: true });
5357
- return failSafeUnprotect(userGroupOptions).then(function () {
5358
- return failSafeRemove(userGroupOptions);
5359
- });
5360
- }
5361
-
5362
- /**
5363
- * @private
5364
- */
5365
- function _consolidateResults(context) {
5366
- var autoAddResult = context.autoAddResult, inviteResult = context.inviteResult, primaryEmailResult = context.primaryEmailResult, secondaryEmailResult = context.secondaryEmailResult;
5367
- var combinedEmailResults;
5368
- if (primaryEmailResult || secondaryEmailResult) {
5369
- var validResults = [primaryEmailResult, secondaryEmailResult].filter(function (r) { return r; });
5370
- var combinedSuccess = validResults.every(function (r) { return r.success; });
5371
- var combinedErrors = validResults.reduce(function (collection, r) { return collection.concat(getWithDefault$1(r, "errors", [])); }, []);
5372
- combinedEmailResults = {
5373
- success: combinedSuccess
5374
- };
5375
- if (combinedErrors.length) {
5376
- combinedEmailResults.errors = combinedErrors;
5377
- }
5378
- }
5379
- var overallSuccess = [autoAddResult, inviteResult, combinedEmailResults]
5380
- .filter(function (r) { return r; })
5381
- .every(function (r) { return r.success; });
5382
- return {
5383
- success: overallSuccess,
5384
- autoAdd: autoAddResult,
5385
- invite: inviteResult,
5386
- email: combinedEmailResults
5387
- };
5388
- }
5389
-
5390
- /**
5391
- * @private
5392
- *
5393
- * Coerce autoAdd response into a more similar interface as
5394
- * the other rest calls.
5395
- *
5396
- * If any users are not auto added, an error is added to the response
5397
- * and unadded users are placed into the invitation list
5277
+ * generates the structured license of an item based on its
5278
+ * configured "licenseInfo"
5279
+ * @param rawLicense an item's raw licenseInfo string
5280
+ * @returns {IStructuredLicense}
5398
5281
  */
5399
- function _formatAutoAddResponse(rawResponse, context) {
5400
- if (rawResponse) {
5401
- var success = !getProp(rawResponse, "notAdded.length") && !rawResponse.errors;
5402
- context.autoAddResult = { success: success };
5403
- if (!success) {
5404
- var errors = rawResponse.errors || [];
5405
- if (getProp(rawResponse, "notAdded.length")) {
5406
- errors.push(new ArcGISRequestError("Users not auto-added: " + rawResponse.notAdded.join(", ")));
5407
- }
5408
- context.autoAddResult.errors = errors;
5409
- // Move unadded users to invite list;
5410
- var unaddedUsers = context.usersToAutoAdd.filter(function (user) {
5411
- return includes(rawResponse.notAdded, user.username);
5412
- });
5413
- context.usersToInvite = context.usersToInvite.concat(unaddedUsers);
5414
- }
5282
+ function getStructuredLicense(rawLicense) {
5283
+ var structuredLicense;
5284
+ rawLicense = rawLicense || "";
5285
+ // (1) start by assuming it's either a custom license, or, if there's no
5286
+ // raw license, then there's no license at all
5287
+ structuredLicense = {
5288
+ type: rawLicense ? "custom" : "none",
5289
+ text: rawLicense,
5290
+ };
5291
+ // (2) Check for standard licenses: If the name, abbr, or url of any standard
5292
+ // license is in the raw license text, we assume that is the license.
5293
+ var hasStandardLicense = false;
5294
+ var matchingStandardLicenses = STANDARD_LICENSES.filter(function (standardLicense) {
5295
+ return licenseTextContainsStandardLicenseAttributes(rawLicense, standardLicense);
5296
+ });
5297
+ if (matchingStandardLicenses.length) {
5298
+ hasStandardLicense = true;
5299
+ structuredLicense = matchingStandardLicenses.pop();
5415
5300
  }
5416
- return context;
5417
- }
5418
-
5419
- /**
5420
- * @private
5421
- *
5422
- * returns whether or not the users are in the same org
5423
- */
5424
- function _canEmailUser(recipient, sender) {
5425
- return recipient.orgId === sender.orgId;
5426
- }
5427
-
5428
- /**
5429
- * @private
5430
- */
5431
- function _isOrgAdmin(user) {
5432
- return user.role === "org_admin" && !user.roleId;
5433
- }
5434
-
5435
- /**
5436
- * Attempts to email members of the requesting user's organization.
5437
- *
5438
- * @param {IUser[]} users Users to email (must be in the same org as the requesting user)
5439
- * @param {IEmail} email
5440
- * @param {IAuthenticationManager} authentication
5441
- * @param {boolean} isOrgAdmin // Whether the requesting user in an org admin
5442
- *
5443
- * @returns {object|null} A promise that resolves to the result of the transaction (null if no users are passed in)
5444
- */
5445
- function emailOrgUsers(users, email, authentication, isOrgAdmin) {
5446
- var response = Promise.resolve(null);
5447
- if (users.length) {
5448
- var args = {
5449
- authentication: authentication,
5450
- message: email.body,
5451
- subject: email.subject,
5452
- notificationChannelType: "email",
5453
- users: users.map(function (u) { return u.username; })
5454
- };
5455
- if (!isOrgAdmin) {
5456
- args.batchSize = 1;
5301
+ // (3) if not a standard license, we check if the raw license is a url or link
5302
+ if (!hasStandardLicense) {
5303
+ var url = void 0;
5304
+ // a. check if the the raw license is simply a url
5305
+ if (isParseableAsURL(rawLicense)) {
5306
+ url = rawLicense;
5307
+ }
5308
+ // b. check if the raw license is simply a link (i.e. an anchor tag with an href)
5309
+ else if (isSingleAnchorWithHrefAttribute(rawLicense)) {
5310
+ var hrefRegex = new RegExp(/href\s?=\s?["'](.*?)["']/);
5311
+ var match = rawLicense.match(hrefRegex);
5312
+ var href = match[1];
5313
+ url = href;
5314
+ }
5315
+ if (url) {
5316
+ structuredLicense.url = url;
5317
+ structuredLicense.text = "";
5457
5318
  }
5458
- response = createOrgNotification(args);
5459
5319
  }
5460
- return response;
5320
+ if (!structuredLicense.text)
5321
+ delete structuredLicense.text;
5322
+ return structuredLicense;
5461
5323
  }
5462
-
5463
5324
  /**
5464
- * @private
5465
- *
5466
- * If a secondary authentication is passed in AND
5467
- * an email object is passed in AND
5468
- * the previous invitation call was successful:
5469
- *
5470
- * Send an email notification to the invited
5471
- * users that are part of the secondary authentication's org
5325
+ * helper function to determine if a raw license is one of the standard licenses.
5326
+ * We say it is if the raw license includes the name, url or abbreviation of the
5327
+ * standard license
5328
+ * @param rawLicense an item's raw licenseInfo string
5329
+ * @param standardLicense one of the standard licenses
5330
+ * @returns {boolean}
5472
5331
  */
5473
- function _processSecondaryEmail(context) {
5474
- var response = Promise.resolve(context);
5475
- // If secondaryRO provided, send email to the invited users in the secondaryRO's org (typically a community org)
5476
- if (context.email &&
5477
- context.secondaryRO &&
5478
- getProp(context, "inviteResult.success")) {
5479
- var secondaryUser_1 = getWithDefault$1(context, "secondaryRO.portalSelf.user", {});
5480
- var secondaryOrgUsersToEmail = context.usersToInvite.filter(function (u) {
5481
- return _canEmailUser(u, secondaryUser_1);
5482
- });
5483
- response = emailOrgUsers(secondaryOrgUsersToEmail, context.email, context.secondaryRO.authentication, _isOrgAdmin(secondaryUser_1)).then(function (result) {
5484
- context.secondaryEmailResult = result;
5485
- return context;
5486
- });
5487
- }
5488
- return response;
5332
+ function licenseTextContainsStandardLicenseAttributes(rawLicense, standardLicense) {
5333
+ rawLicense = rawLicense.toLowerCase();
5334
+ return (rawLicense.includes(standardLicense.name.toLowerCase()) ||
5335
+ rawLicense.includes(standardLicense.url.toLowerCase()) ||
5336
+ rawLicense.includes(standardLicense.abbr.toLowerCase()));
5489
5337
  }
5490
-
5491
5338
  /**
5492
- *
5493
- * Attempts to auto-add users to a group
5494
- *
5495
- * @param {string} id ID of the group the users will be added to
5496
- * @param {IUser[]} users
5497
- * @param {IAuthenticationManager} authentication
5498
- *
5499
- * @returns {IAddGroupUsersResult|null} Result of the transaction (null if no users are passed in)
5339
+ * helper function to determine if an input string can be parsed
5340
+ * as a URL with a protocol
5341
+ * @param value string to check
5342
+ * @returns {boolean}
5500
5343
  */
5501
- function autoAddUsers(id, users, authentication) {
5502
- var response = Promise.resolve(null);
5503
- if (users.length) {
5504
- var args = {
5505
- id: id,
5506
- users: users.map(function (u) { return u.username; }),
5507
- authentication: authentication
5508
- };
5509
- response = addGroupUsers(args);
5344
+ function isParseableAsURL(value) {
5345
+ try {
5346
+ var url = new URL(value);
5347
+ return !!url.protocol;
5348
+ }
5349
+ catch (err) {
5350
+ // just return fals if the URL couldn't be parsed
5351
+ return false;
5510
5352
  }
5511
- return response;
5512
5353
  }
5513
-
5514
5354
  /**
5515
- * @private
5355
+ * helper function to determine if the raw license is simply a link, i.e. a single
5356
+ * anchor tag with an href attribute: <a href="https://google.com">Click</a> or <a href="https://google.com" />
5357
+ * @param rawLicense an item's raw licenseInfo string
5358
+ * @returns {boolean}
5516
5359
  */
5517
- function _processAutoAdd(context) {
5518
- return autoAddUsers(getProp(context, "groupId"), getProp(context, "usersToAutoAdd"), getProp(context, "primaryRO.authentication")).then(function (rawResponse) { return _formatAutoAddResponse(rawResponse, context); });
5360
+ function isSingleAnchorWithHrefAttribute(rawLicense) {
5361
+ var isSingleAnchorTagRegex = new RegExp(/^<a[\s]+(href\s?=\s?["'].*?["'])+([^>]?)>((?:.(?!\<\/a\>))*.)?<\/a>$|^<a[\s]+(href\s?=\s?["'].*?["'])+([^>]?)\/>/);
5362
+ return isSingleAnchorTagRegex.test(rawLicense);
5519
5363
  }
5520
5364
 
5521
- /**
5522
- *
5523
- * Attempts to invite users to a group
5524
- *
5525
- * @param {string} id ID of the group the users will be invited to
5526
- * @param {object[]} users
5527
- * @param {object} authentication
5528
- * @param {number} expiration How long the invite will be active (in minutes)
5529
- * @param {string} role What role should they be added as. Defaults to group member
5530
- *
5531
- * @returns {object|null} Result of the transaction (null if no users are passed in)
5532
- */
5533
- function inviteUsers(id, users, authentication, expiration, // default to 2 week expiration TODO: is this actually 2 weeks?
5534
- role // default to group member, but allow for team_admin as well
5535
- ) {
5536
- if (expiration === void 0) { expiration = 20160; }
5537
- if (role === void 0) { role = "group_member"; }
5538
- var response = Promise.resolve(null);
5539
- if (users.length) {
5540
- var args = {
5541
- id: id,
5542
- users: users.map(function (u) { return u.username; }),
5543
- authentication: authentication,
5544
- role: role,
5545
- expiration: expiration,
5546
- };
5547
- response = inviteGroupUsers(args);
5548
- }
5549
- return response;
5365
+ function collectionToFamily(collection) {
5366
+ var overrides = {
5367
+ other: "content",
5368
+ solution: "template",
5369
+ };
5370
+ return overrides[collection] || collection;
5550
5371
  }
5551
-
5552
- /**
5553
- * @private
5554
- */
5555
- function _processInvite(context) {
5556
- return inviteUsers(getProp(context, "groupId"), getProp(context, "usersToInvite"), getProp(context, "primaryRO.authentication")).then(function (result) {
5557
- context.inviteResult = result;
5558
- return context;
5372
+ function itemExtentToBoundary(extent) {
5373
+ return (extent &&
5374
+ extent.length && {
5375
+ // TODO: center?
5376
+ geometry: createExtent(extent[0][0], extent[0][1], extent[1][0], extent[1][1]),
5559
5377
  });
5560
5378
  }
5561
-
5562
- /**
5563
- * @private
5564
- *
5565
- * Send email notification if an email object is present and
5566
- * the previous invitation call was successful
5567
- */
5568
- function _processPrimaryEmail(context) {
5569
- var response = Promise.resolve(context);
5570
- // Email users if invite succeeds
5571
- if (context.email && getProp(context, "inviteResult.success")) {
5572
- response = emailOrgUsers(context.usersToEmail, context.email, context.primaryRO.authentication, _isOrgAdmin(context.requestingUser)).then(function (result) {
5573
- context.primaryEmailResult = result;
5574
- return context;
5575
- });
5576
- }
5577
- return response;
5578
- }
5579
-
5379
+ var cache = {};
5380
+ // TODO: remove this at next breaking version
5580
5381
  /**
5581
- * @private
5582
- *
5583
- * A user can be auto-added if they are part of the requesting user's e-org
5584
- * or c-org and the requesting user has the assignToGroups privilege
5382
+ * ```js
5383
+ * import { getCategory } from "@esri/hub-common";
5384
+ * //
5385
+ * getCategory('Feature Layer')
5386
+ * > 'dataset'
5387
+ * ```
5388
+ * **DEPRECATED: Use getCollection() instead**
5389
+ * returns the Hub category for a given item type
5390
+ * @param itemType The ArcGIS [item type](https://developers.arcgis.com/rest/users-groups-and-items/items-and-item-types.htm).
5391
+ * @returns the category of a given item type.
5585
5392
  */
5586
- function _getAutoAddUsers(users, requestingUser) {
5587
- var usersToAutoAdd = [];
5588
- if (requestingUser.privileges.indexOf("portal:admin:assignToGroups") !== -1) {
5589
- var orgIds_1 = [requestingUser.orgId, requestingUser.cOrgId].filter(function (o) { return o; });
5590
- usersToAutoAdd = users.filter(function (u) { return orgIds_1.indexOf(u.orgId) !== -1; });
5591
- }
5592
- return usersToAutoAdd;
5393
+ function getCategory(itemType) {
5394
+ if (itemType === void 0) { itemType = ""; }
5395
+ /* tslint:disable no-console */
5396
+ console.warn("DEPRECATED: Use getCollection() instead. getCategory will be removed at v9.0.0");
5397
+ /* tslint:enable no-console */
5398
+ var collection = getCollection(itemType);
5399
+ // for backwards compatibility
5400
+ return collection === "feedback" ? "app" : collection;
5593
5401
  }
5594
-
5595
5402
  /**
5596
- * @private
5403
+ * ```js
5404
+ * import { getTypes } from "@esri/hub-common";
5405
+ * //
5406
+ * getTypes('site')
5407
+ * > [ 'hub site application' ]
5408
+ * ```
5409
+ * To do.
5410
+ * @param category The ArcGIS Hub category.
5411
+ * @returns all the item types for the given category.
5597
5412
  *
5598
- * A user will be invited if they cannot be auto-added
5599
5413
  */
5600
- function _getInviteUsers(users, requestingUser) {
5601
- var autoAddedUsers = _getAutoAddUsers(users, requestingUser);
5602
- return users.filter(function (user) { return !autoAddedUsers.some(function (aau) { return aau.username === user.username; }); });
5414
+ function getTypes(category) {
5415
+ if (category === void 0) { category = ""; }
5416
+ return categories[category.toLowerCase()];
5603
5417
  }
5604
-
5605
5418
  /**
5606
- * @private
5419
+ * ```js
5420
+ * import { normalizeItemType } from "@esri/hub-common";
5421
+ * //
5422
+ * normalizeItemType(item)
5423
+ * > [ 'Hub Site Application' ]
5424
+ * ```
5425
+ * @param item Item object.
5426
+ * @returns type of the input item.
5607
5427
  *
5608
- * A user can be emailed if they are invited (not auto-added)
5609
- * and the _canEmailUser condition is met
5610
5428
  */
5611
- function _getEmailUsers(users, requestingUser, includeSelf) {
5612
- if (includeSelf === void 0) { includeSelf = false; }
5613
- var invitedUsers = _getInviteUsers(users, requestingUser);
5614
- var emailUsers = invitedUsers.filter(function (user) {
5615
- return _canEmailUser(user, requestingUser);
5616
- });
5617
- if (includeSelf) {
5618
- emailUsers.push(requestingUser);
5429
+ function normalizeItemType(item) {
5430
+ if (item === void 0) { item = {}; }
5431
+ var ret = item.type;
5432
+ var typeKeywords = item.typeKeywords || [];
5433
+ if (item.type === "Site Application" ||
5434
+ (item.type === "Web Mapping Application" &&
5435
+ includes(typeKeywords, "hubSite"))) {
5436
+ ret = "Hub Site Application";
5619
5437
  }
5620
- return emailUsers;
5438
+ if (item.type === "Site Page" ||
5439
+ (item.type === "Web Mapping Application" &&
5440
+ includes(typeKeywords, "hubPage"))) {
5441
+ ret = "Hub Page";
5442
+ }
5443
+ if (item.type === "Hub Initiative" &&
5444
+ includes(typeKeywords, "hubInitiativeTemplate")) {
5445
+ ret = "Hub Initiative Template";
5446
+ }
5447
+ if (item.type === "Web Mapping Application" &&
5448
+ includes(typeKeywords, "hubSolutionTemplate")) {
5449
+ ret = "Solution";
5450
+ }
5451
+ return ret;
5621
5452
  }
5622
-
5623
5453
  /**
5624
- * Adds, invites or emails users about joining a group
5625
- * based on the permissions of the requesting user. The
5626
- * function returns a hash of results indicating which
5627
- * operations were attempted and whether they were successful.
5628
- *
5629
- * In general, this algorithm will auto-add all the users
5630
- * that it can, invite the others, and send emails to eligible
5631
- * invited users (See below for more details)
5632
- *
5633
- * Here are a couple caveats to be aware of:
5634
- * 1) If the requestingUser can auto-add to the group (A.K.A. has
5635
- * portal:admin:assignToGroups) no email will be sent, period.
5636
- * 2) Emails can only be sent to members of the same org as the
5637
- * requesting user if they have been invited (not auto-added)
5638
- * to the group. If emails must to be sent to invited members
5639
- * of a second org (e.g a community org), an authenticated user
5640
- * of the second org must be passed in (see secondaryRO)
5641
- * 3) If no email is passed in, no email will be sent
5642
- * 4) If auto-adding fails, the unadded users will be invited
5643
- *
5644
- * @param {string} groupId
5645
- * @param {IUser[]} allUsers
5646
- * @param {IHubRequestOptions} primaryRO Info and authentication for the requesting user
5647
- * @param {IEmail} [email] Email to be sent (if qualifying users are passed in)
5648
- * @param {IHubRequestOptions} [secondaryRO] Info and authentication for emailing members of a secondary organization (typically a community org)
5454
+ * ```js
5455
+ * import { getTypeCategories } from "@esri/hub-common";
5456
+ * //
5457
+ * getTypeCategories(item)
5458
+ * > [ 'Hub Site Application' ]
5459
+ * ```
5460
+ * @param item Item object.
5461
+ * @returns typeCategory of the input item.
5649
5462
  *
5650
- * @returns {IConsolidatedResult} The operations attempted, whether they were successful and any errors
5651
- */
5652
- function addUsersToGroup(groupId, allUsers, primaryRO, email, secondaryRO) {
5653
- // Extract requesting user
5654
- var requestingUser = cloneObject$1(getWithDefault$1(primaryRO, "portalSelf.user", {}));
5655
- requestingUser.cOrgId = getProp(primaryRO, "portalSelf.portalProperties.hub.settings.communityOrg.orgId");
5656
- // Context for each process segment
5657
- var context = {
5658
- groupId: groupId,
5659
- allUsers: allUsers,
5660
- primaryRO: primaryRO,
5661
- email: email,
5662
- secondaryRO: secondaryRO,
5663
- requestingUser: requestingUser,
5664
- usersToAutoAdd: _getAutoAddUsers(allUsers, requestingUser),
5665
- usersToInvite: _getInviteUsers(allUsers, requestingUser),
5666
- usersToEmail: _getEmailUsers(allUsers, requestingUser, getProp(email, "copyMe"))
5667
- };
5668
- return _processAutoAdd(context)
5669
- .then(_processInvite)
5670
- .then(_processPrimaryEmail)
5671
- .then(_processSecondaryEmail)
5672
- .then(_consolidateResults);
5673
- }
5674
-
5675
- /**
5676
- * Unprotect and Remove an Item
5677
- * Assumes caller has checked that the curernt user should be able to
5678
- * unprotect and remove the item. Underlying calls are failsafe
5679
- * so a failure to unprotect or temove the item will not reject.
5680
- * @param {IUserItemOptions} userItemOptions id and authentication
5681
- * @private
5682
5463
  */
5683
- function _unprotectAndRemoveItem(userItemOptions) {
5684
- var failSafeUnprotect = failSafe(unprotectItem, { success: true });
5685
- var failSafeRemove = failSafe(removeItem, { success: true });
5686
- return failSafeUnprotect(userItemOptions).then(function () {
5687
- return failSafeRemove(userItemOptions);
5688
- });
5464
+ function getTypeCategories(item) {
5465
+ if (item === void 0) { item = {}; }
5466
+ var type = normalizeItemType(item);
5467
+ var category = getCategory(type);
5468
+ if (category) {
5469
+ // upper case first letter and return as element in array for backwards compatibility
5470
+ var chars = Array.from(category);
5471
+ chars[0] = chars[0].toUpperCase();
5472
+ return [chars.join("")];
5473
+ }
5474
+ else {
5475
+ return ["Other"];
5476
+ }
5689
5477
  }
5690
-
5691
5478
  /**
5692
- * Apply a hash of properties to an array of items.
5693
- * Extracted to simplify testing.
5694
- * @param {array} items Array of items to apply the properties to
5695
- * @param {object} props hash of properties to apply to the item
5479
+ * ```js
5480
+ * import { getCollection } from "@esri/hub-common";
5481
+ * //
5482
+ * getCollection('Feature Layer')
5483
+ * > 'dataset'
5484
+ * ```
5485
+ * Get the Hub collection for a given item type
5486
+ * @param itemType The ArcGIS [item type](https://developers.arcgis.com/rest/users-groups-and-items/items-and-item-types.htm).
5487
+ * @returns the Hub collection of a given item type.
5696
5488
  */
5697
- function applyPropertiesToItems(items, props) {
5698
- return items.map(function (item) {
5699
- if (!item.properties) {
5700
- item.properties = {};
5489
+ function getCollection(itemType) {
5490
+ if (itemType === void 0) { itemType = ""; }
5491
+ if (cache[itemType]) {
5492
+ return cache[itemType];
5493
+ }
5494
+ for (var _i = 0, _a = Object.keys(collections); _i < _a.length; _i++) {
5495
+ var collection = _a[_i];
5496
+ for (var _b = 0, _c = collections[collection]; _b < _c.length; _b++) {
5497
+ var type = _c[_b];
5498
+ if (itemType.toLowerCase() === type.toLowerCase()) {
5499
+ cache[itemType] = collection;
5500
+ return collection;
5501
+ }
5701
5502
  }
5702
- Object.assign(item.properties, props);
5703
- return item;
5704
- });
5705
- }
5706
-
5707
- /**
5708
- * Delete a property from an object using a deep path
5709
- * MODIFIES PASSED TARGET
5710
- * @param {Object} target Object from which we want to delete the property
5711
- * @param {string} path Dotted path to the property we want to delete
5712
- */
5713
- function deleteProp(target, lookupStr) {
5714
- if (typeof target !== "object" || target === null)
5715
- return;
5716
- if (typeof lookupStr !== "string")
5717
- return;
5718
- var lookupKeys = lookupStr.split(".");
5719
- for (var i = 0; i < lookupKeys.length - 1; i++) {
5720
- if (!target.hasOwnProperty(lookupKeys[i]))
5721
- return;
5722
- target = target[lookupKeys[i]];
5723
5503
  }
5724
- delete target[lookupKeys[lookupKeys.length - 1]];
5725
5504
  }
5726
-
5727
5505
  /**
5728
- * Given a model, return a serialized clone that can be sent to
5729
- * the items api
5730
- * @param {Object} model Item model {item:{}, data:{}}
5506
+ * Case-insensitive check if the type is "Feature Service"
5507
+ * @param {string} type - item's type
5508
+ * @returns {boolean}
5731
5509
  */
5732
- function serializeModel(model) {
5733
- var serialized = cloneObject$1(model.item);
5734
- serialized.text = JSON.stringify(model.data);
5735
- return serialized;
5736
- }
5737
-
5510
+ var isFeatureService = function (type) {
5511
+ return type && type.toLowerCase() === "feature service";
5512
+ };
5738
5513
  /**
5739
- * Update a model's item, wrapped in a failSafe so this will not blow up if
5740
- * the user lacks rights somehow. This should be used in places where there is
5741
- * a high-probability that the current user CAN update the item.
5742
- * @param {Object} model Model object to be updated
5743
- * @param {IRequestOptions} requestOptions
5514
+ * parse layer id from a service URL
5515
+ * @param {string} url
5516
+ * @returns {string} layer id
5744
5517
  */
5745
- function failSafeUpdate(model, requestOptions) {
5746
- var failSafedUpdate = failSafe(updateItem, {
5747
- id: model.item.id,
5748
- success: true
5749
- });
5750
- var opts = Object.assign({ item: serializeModel(model) }, requestOptions);
5751
- return failSafedUpdate(opts);
5752
- }
5753
-
5518
+ var getLayerIdFromUrl = function (url) {
5519
+ var endsWithNumberSegmentRegEx = /\/\d+$/;
5520
+ var matched = url && url.match(endsWithNumberSegmentRegEx);
5521
+ return matched && matched[0].slice(1);
5522
+ };
5754
5523
  /**
5755
- * Gets the full item/data model for an item
5756
- * @param {string} id Id of the item to fetch
5757
- * @param {Object} requestOptions
5524
+ * return the layerId if we can tell that item is a single layer service
5525
+ * @param {*} item from AGO
5526
+ * @returns {string} layer id
5758
5527
  */
5759
- function getModel(id, requestOptions) {
5760
- return Promise.all([
5761
- getItem(id, requestOptions),
5762
- getItemData(id, requestOptions)
5763
- ]).then(function (result) {
5764
- // shape this into a model
5765
- return {
5766
- item: result[0],
5767
- data: result[1]
5768
- };
5769
- });
5770
- }
5771
-
5528
+ var getItemLayerId = function (item) {
5529
+ // try to parse it from the URL, but failing that we check for
5530
+ // the Singlelayer typeKeyword, which I think is set when you create the item in AGO
5531
+ // but have not verified that, nor that we should alway return '0' in that case
5532
+ return (getLayerIdFromUrl(item.url) ||
5533
+ (isFeatureService(item.type) &&
5534
+ includes(item.typeKeywords, "Singlelayer") &&
5535
+ "0"));
5536
+ };
5772
5537
  /**
5773
- * To streamline passing of either a model id or the model itself, we use this function
5774
- * to extract the model or fetch it, and return it. It uses `failSafe` and if the item
5775
- * is not accessible for whatever reason, will return a model-ish object with `isMissing: true`
5776
- * It is up to the caller to take approriate action
5777
- * @param {String} modelType the type of model to extract from the options hash
5778
- * @param {Object} options Something that extends IRequestOptions
5538
+ * given an item, get the id to use w/ the Hub API
5539
+ * @param item
5540
+ * @returns Hub API id (hubId)
5779
5541
  */
5780
- function getModelFromOptions(modelType, options) {
5781
- var modelProp = modelType + "Model";
5782
- var idProp = modelType + "Id";
5783
- // if the options hash has the model, return it
5784
- if (options[modelProp]) {
5785
- return Promise.resolve(options[modelProp]);
5542
+ var getItemHubId = function (item) {
5543
+ if (item.access !== "public") {
5544
+ // the hub only indexes public items
5545
+ return;
5786
5546
  }
5787
- else {
5788
- if (options[idProp]) {
5789
- var failSafeModel = failSafe(getModel, {
5790
- item: { id: options[idProp] },
5791
- isMissing: true
5792
- });
5793
- return failSafeModel(options[idProp], options);
5547
+ var id = item.id;
5548
+ var layerId = getItemLayerId(item);
5549
+ return layerId ? id + "_" + layerId : id;
5550
+ };
5551
+ /**
5552
+ * ```js
5553
+ * import { getContentIdentifier } from "@esri/hub-common";
5554
+ * //
5555
+ * getContentIdentifier(content, site)
5556
+ * > 'f12hhjk32' // id
5557
+ * // OR
5558
+ * > 'content-slug' // human-readable slug
5559
+ * ```
5560
+ * Returns the preferred identifier for a piece of content (determined by content type):
5561
+ * - Content from the 'template' and 'feedback' families return the standard id field
5562
+ * - Pages that are linked to the site parameter will return the slug defined by the site. Otherwise, the page id will be returned
5563
+ * - All other content will return the highest available item in the following hierarchy:
5564
+ * 1. slug - includes org prefix if the site parameter is a portal or has an orgKey different from the slug prefix
5565
+ * 2. hubId
5566
+ * 3. id
5567
+ * @param content The IHubContent item
5568
+ * @param site The site to compare content against
5569
+ * @returns the preferred id for the given content.
5570
+ */
5571
+ function getContentIdentifier(content, site) {
5572
+ // We don't currently support slugs for hub initiative templates, solutions or surveys
5573
+ if (includes(["template", "feedback"], content.family)) {
5574
+ return content.id;
5575
+ }
5576
+ // If it is a hub page linked to a site, return the page slug at the
5577
+ // site data instead. Because this one is the original one that was used
5578
+ // to create the page url (not mutable once created) and the slug (below)
5579
+ // generated by the hub-indexer could simply change with page name.
5580
+ // TODO: we check both "Hub Page" and "Site Page" because we don't know whether the site is a portal or not
5581
+ // In the future, the site object will have a site.isPortal() function that we can leverage
5582
+ // instead of hardcoding the types here.
5583
+ if (includes(["Hub Page", "Site Page"], content.type)) {
5584
+ // check if the page is linked to the current site
5585
+ var pages = getProp(site, "data.values.pages") || [];
5586
+ var page = pages.find(function (p) { return p.id === content.id; });
5587
+ // if so, return the page slug otherwise the page id
5588
+ return page ? page.slug : content.id;
5589
+ }
5590
+ // If a slug is present, always return it
5591
+ if (content.slug) {
5592
+ var slug = void 0;
5593
+ var orgKey = getProp(site, "domainInfo.orgKey");
5594
+ // Use namespaced slug when on the umbrella site
5595
+ if (getProp(site, "data.values.isUmbrella")) {
5596
+ slug = content.slug;
5794
5597
  }
5795
5598
  else {
5796
- throw new Error("getModelFromOptions requires either a ." + modelProp + " or ." + idProp + " property.");
5599
+ // Use shortened slug if the slug's namespace is the same as the orgKey
5600
+ slug = removeContextFromSlug(content.slug, orgKey);
5797
5601
  }
5602
+ return slug;
5798
5603
  }
5604
+ return content.hubId || content.id;
5799
5605
  }
5800
-
5606
+ //////////////////////
5607
+ // Slug Helpers
5608
+ //////////////////////
5801
5609
  /**
5802
- * adlib - v3.0.6 - Thu Dec 17 2020 17:08:08 GMT-0800 (Pacific Standard Time)
5803
- * Copyright (c) 2017-2020 Dave Bouwman / Esri
5804
- * Apache-2.0
5805
- */
5806
- /* Copyright (c) 2017-2019 Esri Inc.
5807
- Licensed under the Apache License, Version 2.0 (the "License");
5808
- you may not use this file except in compliance with the License.
5809
- You may obtain a copy of the License at
5810
- http://www.apache.org/licenses/LICENSE-2.0
5811
- Unless required by applicable law or agreed to in writing, software
5812
- distributed under the License is distributed on an "AS IS" BASIS,
5813
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5814
- See the License for the specific language governing permissions and
5815
- limitations under the License. */
5610
+ * Parse item ID and layer ID (if any) from dataset record ID
5611
+ *
5612
+ * @param datasetId Hub API dataset record id ({itemId}_{layerId} or {itemId})
5613
+ * @returns A hash with the `itemId` and `layerId` (if any)
5614
+ */
5615
+ function parseDatasetId(datasetId) {
5616
+ var _a = datasetId ? datasetId.split("_") : [], itemId = _a[0], layerId = _a[1];
5617
+ return { itemId: itemId, layerId: layerId };
5618
+ }
5619
+ /**
5620
+ * Determine if an identifier is a Hub API slug
5621
+ *
5622
+ * @param identifier Hub API slug ({orgKey}::{title-as-slug} or {title-as-slug})
5623
+ * or record id ((itemId}_{layerId} or {itemId})
5624
+ * @returns true if the identifier is valid _and_ is **not** a record id
5625
+ */
5626
+ function isSlug(identifier) {
5627
+ var itemId = parseDatasetId(identifier).itemId;
5628
+ if (!itemId || isGuid(itemId)) {
5629
+ // it's either invalid, or an item id, or a dataset id
5630
+ return false;
5631
+ }
5632
+ // otherwise assume it's a slug
5633
+ return true;
5634
+ }
5635
+ /**
5636
+ * Add a context (prefix) to slug if it doesn't already have one
5637
+ *
5638
+ * @param slug Hub API slug (with or without context)
5639
+ * @param context usually a portal's orgKey
5640
+ * @returns slug with context ({context}::{slug})
5641
+ */
5642
+ function addContextToSlug(slug, context) {
5643
+ // the slug has an org key already e.g. dc::crime-incidents
5644
+ if (/.+::.+/.test(slug)) {
5645
+ return slug;
5646
+ // the slug belongs to the org that owns the site e.g. crime-incidents
5647
+ }
5648
+ else {
5649
+ return context + "::" + slug;
5650
+ }
5651
+ }
5652
+ /**
5653
+ * Remove context (prefix) from a slug
5654
+ *
5655
+ * @param slug Hub API slug with context
5656
+ * @param context usually a portal's orgKey
5657
+ * @returns slug without context
5658
+ */
5659
+ function removeContextFromSlug(slug, context) {
5660
+ if (context && slug.match(context + "::")) {
5661
+ return slug.split(context + "::")[1];
5662
+ }
5663
+ else {
5664
+ return slug;
5665
+ }
5666
+ }
5667
+ /**
5668
+ * Splits item category strings at slashes and discards the "Categories" keyword
5669
+ *
5670
+ * ```
5671
+ * ["/Categories/Boundaries", "/Categories/Planning and cadastre/Property records", "/Categories/Structure"]
5672
+ * ```
5673
+ * Should end up being
5674
+ * ```
5675
+ * ["Boundaries", "Planning and cadastre", "Property records", "Structure"]
5676
+ * ```
5677
+ *
5678
+ * @param categories - an array of strings
5679
+ * @private
5680
+ */
5681
+ function parseItemCategories(categories) {
5682
+ if (!categories)
5683
+ return categories;
5684
+ var exclude = ["categories", ""];
5685
+ var parsed = categories.map(function (cat) { return cat.split("/"); });
5686
+ var flattened = parsed.reduce(function (acc, arr, _) { return __spreadArrays(acc, arr); }, []);
5687
+ return flattened.filter(function (cat) { return !includes(exclude, cat.toLowerCase()); });
5688
+ }
5689
+ /**
5690
+ * return the Hub family given an item's type
5691
+ * @param type item type
5692
+ * @returns Hub family
5693
+ */
5694
+ function getFamily(type) {
5695
+ var family;
5696
+ // override default behavior for the rows that are highlighted in yellow here:
5697
+ // https://esriis.sharepoint.com/:x:/r/sites/ArcGISHub/_layouts/15/Doc.aspx?sourcedoc=%7BADA1C9DC-4F6C-4DE4-92C6-693EF9571CFA%7D&file=Hub%20Routes.xlsx&nav=MTBfe0VENEREQzI4LUZFMDctNEI0Ri04NjcyLThCQUE2MTA0MEZGRn1fezIwMTIwMEJFLTA4MEQtNEExRC05QzA4LTE5MTAzOUQwMEE1RH0&action=default&mobileredirect=true&cid=df1c874b-c367-4cea-bc13-7bebfad3f2ac
5698
+ switch ((type || "").toLowerCase()) {
5699
+ case "image service":
5700
+ family = "dataset";
5701
+ break;
5702
+ case "feature service":
5703
+ case "raster layer":
5704
+ // TODO: check if feature service has > 1 layer first?
5705
+ family = "map";
5706
+ break;
5707
+ case "microsoft excel":
5708
+ family = "document";
5709
+ break;
5710
+ case "cad drawing":
5711
+ case "feature collection template":
5712
+ case "report template":
5713
+ family = "content";
5714
+ break;
5715
+ default:
5716
+ // by default derive from collection
5717
+ family = collectionToFamily(getCollection(type));
5718
+ }
5719
+ return family;
5720
+ }
5721
+ /**
5722
+ * DEPRECATED: Use getFamily() instead.
5723
+ *
5724
+ * get the HubType for a given item or item type
5725
+ *
5726
+ * @param itemOrType an item or item.type
5727
+ */
5728
+ function getItemHubType(itemOrType) {
5729
+ /* tslint:disable no-console */
5730
+ console.warn("DEPRECATED: Use getFamily() instead. getItemHubType() will be removed at v9.0.0");
5731
+ /* tslint:enable no-console */
5732
+ if (typeof itemOrType === "string") {
5733
+ itemOrType = { type: itemOrType };
5734
+ }
5735
+ var itemType = normalizeItemType(itemOrType);
5736
+ // TODO: not all categories are Hub types, may need to validate
5737
+ return getCollection(itemType);
5738
+ }
5739
+ /**
5740
+ * Convert a Portal item to Hub content
5741
+ *
5742
+ * @param item Portal Item
5743
+ * @returns Hub content
5744
+ * @export
5745
+ */
5746
+ function itemToContent(item) {
5747
+ var createdDate = new Date(item.created);
5748
+ var createdDateSource = "item.created";
5749
+ var properties = item.properties;
5750
+ var normalizedType = normalizeItemType(item);
5751
+ var content = Object.assign({}, item, {
5752
+ // no server errors when fetching the item directly
5753
+ errors: [],
5754
+ // store a reference to the item
5755
+ item: item,
5756
+ // NOTE: this will overwrite any existing item.name, which is
5757
+ // The file name of the item for file types. Read-only.
5758
+ // presumably there to use as the default file name when downloading
5759
+ // we don't store item.name in the Hub API and we use name for title
5760
+ name: item.title,
5761
+ family: getFamily(normalizedType),
5762
+ // TODO: hubType is no longer used, remove it at next breaking change
5763
+ hubType: getItemHubType(item),
5764
+ normalizedType: normalizedType,
5765
+ categories: parseItemCategories(item.categories),
5766
+ itemCategories: item.categories,
5767
+ // can we strip HTML from description, and do we need to trim it to a X chars?
5768
+ summary: item.snippet || item.description,
5769
+ publisher: {
5770
+ name: item.owner,
5771
+ username: item.owner,
5772
+ },
5773
+ permissions: {
5774
+ visibility: item.access,
5775
+ control: item.itemControl || "view",
5776
+ },
5777
+ // Hub app configuration metadata from item properties
5778
+ actionLinks: properties && properties.links,
5779
+ hubActions: properties && properties.actions,
5780
+ metrics: properties && properties.metrics,
5781
+ isDownloadable: isDownloadable(item),
5782
+ // default boundary from item.extent
5783
+ boundary: itemExtentToBoundary(item.extent),
5784
+ license: { name: "Custom License", description: item.accessInformation },
5785
+ // dates and sources we will enrich these later...
5786
+ createdDate: createdDate,
5787
+ createdDateSource: createdDateSource,
5788
+ publishedDate: createdDate,
5789
+ publishedDateSource: createdDateSource,
5790
+ updatedDate: new Date(item.modified),
5791
+ updatedDateSource: "item.modified",
5792
+ structuredLicense: getStructuredLicense(item.licenseInfo),
5793
+ });
5794
+ return content;
5795
+ }
5796
+ /**
5797
+ * Convert a Hub API dataset resource to Hub Content
5798
+ *
5799
+ * @param {DatasetResource} Dataset resource
5800
+ * @returns {IHubContent} Hub content object
5801
+ * @export
5802
+ */
5803
+ function datasetToContent(dataset) {
5804
+ // extract item from dataset, create content, & store a reference to the item
5805
+ var item = datasetToItem(dataset);
5806
+ var content = itemToContent(item);
5807
+ content.item = item;
5808
+ // We remove these because the indexer doesn't actually
5809
+ // preserve the original item categories so this attribute is invalid
5810
+ delete content.itemCategories;
5811
+ // overwrite hubId
5812
+ content.hubId = dataset.id;
5813
+ // overwrite or add enrichments from Hub API
5814
+ var attributes = dataset.attributes;
5815
+ var
5816
+ // common enrichments
5817
+ errors = attributes.errors, boundary = attributes.boundary, extent = attributes.extent, metadata = attributes.metadata, modified = attributes.modified, modifiedProvenance = attributes.modifiedProvenance, slug = attributes.slug, searchDescription = attributes.searchDescription, groupIds = attributes.groupIds,
5818
+ // map and feature server enrichments
5819
+ server = attributes.server, layers = attributes.layers,
5820
+ // NOTE: the Hub API also returns the following server properties
5821
+ // but we should be able to get them from the above server object
5822
+ // currentVersion, capabilities, tileInfo, serviceSpatialReference
5823
+ // maxRecordCount, supportedQueryFormats, etc
5824
+ // feature and raster layer enrichments
5825
+ layer = attributes.layer, recordCount = attributes.recordCount, statistics = attributes.statistics,
5826
+ // NOTE: the Hub API also returns the following layer properties
5827
+ // but we should be able to get them from the above layer object
5828
+ // supportedQueryFormats, supportsAdvancedQueries, advancedQueryCapabilities, useStandardizedQueries
5829
+ // geometryType, objectIdField, displayField, fields,
5830
+ // org properties?
5831
+ orgId = attributes.orgId, orgName = attributes.orgName, organization = attributes.organization, orgExtent = attributes.orgExtent,
5832
+ // NOTE: for layers and tables the Hub API returns the layer type
5833
+ // ("Feature Layer", "Table", "Raster Layer") instead of the item type
5834
+ type = attributes.type;
5835
+ // use the type returned by the API (i.e. possibly layer.type)
5836
+ content.type = type;
5837
+ content.normalizedType = normalizeItemType(__assign(__assign({}, content.item), { type: type }));
5838
+ content.family = getFamily(type);
5839
+ // NOTE: we could throw or return if there are errors
5840
+ // to prevent type errors trying to read properties below
5841
+ content.errors = errors;
5842
+ // common enrichments
5843
+ content.boundary = boundary;
5844
+ if (!isExtentCoordinateArray(item.extent) &&
5845
+ extent &&
5846
+ isExtentCoordinateArray(extent.coordinates)) {
5847
+ // we fall back to the extent derived by the API
5848
+ // which prefers layer or service extents and ultimately
5849
+ // falls back to the org's extent
5850
+ content.extent = extent.coordinates;
5851
+ }
5852
+ // setting this to null signals to enrichMetadata to skip this
5853
+ content.metadata = metadata || null;
5854
+ if (content.modified !== modified) {
5855
+ // capture the enriched modified date
5856
+ // NOTE: the item modified date is still available on content.item.modified
5857
+ content.modified = modified;
5858
+ content.updatedDate = new Date(modified);
5859
+ content.updatedDateSource = modifiedProvenance;
5860
+ }
5861
+ content.slug = slug;
5862
+ if (searchDescription) {
5863
+ // overwrite default summary (from snippet) w/ search description
5864
+ content.summary = searchDescription;
5865
+ }
5866
+ content.groupIds = groupIds;
5867
+ // server enrichments
5868
+ content.server = server;
5869
+ content.layers = layers;
5870
+ // layer enrichments
5871
+ content.layer = layer;
5872
+ content.recordCount = recordCount;
5873
+ content.statistics = statistics;
5874
+ // org enrichments
5875
+ if (orgId) {
5876
+ content.org = {
5877
+ id: orgId,
5878
+ name: orgName || organization,
5879
+ extent: orgExtent,
5880
+ };
5881
+ }
5882
+ return content;
5883
+ }
5884
+ /**
5885
+ * Convert a Hub API dataset resource to a portal item
5886
+ *
5887
+ * @param {DatasetResource} Dataset resource
5888
+ * @returns {IItem} portal item
5889
+ * @export
5890
+ */
5891
+ function datasetToItem(dataset) {
5892
+ if (!dataset) {
5893
+ return;
5894
+ }
5895
+ var id = dataset.id, attributes = dataset.attributes;
5896
+ if (!attributes) {
5897
+ return;
5898
+ }
5899
+ // parse item id
5900
+ var itemId = parseDatasetId(id).itemId;
5901
+ // read item properties from attributes
5902
+ // NOTE: we attempt to read all item properties
5903
+ // even though some may not be currently returned
5904
+ var
5905
+ // start w/ item properties from
5906
+ // https://developers.arcgis.com/rest/users-groups-and-items/item.htm
5907
+ owner = attributes.owner, orgId = attributes.orgId, created = attributes.created,
5908
+ // the Hub API returns item.modified in attributes.itemModified (below)
5909
+ modified = attributes.modified,
5910
+ // NOTE: we use attributes.name to store the title or the service/layer name
5911
+ // but in Portal name is only used for file types to store the file name (read only)
5912
+ name = attributes.name, title = attributes.title, type = attributes.type, typeKeywords = attributes.typeKeywords, description = attributes.description, snippet = attributes.snippet, tags = attributes.tags, thumbnail = attributes.thumbnail,
5913
+ // the Hub API returns item.extent in attributes.itemExtent (below)
5914
+ // extent,
5915
+ categories = attributes.categories, contentStatus = attributes.contentStatus,
5916
+ // the Hub API doesn't currently return spatialReference
5917
+ spatialReference = attributes.spatialReference,
5918
+ // the Hub API doesn't currently return accessInformation
5919
+ accessInformation = attributes.accessInformation, licenseInfo = attributes.licenseInfo, culture = attributes.culture, url = attributes.url, access = attributes.access,
5920
+ // the Hub API doesn't currently return proxyFilter
5921
+ proxyFilter = attributes.proxyFilter, properties = attributes.properties,
5922
+ // the Hub API doesn't currently return appCategories, industries,
5923
+ // languages, largeThumbnail, banner, screenshots, listed, ownerFolder
5924
+ appCategories = attributes.appCategories, industries = attributes.industries, languages = attributes.languages, largeThumbnail = attributes.largeThumbnail, banner = attributes.banner, screenshots = attributes.screenshots, listed = attributes.listed, ownerFolder = attributes.ownerFolder, size = attributes.size,
5925
+ // the Hub API doesn't currently return protected
5926
+ isProtected = attributes.protected, commentsEnabled = attributes.commentsEnabled,
5927
+ // the Hub API doesn't currently return numComments, numRatings,
5928
+ // avgRating, numViews, itemControl, scoreCompleteness
5929
+ numComments = attributes.numComments, numRatings = attributes.numRatings, avgRating = attributes.avgRating, numViews = attributes.numViews, itemControl = attributes.itemControl, scoreCompleteness = attributes.scoreCompleteness,
5930
+ // additional attributes we'll need
5931
+ // to derive the above values when missing
5932
+ itemExtent = attributes.itemExtent, itemModified = attributes.itemModified, modifiedProvenance = attributes.modifiedProvenance, serviceSpatialReference = attributes.serviceSpatialReference;
5933
+ // layer datasets will get their type from the layer
5934
+ // so we will need to derive the item type from the URL
5935
+ var serviceType = url && getServiceTypeFromUrl(url);
5936
+ // build and return an item from properties
5937
+ // NOTE: we currently do NOT provide default values
5938
+ // (i.e. null for scalar attributes, [] for arrays, etc)
5939
+ // for attributes that are not returned by the Hub API
5940
+ // this helps distinguish an item that comes from the API
5941
+ // but forces all consumers to do handle missing properties
5942
+ return {
5943
+ id: itemId,
5944
+ owner: owner,
5945
+ orgId: orgId,
5946
+ created: created,
5947
+ // for feature layers, modified will usually come from the layer so
5948
+ // we prefer itemModified, but fall back to modified if it came from the item
5949
+ modified: (itemModified ||
5950
+ (modifiedProvenance === "item.modified" && modified)),
5951
+ title: (title || name),
5952
+ type: serviceType || type,
5953
+ typeKeywords: typeKeywords,
5954
+ description: description,
5955
+ tags: tags,
5956
+ snippet: snippet,
5957
+ thumbnail: thumbnail,
5958
+ extent: itemExtent ||
5959
+ /* istanbul ignore next: API should always return itemExtent, but we default to [] just in case */ [],
5960
+ categories: categories,
5961
+ contentStatus: contentStatus,
5962
+ spatialReference: spatialReference || serviceSpatialReference,
5963
+ accessInformation: accessInformation,
5964
+ licenseInfo: licenseInfo,
5965
+ culture: culture,
5966
+ url: url,
5967
+ access: access,
5968
+ size: size,
5969
+ protected: isProtected,
5970
+ proxyFilter: proxyFilter,
5971
+ properties: properties,
5972
+ appCategories: appCategories,
5973
+ industries: industries,
5974
+ languages: languages,
5975
+ largeThumbnail: largeThumbnail,
5976
+ banner: banner,
5977
+ screenshots: screenshots,
5978
+ listed: listed,
5979
+ ownerFolder: ownerFolder,
5980
+ commentsEnabled: commentsEnabled,
5981
+ numComments: numComments,
5982
+ numRatings: numRatings,
5983
+ avgRating: avgRating,
5984
+ numViews: numViews,
5985
+ itemControl: itemControl,
5986
+ scoreCompleteness: scoreCompleteness,
5987
+ };
5988
+ }
5816
5989
 
5817
5990
  /**
5818
- * Return the value of a deep property, using a path.
5991
+ * Implementation of atob() according to the HTML and Infra specs, except that
5992
+ * instead of throwing INVALID_CHARACTER_ERR we return null.
5993
+ */
5994
+ function atob(data) {
5995
+ // Web IDL requires DOMStrings to just be converted using ECMAScript
5996
+ // ToString, which in our case amounts to using a template literal.
5997
+ data = `${data}`;
5998
+ // "Remove all ASCII whitespace from data."
5999
+ data = data.replace(/[ \t\n\f\r]/g, "");
6000
+ // "If data's length divides by 4 leaving no remainder, then: if data ends
6001
+ // with one or two U+003D (=) code points, then remove them from data."
6002
+ if (data.length % 4 === 0) {
6003
+ data = data.replace(/==?$/, "");
6004
+ }
6005
+ // "If data's length divides by 4 leaving a remainder of 1, then return
6006
+ // failure."
6007
+ //
6008
+ // "If data contains a code point that is not one of
6009
+ //
6010
+ // U+002B (+)
6011
+ // U+002F (/)
6012
+ // ASCII alphanumeric
6013
+ //
6014
+ // then return failure."
6015
+ if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) {
6016
+ return null;
6017
+ }
6018
+ // "Let output be an empty byte sequence."
6019
+ let output = "";
6020
+ // "Let buffer be an empty buffer that can have bits appended to it."
6021
+ //
6022
+ // We append bits via left-shift and or. accumulatedBits is used to track
6023
+ // when we've gotten to 24 bits.
6024
+ let buffer = 0;
6025
+ let accumulatedBits = 0;
6026
+ // "Let position be a position variable for data, initially pointing at the
6027
+ // start of data."
6028
+ //
6029
+ // "While position does not point past the end of data:"
6030
+ for (let i = 0; i < data.length; i++) {
6031
+ // "Find the code point pointed to by position in the second column of
6032
+ // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in
6033
+ // the first cell of the same row.
6034
+ //
6035
+ // "Append to buffer the six bits corresponding to n, most significant bit
6036
+ // first."
6037
+ //
6038
+ // atobLookup() implements the table from RFC 4648.
6039
+ buffer <<= 6;
6040
+ buffer |= atobLookup(data[i]);
6041
+ accumulatedBits += 6;
6042
+ // "If buffer has accumulated 24 bits, interpret them as three 8-bit
6043
+ // big-endian numbers. Append three bytes with values equal to those
6044
+ // numbers to output, in the same order, and then empty buffer."
6045
+ if (accumulatedBits === 24) {
6046
+ output += String.fromCharCode((buffer & 0xff0000) >> 16);
6047
+ output += String.fromCharCode((buffer & 0xff00) >> 8);
6048
+ output += String.fromCharCode(buffer & 0xff);
6049
+ buffer = accumulatedBits = 0;
6050
+ }
6051
+ // "Advance position by 1."
6052
+ }
6053
+ // "If buffer is not empty, it contains either 12 or 18 bits. If it contains
6054
+ // 12 bits, then discard the last four and interpret the remaining eight as
6055
+ // an 8-bit big-endian number. If it contains 18 bits, then discard the last
6056
+ // two and interpret the remaining 16 as two 8-bit big-endian numbers. Append
6057
+ // the one or two bytes with values equal to those one or two numbers to
6058
+ // output, in the same order."
6059
+ if (accumulatedBits === 12) {
6060
+ buffer >>= 4;
6061
+ output += String.fromCharCode(buffer);
6062
+ } else if (accumulatedBits === 18) {
6063
+ buffer >>= 2;
6064
+ output += String.fromCharCode((buffer & 0xff00) >> 8);
6065
+ output += String.fromCharCode(buffer & 0xff);
6066
+ }
6067
+ // "Return output."
6068
+ return output;
6069
+ }
6070
+ /**
6071
+ * A lookup table for atob(), which converts an ASCII character to the
6072
+ * corresponding six-bit number.
5819
6073
  */
5820
- var getWithDefault = function (obj, path, defaultValue) {
5821
- if ( defaultValue === void 0 ) defaultValue = undefined;
5822
6074
 
5823
- return path
5824
- .split('.')
5825
- .reduce(function (o, p) { return o ? o[p] : defaultValue; }, obj);
5826
- };
6075
+ const keystr$1 =
6076
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5827
6077
 
5828
- /* Copyright (c) 2017-2019 Esri Inc.
5829
- Licensed under the Apache License, Version 2.0 (the "License");
5830
- you may not use this file except in compliance with the License.
5831
- You may obtain a copy of the License at
5832
- http://www.apache.org/licenses/LICENSE-2.0
5833
- Unless required by applicable law or agreed to in writing, software
5834
- distributed under the License is distributed on an "AS IS" BASIS,
5835
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5836
- See the License for the specific language governing permissions and
5837
- limitations under the License. */
6078
+ function atobLookup(chr) {
6079
+ const index = keystr$1.indexOf(chr);
6080
+ // Throw exception if character is not in the lookup string; should not be hit in tests
6081
+ return index < 0 ? undefined : index;
6082
+ }
6083
+
6084
+ var atob_1 = atob;
5838
6085
 
5839
6086
  /**
5840
- * Simply Map over the props of an object
6087
+ * btoa() as defined by the HTML and Infra specs, which mostly just references
6088
+ * RFC 4648.
5841
6089
  */
5842
- function mapValues (obj, fn) {
5843
- var keys = Object.keys(obj);
5844
- // console.info(`keys: ${keys}`);
5845
- var newObject = keys.reduce(function(acc, currentKey) {
5846
- // console.log(` acc: ${JSON.stringify(acc)} curKey: ${currentKey}`);
5847
- acc[currentKey] = fn(obj[currentKey], currentKey, obj);
5848
- return acc;
5849
- }, {});
5850
- // console.info(` output: ${JSON.stringify(newObject)}`);
5851
- return newObject;
6090
+ function btoa(s) {
6091
+ let i;
6092
+ // String conversion as required by Web IDL.
6093
+ s = `${s}`;
6094
+ // "The btoa() method must throw an "InvalidCharacterError" DOMException if
6095
+ // data contains any character whose code point is greater than U+00FF."
6096
+ for (i = 0; i < s.length; i++) {
6097
+ if (s.charCodeAt(i) > 255) {
6098
+ return null;
6099
+ }
6100
+ }
6101
+ let out = "";
6102
+ for (i = 0; i < s.length; i += 3) {
6103
+ const groupsOfSix = [undefined, undefined, undefined, undefined];
6104
+ groupsOfSix[0] = s.charCodeAt(i) >> 2;
6105
+ groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
6106
+ if (s.length > i + 1) {
6107
+ groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
6108
+ groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
6109
+ }
6110
+ if (s.length > i + 2) {
6111
+ groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
6112
+ groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
6113
+ }
6114
+ for (let j = 0; j < groupsOfSix.length; j++) {
6115
+ if (typeof groupsOfSix[j] === "undefined") {
6116
+ out += "=";
6117
+ } else {
6118
+ out += btoaLookup(groupsOfSix[j]);
6119
+ }
6120
+ }
6121
+ }
6122
+ return out;
5852
6123
  }
5853
6124
 
5854
- /* Copyright (c) 2017-2019 Esri Inc.
5855
- Licensed under the Apache License, Version 2.0 (the "License");
5856
- you may not use this file except in compliance with the License.
5857
- You may obtain a copy of the License at
5858
- http://www.apache.org/licenses/LICENSE-2.0
5859
- Unless required by applicable law or agreed to in writing, software
5860
- distributed under the License is distributed on an "AS IS" BASIS,
5861
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5862
- See the License for the specific language governing permissions and
5863
- limitations under the License. */
6125
+ /**
6126
+ * Lookup table for btoa(), which converts a six-bit number into the
6127
+ * corresponding ASCII character.
6128
+ */
6129
+ const keystr =
6130
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5864
6131
 
5865
- var isDate = function (v) { return v instanceof Date; };
6132
+ function btoaLookup(index) {
6133
+ if (index >= 0 && index < 64) {
6134
+ return keystr[index];
6135
+ }
5866
6136
 
5867
- var isFunction = function (v) { return typeof v === 'function'; };
6137
+ // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
6138
+ return undefined;
6139
+ }
5868
6140
 
5869
- var isObject = function (v) { return typeof v === 'object'; };
6141
+ var btoa_1 = btoa;
5870
6142
 
5871
- var isRegExp = function (v) { return v instanceof RegExp; };
5872
-
5873
- function deepMapValues(object, callback, propertyPath) {
5874
- propertyPath = propertyPath || '';
5875
- if(Array.isArray(object)){
5876
- return object.map(deepMapValuesIteratee);
5877
- }
5878
- else if(object && isObject(object) && !isDate(object) && !isRegExp(object) && !isFunction(object)){
5879
- return Object.assign({}, object, mapValues(object, deepMapValuesIteratee));
5880
- }
5881
- else {
5882
- var output = callback(object, propertyPath);
5883
- return output;
5884
- }
5885
-
5886
- function deepMapValuesIteratee(value, key){
5887
- var valuePath = propertyPath ? propertyPath + '.' + key : key;
5888
- return deepMapValues(value, callback, valuePath);
5889
- }
5890
- }
5891
-
5892
- /* Copyright (c) 2017-2019 Esri Inc.
5893
- Licensed under the Apache License, Version 2.0 (the "License");
5894
- you may not use this file except in compliance with the License.
5895
- You may obtain a copy of the License at
5896
- http://www.apache.org/licenses/LICENSE-2.0
5897
- Unless required by applicable law or agreed to in writing, software
5898
- distributed under the License is distributed on an "AS IS" BASIS,
5899
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5900
- See the License for the specific language governing permissions and
5901
- limitations under the License. */
5902
-
5903
- var isObject$1 = function (v) { return typeof v === 'object'; };
6143
+ var abab = {
6144
+ atob: atob_1,
6145
+ btoa: btoa_1
6146
+ };
5904
6147
 
6148
+ var WGS84_WKID = "4326";
6149
+ var PORTAL_EXPORT_TYPES = {
6150
+ csv: {
6151
+ name: "CSV",
6152
+ itemTypes: ["CSV", "CSV Collection"],
6153
+ supportsProjection: true,
6154
+ },
6155
+ kml: {
6156
+ name: "KML",
6157
+ itemTypes: ["KML", "KML Collection"],
6158
+ supportsProjection: false,
6159
+ },
6160
+ shapefile: {
6161
+ name: "Shapefile",
6162
+ itemTypes: ["Shapefile"],
6163
+ supportsProjection: true,
6164
+ },
6165
+ fileGeodatabase: {
6166
+ name: "File Geodatabase",
6167
+ itemTypes: ["File Geodatabase"],
6168
+ supportsProjection: true,
6169
+ },
6170
+ geojson: {
6171
+ name: "GeoJson",
6172
+ itemTypes: ["GeoJson"],
6173
+ supportsProjection: false,
6174
+ },
6175
+ excel: {
6176
+ name: "Excel",
6177
+ itemTypes: ["Microsoft Excel"],
6178
+ supportsProjection: true,
6179
+ },
6180
+ featureCollection: {
6181
+ name: "Feature Collection",
6182
+ itemTypes: ["Feature Collection"],
6183
+ supportsProjection: true,
6184
+ },
6185
+ };
5905
6186
  /**
5906
- * Trim a tree decorated with `{{delete:NNN}}`
6187
+ * Puts a spatial reference into a serialized format that can be used
6188
+ * for item typeKeywords.
6189
+ *
6190
+ * **Note**: discards "latestWkid"
6191
+ *
6192
+ * In the past we used `JSON.stringify`, but that causes problems because
6193
+ * it can include commas which are interpreted by the portal [update item call](https://developers.arcgis.com/rest/users-groups-and-items/update-item.htm)
6194
+ * as being separate typekeywords. With `JSON.stringify`, equality was also
6195
+ * dependent on the order of the properties in the spatial reference.
6196
+ *
6197
+ * Check https://developers.arcgis.com/web-map-specification/objects/spatialReference/
6198
+ * for more details on what this object looks like.
5907
6199
  */
5908
- function arborist (object, propertyPath) {
5909
-
5910
- if(Array.isArray(object)){
5911
- // filter out any nulls...
5912
- var arrResults = object.map(iteratee).filter(function (entry) {
5913
- // need to ensure entry is actually NULL vs just falsey
5914
- return entry !== null && entry !== undefined;
5915
- });
5916
- return pruneArray(arrResults);
5917
-
5918
- } if(object && isObject$1(object) ) {
5919
-
5920
- return pruneObject(mapValues(object, iteratee));
5921
-
5922
- } else {
5923
-
5924
- return getPropertyValue(object);
5925
- }
5926
-
5927
- function iteratee(value, key){
5928
- return arborist(value);
5929
- }
6200
+ function serializeSpatialReference(spatialReference) {
6201
+ if (typeof spatialReference === "object") {
6202
+ var wkid = spatialReference.wkid, wkt = spatialReference.wkt;
6203
+ return wkid ? wkid + "" : abab.btoa(wkt);
6204
+ }
6205
+ else {
6206
+ return spatialReference;
6207
+ }
5930
6208
  }
5931
-
5932
6209
  /**
5933
- * Prune an array
5934
- * For all the entries in the array...
5935
- * if the entry is a naked string and contains `{{delete:NNN}}`
5936
- * get maximum NNN value
5937
- * then
5938
- * if maxN === 0
5939
- * return an empty array
5940
- * if maxN > 0
5941
- * return `{{delete:maxN-1}}`
5942
- * else
5943
- * return array
6210
+ * spatialRefId can currently take the form of either a WKID string or a
6211
+ * serialized ISpatialReference object.
6212
+ *
6213
+ * TODO - we shouldn't need this function. Instead, spatialRefId should
6214
+ * always be consistent, maybe by using serializeSpatialReference
6215
+ *
6216
+ * @private
5944
6217
  */
5945
- function pruneArray (arrResults) {
5946
- var res = arrResults;
5947
- // is any entry a string w/ {{delete}}?
5948
- var maxLevel = arrResults.reduce(function (maxLevel, e) {
5949
- if (isString(e) && hasDelete(e)) {
5950
- var lvl = getLevel(e);
5951
- if (lvl > maxLevel) {
5952
- maxLevel = lvl;
5953
- }
6218
+ function parseSpatialRefId(spatialRefId) {
6219
+ var _spatialRefId;
6220
+ try {
6221
+ _spatialRefId = JSON.parse(spatialRefId);
5954
6222
  }
5955
- return maxLevel;
5956
- }, -1);
5957
-
5958
- if (maxLevel > -1) {
5959
- if (maxLevel === 0) {
5960
- res = [];
5961
- } else {
5962
- res = "{{delete:" + (maxLevel - 1) + "}}";
6223
+ catch (_a) {
6224
+ _spatialRefId = spatialRefId;
5963
6225
  }
5964
- }
5965
-
5966
- return res;
6226
+ return _spatialRefId;
5967
6227
  }
5968
-
5969
-
5970
- function pruneObject (objResults) {
5971
- // console.log(` pruneObject:: working on ${JSON.stringify(objResults)}`);
5972
- var startVal = {obj: {}, maxLevel: -1 };
5973
- var res;
5974
- // cook a new clone object, and track the maxLevel
5975
- var reduction = Object.keys(objResults).reduce(function (acc, key) {
5976
- var val = objResults[key];
5977
- if (isString(val) && hasDelete(val)) {
5978
- var lvl = getLevel(val);
5979
- if (lvl > acc.maxLevel) {
5980
- acc.maxLevel = lvl;
5981
- }
5982
- } else {
5983
- // only add the prop if it's not a `{{delete:NNN}}`
5984
- acc.obj[key] = val;
6228
+ /**
6229
+ * Builds the Portal API query string to search for exports from a given dataset
6230
+ *
6231
+ * @param itemId - The dataset ID
6232
+ * @param options - A set of options including item types, layerId, and spatialRefId
6233
+ * @returns
6234
+ */
6235
+ function buildExistingExportsPortalQuery(itemId, options) {
6236
+ var _a = maybeExtractOptions(options), onlyTypes = _a.onlyTypes, layerId = _a.layerId, spatialRefId = _a.spatialRefId;
6237
+ var formatInfos = Object.keys(PORTAL_EXPORT_TYPES).map(function (key) { return PORTAL_EXPORT_TYPES[key]; });
6238
+ var noProjectionItemTypes = new Set(flattenArray(formatInfos
6239
+ .filter(function (info) { return !info.supportsProjection; })
6240
+ .map(function (info) { return info.itemTypes; })));
6241
+ var types;
6242
+ if (!onlyTypes) {
6243
+ types = flattenArray(formatInfos.map(function (info) { return info.itemTypes; }));
5985
6244
  }
5986
- return acc;
5987
- }, startVal);
5988
- // if -1, we return entire object...
5989
- // if 0 we just remove the prop...
5990
- // if 1 we return undefined...
5991
- // if > 1 we return the deleteVal
5992
- if (reduction.maxLevel > 0 ) {
5993
- if (reduction.maxLevel === 1) {
5994
- res = undefined;
5995
- } else {
5996
- res = "{{delete:" + (reduction.maxLevel - 1) + "}}";
6245
+ else {
6246
+ types = onlyTypes;
6247
+ }
6248
+ var queryBuilder = new SearchQueryBuilder()
6249
+ .startGroup()
6250
+ .match(getExportItemTypeKeyword(itemId))
6251
+ .in("typekeywords")
6252
+ .and()
6253
+ .match(getExportLayerTypeKeyword(layerId))
6254
+ .in("typekeywords")
6255
+ .endGroup()
6256
+ .and()
6257
+ .startGroup();
6258
+ buildExportTypesClause(queryBuilder, {
6259
+ types: types,
6260
+ spatialRefId: spatialRefId,
6261
+ noProjectionItemTypes: noProjectionItemTypes,
6262
+ });
6263
+ queryBuilder.endGroup();
6264
+ return queryBuilder.toParam();
6265
+ }
6266
+ function maybeExtractOptions(options) {
6267
+ if (options) {
6268
+ return {
6269
+ onlyTypes: options.onlyTypes,
6270
+ layerId: options.layerId,
6271
+ spatialRefId: options.spatialRefId,
6272
+ };
5997
6273
  }
5998
- } else {
5999
- res = reduction.obj;
6000
- }
6001
-
6002
- // console.log(` returning ${JSON.stringify(res)}`);
6003
- return res;
6274
+ return {};
6275
+ }
6276
+ function buildExportTypesClause(builder, options) {
6277
+ var types = options.types, noProjectionItemTypes = options.noProjectionItemTypes, spatialRefId = options.spatialRefId;
6278
+ var getSpatialRefIdWithDefaults = function (_spatialRefId, itemType) {
6279
+ var ret = WGS84_WKID;
6280
+ if (_spatialRefId && !noProjectionItemTypes.has(itemType)) {
6281
+ ret = _spatialRefId;
6282
+ }
6283
+ return ret;
6284
+ };
6285
+ var buildQueryForType = function (type, _builder) {
6286
+ _builder
6287
+ .startGroup()
6288
+ .match(/\s/g.test(type) ? type : "\"" + type + "\"") // temporary logic until https://github.com/Esri/arcgis-rest-js/issues/916 is resolved
6289
+ .in("type")
6290
+ .and()
6291
+ .match(getSpatialRefTypeKeyword(getSpatialRefIdWithDefaults(spatialRefId, type)))
6292
+ .in("typekeywords")
6293
+ .endGroup();
6294
+ };
6295
+ types.forEach(function (type, i) {
6296
+ buildQueryForType(type, builder);
6297
+ if (i < types.length - 1) {
6298
+ builder.or();
6299
+ }
6300
+ });
6004
6301
  }
6005
-
6006
6302
  /**
6007
- * Get a value for a property, handling the `{{delete:NNN}}` syntax
6303
+ * Generates typekeyword for identifying which spatialRefId an export is
6304
+ * @param spatialRefId - either a WKID, WKT, or stringified ISpatialReference
6305
+ * @private
6008
6306
  */
6009
- function getPropertyValue (val){
6010
- var output = val;
6011
-
6012
- if (typeof val === 'string') {
6013
- if (hasDelete(val)) {
6014
- output = getDeleteValue(val);
6015
- }
6016
- }
6017
- return output;
6307
+ function getSpatialRefTypeKeyword(spatialRefId) {
6308
+ var parsedSpatialReference = parseSpatialRefId(spatialRefId);
6309
+ var serializedSpatialReference = serializeSpatialReference(parsedSpatialReference);
6310
+ return "spatialRefId:" + serializedSpatialReference;
6018
6311
  }
6019
-
6020
6312
  /**
6021
- * Given a string with `{{delete:NNN}}`
6022
- * if NNN === 0 return undefined
6023
- * else return `{{delete:NNN - 1}}`
6313
+ * Returns the keyword identifying exports by the item they originate from
6314
+ * @param itemId - ID for the item from which the export originated
6315
+ * @private
6024
6316
  */
6025
- function getDeleteValue (val) {
6026
- var output = val;
6027
- var level = getLevel(val);
6028
- if (level === 0) {
6029
- output = undefined;
6030
- } else {
6031
- output = "{{delete:" + level + "}}";
6032
- }
6033
- return output;
6317
+ function getExportItemTypeKeyword(itemId) {
6318
+ return "exportItem:" + itemId;
6034
6319
  }
6035
-
6036
6320
  /**
6037
- * Extract the level from a `{{delete:NNN}}`
6321
+ * Returns the keyword identifying exports by the layer they originate from
6322
+ * @param layerId - ID for the layer from which the export originated
6323
+ * @private
6038
6324
  */
6039
- var getLevel = function (value) { return parseInt(value.replace(/{|}/g, '').split(':')[1]); };
6325
+ function getExportLayerTypeKeyword(layerId) {
6326
+ // NOTE - Layer Id's need to be padded with "0" so that /search results are predictable. Searches for typeKeywords:"exportLayer:1" don't work.
6327
+ // See https://github.com/Esri/hub.js/pull/472 for more information.
6328
+ // TODO - use `filter` when Enterprise Sites adds support.
6329
+ return layerId ? "exportLayer:0" + layerId : "exportLayer:null";
6330
+ }
6040
6331
 
6041
6332
  /**
6042
- * Simple check if a value has `{{delete` in it
6333
+ * Unprotect and Remove a Group.
6334
+ * Assumed caller has checked that the current user should be able
6335
+ * to unprotect and remove the group. Underlying calls are failsafe
6336
+ * so a failure to unprotect or remove the group will not reject
6337
+ * @param {IUserGroupOptions} userGroupOptions id and authentication
6338
+ * @private
6043
6339
  */
6044
- function hasDelete (value) {
6045
- if (value && typeof value === 'string') {
6046
- return value.indexOf('{{delete') > -1;
6047
- } else {
6048
- return false;
6049
- }
6340
+ function _unprotectAndRemoveGroup(userGroupOptions) {
6341
+ var failSafeUnprotect = failSafe(unprotectGroup, { success: true });
6342
+ var failSafeRemove = failSafe(removeGroup, { success: true });
6343
+ return failSafeUnprotect(userGroupOptions).then(function () {
6344
+ return failSafeRemove(userGroupOptions);
6345
+ });
6050
6346
  }
6051
6347
 
6052
- var isString = function (v) { return typeof v === 'string'; };
6053
-
6054
- /* Copyright (c) 2017-2019 Esri Inc.
6055
- Licensed under the Apache License, Version 2.0 (the "License");
6056
- you may not use this file except in compliance with the License.
6057
- You may obtain a copy of the License at
6058
- http://www.apache.org/licenses/LICENSE-2.0
6059
- Unless required by applicable law or agreed to in writing, software
6060
- distributed under the License is distributed on an "AS IS" BASIS,
6061
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6062
- See the License for the specific language governing permissions and
6063
- limitations under the License. */
6348
+ /**
6349
+ * @private
6350
+ */
6351
+ function _consolidateResults(context) {
6352
+ var autoAddResult = context.autoAddResult, inviteResult = context.inviteResult, primaryEmailResult = context.primaryEmailResult, secondaryEmailResult = context.secondaryEmailResult;
6353
+ var combinedEmailResults;
6354
+ if (primaryEmailResult || secondaryEmailResult) {
6355
+ var validResults = [primaryEmailResult, secondaryEmailResult].filter(function (r) { return r; });
6356
+ var combinedSuccess = validResults.every(function (r) { return r.success; });
6357
+ var combinedErrors = validResults.reduce(function (collection, r) { return collection.concat(getWithDefault$1(r, "errors", [])); }, []);
6358
+ combinedEmailResults = {
6359
+ success: combinedSuccess
6360
+ };
6361
+ if (combinedErrors.length) {
6362
+ combinedEmailResults.errors = combinedErrors;
6363
+ }
6364
+ }
6365
+ var overallSuccess = [autoAddResult, inviteResult, combinedEmailResults]
6366
+ .filter(function (r) { return r; })
6367
+ .every(function (r) { return r.success; });
6368
+ return {
6369
+ success: overallSuccess,
6370
+ autoAdd: autoAddResult,
6371
+ invite: inviteResult,
6372
+ email: combinedEmailResults
6373
+ };
6374
+ }
6064
6375
 
6065
6376
  /**
6066
- * Optional Transform
6067
- * Supports a declarative syntax for optional template properties
6377
+ * @private
6068
6378
  *
6069
- * {{some.object.key:optional:2}}
6379
+ * Coerce autoAdd response into a more similar interface as
6380
+ * the other rest calls.
6070
6381
  *
6071
- * In this example, if defined, the value of `some.object.key` is used.
6072
- * If not defined, then the optional transform is utilized
6073
- * and a post-processing step is executed which will remove two parent levels
6074
- * from the output structure
6382
+ * If any users are not auto added, an error is added to the response
6383
+ * and unadded users are placed into the invitation list
6075
6384
  */
6076
-
6077
- function optionalTransform(key, value, settings, level) {
6078
- if ( level === void 0 ) level = 0;
6079
-
6080
- // console.log(`optional: ${key}, ${value}, ${level}`);
6081
- var val = value;
6082
- if (!value) {
6083
- val = "{{delete:" + level + "}}";
6084
- }
6085
- return val;
6385
+ function _formatAutoAddResponse(rawResponse, context) {
6386
+ if (rawResponse) {
6387
+ var success = !getProp(rawResponse, "notAdded.length") && !rawResponse.errors;
6388
+ context.autoAddResult = { success: success };
6389
+ if (!success) {
6390
+ var errors = rawResponse.errors || [];
6391
+ if (getProp(rawResponse, "notAdded.length")) {
6392
+ errors.push(new ArcGISRequestError("Users not auto-added: " + rawResponse.notAdded.join(", ")));
6393
+ }
6394
+ context.autoAddResult.errors = errors;
6395
+ // Move unadded users to invite list;
6396
+ var unaddedUsers = context.usersToAutoAdd.filter(function (user) {
6397
+ return includes(rawResponse.notAdded, user.username);
6398
+ });
6399
+ context.usersToInvite = context.usersToInvite.concat(unaddedUsers);
6400
+ }
6401
+ }
6402
+ return context;
6086
6403
  }
6087
6404
 
6088
- /* Copyright (c) 2017-2019 Esri Inc.
6089
- Licensed under the Apache License, Version 2.0 (the "License");
6090
- you may not use this file except in compliance with the License.
6091
- You may obtain a copy of the License at
6092
- http://www.apache.org/licenses/LICENSE-2.0
6093
- Unless required by applicable law or agreed to in writing, software
6094
- distributed under the License is distributed on an "AS IS" BASIS,
6095
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6096
- See the License for the specific language governing permissions and
6097
- limitations under the License. */
6098
-
6099
6405
  /**
6100
- * ```js
6101
- * import { cloneObject } from "./cloneObject";
6102
- * const original = { foo: "bar" }
6103
- * const copy = cloneObject(original)
6104
- * copy.foo // "bar"
6105
- * copy === original // false
6106
- * ```
6107
- * Make a deep clone, including arrays. Does not handle functions!
6406
+ * @private
6108
6407
  *
6109
- * Copied from @esri/hub-common to avoid bringing along that package's
6110
- * dependencies, @esri/hub-common should be made a dependency if more
6111
- * functions are needed from it in the future
6408
+ * returns whether or not the users are in the same org
6112
6409
  */
6113
- var cloneObject = function (obj) {
6114
- var clone = {};
6115
- // first check array
6116
- if (Array.isArray(obj)) {
6117
- clone = obj.map(cloneObject);
6118
- } else if (typeof obj === "object") {
6119
- for (var i in obj) {
6120
- if (obj[i] != null && typeof obj[i] === "object") {
6121
- clone[i] = cloneObject(obj[i]);
6122
- } else {
6123
- clone[i] = obj[i];
6124
- }
6125
- }
6126
- } else {
6127
- clone = obj;
6128
- }
6129
- return clone;
6130
- };
6131
-
6132
- /* Copyright (c) 2017-2019 Esri Inc.
6133
- Licensed under the Apache License, Version 2.0 (the "License");
6134
- you may not use this file except in compliance with the License.
6135
- You may obtain a copy of the License at
6136
- http://www.apache.org/licenses/LICENSE-2.0
6137
- Unless required by applicable law or agreed to in writing, software
6138
- distributed under the License is distributed on an "AS IS" BASIS,
6139
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6140
- See the License for the specific language governing permissions and
6141
- limitations under the License. */
6142
- var HANDLEBARS = /{{\s*?[\w].*?}}/g;
6410
+ function _canEmailUser(recipient, sender) {
6411
+ return recipient.orgId === sender.orgId;
6412
+ }
6143
6413
 
6144
- var isString$1 = function (v) { return typeof v === 'string'; };
6414
+ /**
6415
+ * @private
6416
+ */
6417
+ function _isOrgAdmin(user) {
6418
+ return user.role === "org_admin" && !user.roleId;
6419
+ }
6145
6420
 
6146
- function _swap(parameter, settings, transforms) {
6147
- var value;
6148
- // console.info(`_swap: param: ${parameter}`);
6149
- // Parameters can optionally call transform functions
6150
- // e.g. "{{ipsum:translateLatin}}"
6151
- // so extract {{<parameter>:<transformFunction>:<key||value>}}
6152
- var transformCheck = parameter.split(':');
6153
- if (transformCheck.length > 1) {
6154
- // we have a request to use a transform...
6155
- var key = transformCheck[0];
6156
- var fn = transformCheck[1];
6157
- // we default to using the value...
6158
- var param;
6159
- if (transformCheck[2]){
6160
- param = transformCheck[2];
6161
- }
6162
- if(transforms && transforms[fn] && typeof transforms[fn] === 'function') {
6163
- // get the value from the param
6164
- value = getWithDefault(settings, key);
6165
- // transform it...
6166
- value = transforms[fn](key, value, settings, param);
6167
- } else {
6168
- throw new Error(("Attempted to apply non-existant transform " + fn + " on " + key + " with params " + parameter));
6421
+ /**
6422
+ * Attempts to email members of the requesting user's organization.
6423
+ *
6424
+ * @param {IUser[]} users Users to email (must be in the same org as the requesting user)
6425
+ * @param {IEmail} email
6426
+ * @param {IAuthenticationManager} authentication
6427
+ * @param {boolean} isOrgAdmin // Whether the requesting user in an org admin
6428
+ *
6429
+ * @returns {object|null} A promise that resolves to the result of the transaction (null if no users are passed in)
6430
+ */
6431
+ function emailOrgUsers(users, email, authentication, isOrgAdmin) {
6432
+ var response = Promise.resolve(null);
6433
+ if (users.length) {
6434
+ var args = {
6435
+ authentication: authentication,
6436
+ message: email.body,
6437
+ subject: email.subject,
6438
+ notificationChannelType: "email",
6439
+ users: users.map(function (u) { return u.username; })
6440
+ };
6441
+ if (!isOrgAdmin) {
6442
+ args.batchSize = 1;
6443
+ }
6444
+ response = createOrgNotification(args);
6169
6445
  }
6170
- } else {
6171
- // we just get the value
6172
- value = getWithDefault(settings, parameter);
6173
- }
6174
- return value;
6446
+ return response;
6175
6447
  }
6176
6448
 
6177
6449
  /**
6178
- * Does a propertyPath exist on a target
6450
+ * @private
6451
+ *
6452
+ * If a secondary authentication is passed in AND
6453
+ * an email object is passed in AND
6454
+ * the previous invitation call was successful:
6455
+ *
6456
+ * Send an email notification to the invited
6457
+ * users that are part of the secondary authentication's org
6179
6458
  */
6180
- function _propertyPathExists (propertyPath, target) {
6181
- // remove any transforms
6182
- var cleanPath = propertyPath.split(':')[0];
6183
- var value = getWithDefault(target, cleanPath, null);
6184
- if (value !== null && value !== undefined) {
6185
- return true;
6186
- } else {
6187
- return false;
6188
- }
6459
+ function _processSecondaryEmail(context) {
6460
+ var response = Promise.resolve(context);
6461
+ // If secondaryRO provided, send email to the invited users in the secondaryRO's org (typically a community org)
6462
+ if (context.email &&
6463
+ context.secondaryRO &&
6464
+ getProp(context, "inviteResult.success")) {
6465
+ var secondaryUser_1 = getWithDefault$1(context, "secondaryRO.portalSelf.user", {});
6466
+ var secondaryOrgUsersToEmail = context.usersToInvite.filter(function (u) {
6467
+ return _canEmailUser(u, secondaryUser_1);
6468
+ });
6469
+ response = emailOrgUsers(secondaryOrgUsersToEmail, context.email, context.secondaryRO.authentication, _isOrgAdmin(secondaryUser_1)).then(function (result) {
6470
+ context.secondaryEmailResult = result;
6471
+ return context;
6472
+ });
6473
+ }
6474
+ return response;
6189
6475
  }
6190
6476
 
6191
6477
  /**
6192
- * Is the value considered valid
6478
+ *
6479
+ * Attempts to auto-add users to a group
6480
+ *
6481
+ * @param {string} id ID of the group the users will be added to
6482
+ * @param {IUser[]} users
6483
+ * @param {IAuthenticationManager} authentication
6484
+ *
6485
+ * @returns {IAddGroupUsersResult|null} Result of the transaction (null if no users are passed in)
6193
6486
  */
6194
- function _isValue (val) {
6195
- return val || val === '' || val === 0;
6487
+ function autoAddUsers(id, users, authentication) {
6488
+ var response = Promise.resolve(null);
6489
+ if (users.length) {
6490
+ var args = {
6491
+ id: id,
6492
+ users: users.map(function (u) { return u.username; }),
6493
+ authentication: authentication
6494
+ };
6495
+ response = addGroupUsers(args);
6496
+ }
6497
+ return response;
6196
6498
  }
6197
6499
 
6198
- // Combine a Template with Settings
6199
- function adlib (template, settings, transforms) {
6200
- if ( transforms === void 0 ) transforms = null;
6201
-
6202
- transforms = cloneObject(transforms) || {};
6203
- if (transforms.optional) {
6204
- throw new Error('Please do not pass in an `optional` transform; adlib provides that internally.');
6205
- } else {
6206
- transforms.optional = optionalTransform;
6207
- }
6500
+ /**
6501
+ * @private
6502
+ */
6503
+ function _processAutoAdd(context) {
6504
+ return autoAddUsers(getProp(context, "groupId"), getProp(context, "usersToAutoAdd"), getProp(context, "primaryRO.authentication")).then(function (rawResponse) { return _formatAutoAddResponse(rawResponse, context); });
6505
+ }
6208
6506
 
6209
- var res = deepMapValues(template, function(templateValue, templatePath){
6210
- // Only string templates
6211
- if (!isString$1(templateValue)) {
6212
- return templateValue;
6507
+ /**
6508
+ *
6509
+ * Attempts to invite users to a group
6510
+ *
6511
+ * @param {string} id ID of the group the users will be invited to
6512
+ * @param {object[]} users
6513
+ * @param {object} authentication
6514
+ * @param {number} expiration How long the invite will be active (in minutes)
6515
+ * @param {string} role What role should they be added as. Defaults to group member
6516
+ *
6517
+ * @returns {object|null} Result of the transaction (null if no users are passed in)
6518
+ */
6519
+ function inviteUsers(id, users, authentication, expiration, // default to 2 week expiration TODO: is this actually 2 weeks?
6520
+ role // default to group member, but allow for team_admin as well
6521
+ ) {
6522
+ if (expiration === void 0) { expiration = 20160; }
6523
+ if (role === void 0) { role = "group_member"; }
6524
+ var response = Promise.resolve(null);
6525
+ if (users.length) {
6526
+ var args = {
6527
+ id: id,
6528
+ users: users.map(function (u) { return u.username; }),
6529
+ authentication: authentication,
6530
+ role: role,
6531
+ expiration: expiration,
6532
+ };
6533
+ response = inviteGroupUsers(args);
6213
6534
  }
6535
+ return response;
6536
+ }
6214
6537
 
6215
- // When we match "{{layer.fields..}}"
6216
- var settingsValue;
6217
-
6218
- var hbsEntries = templateValue.match(HANDLEBARS);
6538
+ /**
6539
+ * @private
6540
+ */
6541
+ function _processInvite(context) {
6542
+ return inviteUsers(getProp(context, "groupId"), getProp(context, "usersToInvite"), getProp(context, "primaryRO.authentication")).then(function (result) {
6543
+ context.inviteResult = result;
6544
+ return context;
6545
+ });
6546
+ }
6219
6547
 
6220
- if (hbsEntries && hbsEntries.length) {
6221
- // console.log(`Got a ${hbsEntries.length} handlebar entries...`);
6222
- // iterate over the entries...
6223
- var values = hbsEntries.map(function (entry) {
6224
- var isStaticValue = false;
6225
- // console.info(`Matched ${entry}...`);
6226
- // strip off the curlies and trim any leading/trailing whitespace...
6227
- var path = entry.replace(/{|}/g, '').trim();
6228
- // check for || which indicate a hiearchy
6229
- if (path.indexOf('||') > -1) {
6230
- var paths = path.split('||').map(function (path) { return path.trim(); });
6231
- var numberOfPaths = paths.length;
6232
- // here we check each option, in order, and return the first with a value in the hash, OR the last
6233
- path = paths.find(function (pathOption, idx) {
6234
- // console.info(`Checking to see if ${pathOption} is in settings hash...`);
6235
- var exists = _propertyPathExists(pathOption, settings);
6236
- if (!exists) {
6237
- if ((idx + 1) === numberOfPaths) {
6238
- // console.info(`Got to last entry, and still did not find anything... assuming ${pathOption} is a static value...`);
6239
- isStaticValue = true;
6240
- // check if we can convert this into a number...
6241
- if (!isNaN(pathOption)) {
6242
- pathOption = parseInt(pathOption);
6243
- }
6244
- return pathOption;
6245
- } else {
6246
- return false;
6247
- }
6248
- } else {
6249
- return pathOption;
6250
- }
6251
- });
6252
- }
6253
- // setup the return value...
6254
- var result = {
6255
- key: entry,
6256
- value: path
6257
- };
6258
- // if we have a valid object path, value comes from _swap
6259
- if (!isStaticValue) {
6260
- var swap = _swap(path, settings, transforms);
6261
- result.value = _isValue(swap) ? swap : entry;
6262
- }
6263
- // console.info(`Value: ${JSON.stringify(result)}`);
6264
- return result;
6265
- });
6266
-
6267
- values.forEach(function (v) {
6268
- // console.log(`Comparing ${templateValue} with ${v.key}`)
6269
- if (templateValue === v.key) {
6270
- // console.log(`template matches key, returning ${v.value}`);
6271
- // if the value is a string...
6272
- if (typeof v.value === 'string') {
6273
- // and it's numeric-ish
6274
- if(!isNaN(v.value) && v.value !== '') {
6275
- // and has a . in it...
6276
- if (v.value.indexOf('.') > -1) {
6277
- // parse as a float...
6278
- v.value = parseFloat(v.value);
6279
- } else {
6280
- // parse as an int
6281
- v.value = parseInt(v.value);
6282
- }
6283
- }
6284
- }
6285
- settingsValue = v.value;
6286
- } else {
6287
- // a little extra regex dance to match the '||' because '|'
6288
- // is a Very Special Regex Character and we need to super
6289
- // escape them for the regex to work
6290
- // console.log(`KEY ${v.key}`);
6291
- // console.log(`TEMPLATE ${templateValue}`);
6292
- templateValue = templateValue.replace(v.key, v.value);
6293
- // console.log(`template did not match key, interpolating value ${v.value} into template to produce ${templateValue}`);
6294
- }
6295
- });
6296
-
6297
- // if we have a value, let's return that...
6298
- if (_isValue(settingsValue)) {
6299
- // console.log(`We found a value so we return it ${settingsValue}`);
6300
- return settingsValue;
6301
- } else {
6302
- // console.log(`We did not find a value so we return the template ${templateValue}`);
6303
- // but if we don't, lets return the template itself
6304
- return templateValue;
6305
- }
6306
- } else {
6307
- // console.log(`We did not find a hbs match, so we return the template ${templateValue}`);
6308
- // no match, return the templateValue...
6309
- return templateValue;
6548
+ /**
6549
+ * @private
6550
+ *
6551
+ * Send email notification if an email object is present and
6552
+ * the previous invitation call was successful
6553
+ */
6554
+ function _processPrimaryEmail(context) {
6555
+ var response = Promise.resolve(context);
6556
+ // Email users if invite succeeds
6557
+ if (context.email && getProp(context, "inviteResult.success")) {
6558
+ response = emailOrgUsers(context.usersToEmail, context.email, context.primaryRO.authentication, _isOrgAdmin(context.requestingUser)).then(function (result) {
6559
+ context.primaryEmailResult = result;
6560
+ return context;
6561
+ });
6310
6562
  }
6311
- });
6312
- return arborist(res);
6563
+ return response;
6313
6564
  }
6314
6565
 
6315
6566
  /**
6316
- * Interpolates handlebars-style placeholders on an object graph
6317
- * @param template
6318
- * @param settings
6319
- * @param transforms
6567
+ * @private
6568
+ *
6569
+ * A user can be auto-added if they are part of the requesting user's e-org
6570
+ * or c-org and the requesting user has the assignToGroups privilege
6320
6571
  */
6321
- function interpolate(template, settings, transforms) {
6322
- return adlib(template, settings, transforms);
6572
+ function _getAutoAddUsers(users, requestingUser) {
6573
+ var usersToAutoAdd = [];
6574
+ if (requestingUser.privileges.indexOf("portal:admin:assignToGroups") !== -1) {
6575
+ var orgIds_1 = [requestingUser.orgId, requestingUser.cOrgId].filter(function (o) { return o; });
6576
+ usersToAutoAdd = users.filter(function (u) { return orgIds_1.indexOf(u.orgId) !== -1; });
6577
+ }
6578
+ return usersToAutoAdd;
6323
6579
  }
6324
6580
 
6325
6581
  /**
6326
- * Interpolate the item id back into any {{appid}} instances
6327
- * in the item. Allows for self-referencing in templates
6328
- * @param {object} model Item Model
6582
+ * @private
6583
+ *
6584
+ * A user will be invited if they cannot be auto-added
6329
6585
  */
6330
- function interpolateItemId(model) {
6331
- var settings = { item: { id: model.item.id }, appid: model.item.id };
6332
- var transforms = {
6333
- toISO: function (_, v) {
6334
- return v;
6335
- }
6336
- };
6337
- return interpolate(model, settings, transforms);
6586
+ function _getInviteUsers(users, requestingUser) {
6587
+ var autoAddedUsers = _getAutoAddUsers(users, requestingUser);
6588
+ return users.filter(function (user) { return !autoAddedUsers.some(function (aau) { return aau.username === user.username; }); });
6338
6589
  }
6339
6590
 
6340
- var itemPropsNotInTemplates = [
6341
- "id",
6342
- "isOrgItem",
6343
- "proxyFilter",
6344
- "ownerFolder",
6345
- "protected",
6346
- "owner",
6347
- "created",
6348
- "modified",
6349
- "guid",
6350
- "name",
6351
- "access",
6352
- "size",
6353
- "listed",
6354
- "numComments",
6355
- "numRatings",
6356
- "avgRating",
6357
- "numViews",
6358
- "scoreCompleteness",
6359
- "groupDesignations",
6360
- "listed",
6361
- "screenshots",
6362
- "banner",
6363
- "appCategories",
6364
- "industries",
6365
- "languages",
6366
- "largeThumbnail"
6367
- ];
6368
6591
  /**
6369
- * Given an item, remove a standard set of properties not needed in a template
6370
- * TODO: This should land in a templating helper lib in hub.js
6371
- * @param {Object} item Item to be normalized
6592
+ * @private
6593
+ *
6594
+ * A user can be emailed if they are invited (not auto-added)
6595
+ * and the _canEmailUser condition is met
6372
6596
  */
6373
- function normalizeSolutionTemplateItem(item) {
6374
- var template = cloneObject$1(item);
6375
- itemPropsNotInTemplates.forEach(function (prop) {
6376
- delete template[prop];
6597
+ function _getEmailUsers(users, requestingUser, includeSelf) {
6598
+ if (includeSelf === void 0) { includeSelf = false; }
6599
+ var invitedUsers = _getInviteUsers(users, requestingUser);
6600
+ var emailUsers = invitedUsers.filter(function (user) {
6601
+ return _canEmailUser(user, requestingUser);
6377
6602
  });
6378
- // set a bunch of things we do want
6379
- template.extent = "{{organization.defaultExtentBBox}}";
6380
- return template;
6603
+ if (includeSelf) {
6604
+ emailUsers.push(requestingUser);
6605
+ }
6606
+ return emailUsers;
6381
6607
  }
6382
6608
 
6383
6609
  /**
6384
- * Replaces instances of item ids on an item model
6385
- * @param {Object} obj Object graph to traverse
6386
- * @param {string} itemId id to replace with `{{appid}}`
6610
+ * Adds, invites or emails users about joining a group
6611
+ * based on the permissions of the requesting user. The
6612
+ * function returns a hash of results indicating which
6613
+ * operations were attempted and whether they were successful.
6614
+ *
6615
+ * In general, this algorithm will auto-add all the users
6616
+ * that it can, invite the others, and send emails to eligible
6617
+ * invited users (See below for more details)
6618
+ *
6619
+ * Here are a couple caveats to be aware of:
6620
+ * 1) If the requestingUser can auto-add to the group (A.K.A. has
6621
+ * portal:admin:assignToGroups) no email will be sent, period.
6622
+ * 2) Emails can only be sent to members of the same org as the
6623
+ * requesting user if they have been invited (not auto-added)
6624
+ * to the group. If emails must to be sent to invited members
6625
+ * of a second org (e.g a community org), an authenticated user
6626
+ * of the second org must be passed in (see secondaryRO)
6627
+ * 3) If no email is passed in, no email will be sent
6628
+ * 4) If auto-adding fails, the unadded users will be invited
6629
+ *
6630
+ * @param {string} groupId
6631
+ * @param {IUser[]} allUsers
6632
+ * @param {IHubRequestOptions} primaryRO Info and authentication for the requesting user
6633
+ * @param {IEmail} [email] Email to be sent (if qualifying users are passed in)
6634
+ * @param {IHubRequestOptions} [secondaryRO] Info and authentication for emailing members of a secondary organization (typically a community org)
6635
+ *
6636
+ * @returns {IConsolidatedResult} The operations attempted, whether they were successful and any errors
6387
6637
  */
6388
- function replaceItemId(obj, itemId, replacement) {
6389
- if (replacement === void 0) { replacement = "{{appid}}"; }
6390
- var clone = cloneObject$1(obj);
6391
- var re = new RegExp(itemId, "g");
6392
- return deepStringReplace(clone, re, replacement);
6638
+ function addUsersToGroup(groupId, allUsers, primaryRO, email, secondaryRO) {
6639
+ // Extract requesting user
6640
+ var requestingUser = cloneObject$1(getWithDefault$1(primaryRO, "portalSelf.user", {}));
6641
+ requestingUser.cOrgId = getProp(primaryRO, "portalSelf.portalProperties.hub.settings.communityOrg.orgId");
6642
+ // Context for each process segment
6643
+ var context = {
6644
+ groupId: groupId,
6645
+ allUsers: allUsers,
6646
+ primaryRO: primaryRO,
6647
+ email: email,
6648
+ secondaryRO: secondaryRO,
6649
+ requestingUser: requestingUser,
6650
+ usersToAutoAdd: _getAutoAddUsers(allUsers, requestingUser),
6651
+ usersToInvite: _getInviteUsers(allUsers, requestingUser),
6652
+ usersToEmail: _getEmailUsers(allUsers, requestingUser, getProp(email, "copyMe"))
6653
+ };
6654
+ return _processAutoAdd(context)
6655
+ .then(_processInvite)
6656
+ .then(_processPrimaryEmail)
6657
+ .then(_processSecondaryEmail)
6658
+ .then(_consolidateResults);
6393
6659
  }
6394
6660
 
6395
6661
  /**
6396
- * Share an item to a set of groups
6397
- * @param {String} itemId Iten Id to share to the groups
6398
- * @param {Array} groups Array of group id's to which the item will be shared
6399
- * @param {*} requestOptions
6662
+ * Unprotect and Remove an Item
6663
+ * Assumes caller has checked that the curernt user should be able to
6664
+ * unprotect and remove the item. Underlying calls are failsafe
6665
+ * so a failure to unprotect or temove the item will not reject.
6666
+ * @param {IUserItemOptions} userItemOptions id and authentication
6667
+ * @private
6400
6668
  */
6401
- function shareItemToGroups(itemId, groups, requestOptions) {
6402
- return Promise.all(groups.map(function (groupId) {
6403
- var opt = Object.assign({}, { id: itemId, groupId: groupId }, requestOptions);
6404
- return shareItemWithGroup(opt);
6405
- }));
6669
+ function _unprotectAndRemoveItem(userItemOptions) {
6670
+ var failSafeUnprotect = failSafe(unprotectItem, { success: true });
6671
+ var failSafeRemove = failSafe(removeItem, { success: true });
6672
+ return failSafeUnprotect(userItemOptions).then(function () {
6673
+ return failSafeRemove(userItemOptions);
6674
+ });
6406
6675
  }
6407
6676
 
6408
6677
  /**
6409
- * Given a model, determine if it is protected, and unprotect it if it is.
6410
- * Otherwise, just resolve with the same result.
6411
- * @param {Object} model Model Object
6412
- * @param {IRequestOptions} requestOptions
6678
+ * Apply a hash of properties to an array of items.
6679
+ * Extracted to simplify testing.
6680
+ * @param {array} items Array of items to apply the properties to
6681
+ * @param {object} props hash of properties to apply to the item
6413
6682
  */
6414
- function unprotectModel(model, requestOptions) {
6415
- if (model.item.protected) {
6416
- var opts = Object.assign({ id: model.item.id }, requestOptions);
6417
- return unprotectItem(opts);
6418
- }
6419
- else {
6420
- // act as though we did it
6421
- return Promise.resolve({ success: true });
6683
+ function applyPropertiesToItems(items, props) {
6684
+ return items.map(function (item) {
6685
+ if (!item.properties) {
6686
+ item.properties = {};
6687
+ }
6688
+ Object.assign(item.properties, props);
6689
+ return item;
6690
+ });
6691
+ }
6692
+
6693
+ /**
6694
+ * Delete a property from an object using a deep path
6695
+ * MODIFIES PASSED TARGET
6696
+ * @param {Object} target Object from which we want to delete the property
6697
+ * @param {string} path Dotted path to the property we want to delete
6698
+ */
6699
+ function deleteProp(target, lookupStr) {
6700
+ if (typeof target !== "object" || target === null)
6701
+ return;
6702
+ if (typeof lookupStr !== "string")
6703
+ return;
6704
+ var lookupKeys = lookupStr.split(".");
6705
+ for (var i = 0; i < lookupKeys.length - 1; i++) {
6706
+ if (!target.hasOwnProperty(lookupKeys[i]))
6707
+ return;
6708
+ target = target[lookupKeys[i]];
6422
6709
  }
6710
+ delete target[lookupKeys[lookupKeys.length - 1]];
6423
6711
  }
6424
6712
 
6425
6713
  /**
6426
- * Unshare an item from a set of groups
6427
- * @param {String} itemId Item Id to unshare from groups
6428
- * @param {Array} groups Array of group id's from which the item will be unshared
6714
+ * Given a model, return a serialized clone that can be sent to
6715
+ * the items api
6716
+ * @param {Object} model Item model {item:{}, data:{}}
6717
+ */
6718
+ function serializeModel(model) {
6719
+ var serialized = cloneObject$1(model.item);
6720
+ serialized.text = JSON.stringify(model.data);
6721
+ return serialized;
6722
+ }
6723
+
6724
+ /**
6725
+ * Update a model's item, wrapped in a failSafe so this will not blow up if
6726
+ * the user lacks rights somehow. This should be used in places where there is
6727
+ * a high-probability that the current user CAN update the item.
6728
+ * @param {Object} model Model object to be updated
6429
6729
  * @param {IRequestOptions} requestOptions
6430
6730
  */
6431
- function unshareItemFromGroups(itemId, groups, requestOptions) {
6432
- return Promise.all(groups.map(function (groupId) {
6433
- var opt = Object.assign({}, { id: itemId, groupId: groupId }, requestOptions);
6434
- return unshareItemWithGroup(opt);
6435
- }));
6731
+ function failSafeUpdate(model, requestOptions) {
6732
+ var failSafedUpdate = failSafe(updateItem, {
6733
+ id: model.item.id,
6734
+ success: true
6735
+ });
6736
+ var opts = Object.assign({ item: serializeModel(model) }, requestOptions);
6737
+ return failSafedUpdate(opts);
6436
6738
  }
6437
6739
 
6438
6740
  /**
6439
- * Check if a site/page exists with a specific name
6741
+ * Gets the full item/data model for an item
6742
+ * @param {string} id Id of the item to fetch
6743
+ * @param {Object} requestOptions
6440
6744
  */
6441
- function doesItemExistWithTitle(itemTitle, options, authMgr) {
6442
- // if options have multiple properties, put them into one string separated with 'AND'
6443
- var optionsQuery = Object.keys(options)
6444
- .map(function (key) {
6445
- return key + ":\"" + options[key] + "\"";
6446
- })
6447
- .join(" AND ");
6448
- var opts = {
6449
- q: "title:\"" + itemTitle + "\" AND " + optionsQuery,
6450
- authentication: authMgr
6451
- };
6452
- return searchItems(opts)
6453
- .then(function (searchResponse) { return searchResponse.results.length > 0; })
6454
- .catch(function (e) {
6455
- throw Error("Error in doesItemExistWithTitle " + e);
6745
+ function getModel(id, requestOptions) {
6746
+ return Promise.all([
6747
+ getItem(id, requestOptions),
6748
+ getItemData(id, requestOptions)
6749
+ ]).then(function (result) {
6750
+ // shape this into a model
6751
+ return {
6752
+ item: result[0],
6753
+ data: result[1]
6754
+ };
6456
6755
  });
6457
6756
  }
6458
6757
 
6459
6758
  /**
6460
- * Given a title, construct a site/page title that is unique
6461
- * if that title exists, this fn will add a number on the end, and increment until
6462
- * an available title is found
6463
- * @param {string} title site/page title to ensure if unique
6464
- * @param {object} options an object that can be passed in to the q, eg. typekeywords, type
6465
- * @param {object} authMgr auth info tells the function what url to use for the "root" of the API,
6466
- * if missing, it will search against PROD
6467
- * @param {number} step Number to increment. Defaults to 0
6759
+ * To streamline passing of either a model id or the model itself, we use this function
6760
+ * to extract the model or fetch it, and return it. It uses `failSafe` and if the item
6761
+ * is not accessible for whatever reason, will return a model-ish object with `isMissing: true`
6762
+ * It is up to the caller to take approriate action
6763
+ * @param {String} modelType the type of model to extract from the options hash
6764
+ * @param {Object} options Something that extends IRequestOptions
6468
6765
  */
6469
- function getUniqueItemTitle(title, options, authMgr, step) {
6470
- if (step === void 0) { step = 0; }
6471
- var combinedName = title;
6472
- if (step) {
6473
- combinedName = title + " " + step;
6766
+ function getModelFromOptions(modelType, options) {
6767
+ var modelProp = modelType + "Model";
6768
+ var idProp = modelType + "Id";
6769
+ // if the options hash has the model, return it
6770
+ if (options[modelProp]) {
6771
+ return Promise.resolve(options[modelProp]);
6474
6772
  }
6475
- return doesItemExistWithTitle(combinedName, options, authMgr)
6476
- .then(function (result) {
6477
- if (result) {
6478
- step++;
6479
- return getUniqueItemTitle(title, options, authMgr, step);
6773
+ else {
6774
+ if (options[idProp]) {
6775
+ var failSafeModel = failSafe(getModel, {
6776
+ item: { id: options[idProp] },
6777
+ isMissing: true
6778
+ });
6779
+ return failSafeModel(options[idProp], options);
6480
6780
  }
6481
6781
  else {
6482
- return combinedName;
6782
+ throw new Error("getModelFromOptions requires either a ." + modelProp + " or ." + idProp + " property.");
6483
6783
  }
6484
- })
6485
- .catch(function (e) {
6486
- throw Error("Error in getUniqueItemTitle " + e);
6487
- });
6784
+ }
6488
6785
  }
6489
6786
 
6490
- var MAX_NUM = 100;
6491
6787
  /**
6492
- * Fetches all the pages in a search request
6493
- * @param {SearchFunction} searchFunc
6494
- * @param {ISearchOptions} opts
6495
- * @param {number} limit
6496
- * @param {batchSize} number of concurrent requests at a time
6497
- * @returns {Promise<SearchableType[]>}
6788
+ * adlib - v3.0.6 - Thu Dec 17 2020 17:08:08 GMT-0800 (Pacific Standard Time)
6789
+ * Copyright (c) 2017-2020 Dave Bouwman / Esri
6790
+ * Apache-2.0
6791
+ */
6792
+ /* Copyright (c) 2017-2019 Esri Inc.
6793
+ Licensed under the Apache License, Version 2.0 (the "License");
6794
+ you may not use this file except in compliance with the License.
6795
+ You may obtain a copy of the License at
6796
+ http://www.apache.org/licenses/LICENSE-2.0
6797
+ Unless required by applicable law or agreed to in writing, software
6798
+ distributed under the License is distributed on an "AS IS" BASIS,
6799
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6800
+ See the License for the specific language governing permissions and
6801
+ limitations under the License. */
6802
+
6803
+ /**
6804
+ * Return the value of a deep property, using a path.
6498
6805
  */
6499
- function fetchAllPages(searchFunc, opts, limit, batchSize) {
6500
- if (limit === void 0) { limit = -1; }
6501
- var pageSize = opts.num || MAX_NUM;
6502
- var firstStart = opts.start || 1;
6503
- // If a limit is provided, we don't have to use the first request to get the
6504
- // total count before sending things off to batch(). So instead we fake the first
6505
- // response just to set things up.
6506
- var promise = limit === -1
6507
- ? searchFunc(__assign(__assign({}, opts), { num: pageSize, start: firstStart }))
6508
- : Promise.resolve({
6509
- nextStart: firstStart,
6510
- total: limit,
6511
- results: [],
6512
- num: pageSize
6513
- });
6514
- return promise
6515
- .then(function (firstResponse) {
6516
- // no more requests needed, return the first response
6517
- if (firstResponse.nextStart === -1)
6518
- return [firstResponse];
6519
- // generate batch requests for the remaining pages to fetch
6520
- var starts = [];
6521
- for (var i = firstResponse.nextStart; i <= firstResponse.total; i += pageSize) {
6522
- starts.push(i);
6523
- }
6524
- var batchSearchFunc = function (start) {
6525
- return searchFunc(__assign(__assign({}, opts), { start: start, num: pageSize }));
6526
- };
6527
- return batch(starts, batchSearchFunc, batchSize).then(function (responses) { return __spreadArrays([
6528
- firstResponse
6529
- ], responses); });
6530
- })
6531
- .then(function (responses) {
6532
- // merge all the search results into a single array
6533
- var results = responses.reduce(function (acc, response) { return __spreadArrays(acc, response.results); }, []);
6534
- // discard results beyond the limit if applicable
6535
- var clipLimit = limit === -1 ? results.length : limit;
6536
- return results.slice(0, clipLimit);
6537
- });
6806
+ var getWithDefault = function (obj, path, defaultValue) {
6807
+ if ( defaultValue === void 0 ) defaultValue = undefined;
6808
+
6809
+ return path
6810
+ .split('.')
6811
+ .reduce(function (o, p) { return o ? o[p] : defaultValue; }, obj);
6812
+ };
6813
+
6814
+ /* Copyright (c) 2017-2019 Esri Inc.
6815
+ Licensed under the Apache License, Version 2.0 (the "License");
6816
+ you may not use this file except in compliance with the License.
6817
+ You may obtain a copy of the License at
6818
+ http://www.apache.org/licenses/LICENSE-2.0
6819
+ Unless required by applicable law or agreed to in writing, software
6820
+ distributed under the License is distributed on an "AS IS" BASIS,
6821
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6822
+ See the License for the specific language governing permissions and
6823
+ limitations under the License. */
6824
+
6825
+ /**
6826
+ * Simply Map over the props of an object
6827
+ */
6828
+ function mapValues (obj, fn) {
6829
+ var keys = Object.keys(obj);
6830
+ // console.info(`keys: ${keys}`);
6831
+ var newObject = keys.reduce(function(acc, currentKey) {
6832
+ // console.log(` acc: ${JSON.stringify(acc)} curKey: ${currentKey}`);
6833
+ acc[currentKey] = fn(obj[currentKey], currentKey, obj);
6834
+ return acc;
6835
+ }, {});
6836
+ // console.info(` output: ${JSON.stringify(newObject)}`);
6837
+ return newObject;
6538
6838
  }
6539
6839
 
6540
- var STANDARD_LICENSES = [
6541
- {
6542
- type: "CC0-1.0",
6543
- abbr: "CC0",
6544
- name: "Public Domain Dedication",
6545
- url: "http://creativecommons.org/publicdomain/zero/1.0",
6546
- },
6547
- {
6548
- type: "CC-BY-4.0",
6549
- abbr: "CC BY",
6550
- name: "Attribution 4.0 International",
6551
- url: "http://creativecommons.org/licenses/by/4.0",
6552
- },
6553
- {
6554
- type: "CC-BY-3.0",
6555
- abbr: "CC BY 3.0",
6556
- name: "Attribution 3.0 Unported",
6557
- url: "http://creativecommons.org/licenses/by/3.0",
6558
- },
6559
- {
6560
- type: "CC-BY-2.5",
6561
- abbr: "CC BY 2.5",
6562
- name: "Attribution 2.5 Generic",
6563
- url: "http://creativecommons.org/licenses/by/2.5",
6564
- },
6565
- {
6566
- type: "CC-BY-2.0",
6567
- abbr: "CC BY 2.0",
6568
- name: "Attribution 2.0 Generic",
6569
- url: "http://creativecommons.org/licenses/by/2.0",
6570
- },
6571
- {
6572
- type: "CC-BY-1.0",
6573
- abbr: "CC BY 1.0",
6574
- name: "Attribution 1.0 Generic",
6575
- url: "http://creativecommons.org/licenses/by/1.0",
6576
- },
6577
- {
6578
- type: "CC-BY-SA-4.0",
6579
- abbr: "CC BY-SA",
6580
- name: "Attribution-ShareAlike 4.0 International",
6581
- url: "http://creativecommons.org/licenses/by-sa/4.0",
6582
- },
6583
- {
6584
- type: "CC-BY-SA-3.0",
6585
- abbr: "CC BY-SA 3.0",
6586
- name: "Attribution-ShareAlike 3.0 Unported",
6587
- url: "http://creativecommons.org/licenses/by-sa/3.0",
6588
- },
6589
- {
6590
- type: "CC-BY-SA-2.5",
6591
- abbr: "CC BY-SA 2.5",
6592
- name: "Attribution-ShareAlike 2.5 Generic",
6593
- url: "http://creativecommons.org/licenses/by-sa/2.5",
6594
- },
6595
- {
6596
- type: "CC-BY-SA-2.0",
6597
- abbr: "CC BY-SA 2.0",
6598
- name: "Attribution-ShareAlike 2.0 Generic",
6599
- url: "http://creativecommons.org/licenses/by-sa/2.0",
6600
- },
6601
- {
6602
- type: "CC-BY-SA-1.0",
6603
- abbr: "CC BY-SA 1.0",
6604
- name: "Attribution-ShareAlike 1.0 Generic",
6605
- url: "http://creativecommons.org/licenses/by-sa/1.0",
6606
- },
6607
- {
6608
- type: "CC-BY-ND-4.0",
6609
- abbr: "CC BY-ND",
6610
- name: "Attribution-NoDerivatives 4.0 International",
6611
- url: "http://creativecommons.org/licenses/by-nd/4.0",
6612
- },
6613
- {
6614
- type: "CC-BY-ND-3.0",
6615
- abbr: "CC BY-ND 3.0",
6616
- name: "Attribution-NoDerivs 3.0 Unported",
6617
- url: "http://creativecommons.org/licenses/by-nd/3.0",
6618
- },
6619
- {
6620
- type: "CC-BY-ND-2.5",
6621
- abbr: "CC BY-ND 2.5",
6622
- name: "Attribution-NoDerivs 2.5 Generic",
6623
- url: "http://creativecommons.org/licenses/by-nd/2.5",
6624
- },
6625
- {
6626
- type: "CC-BY-ND-2.0",
6627
- abbr: "CC BY-ND 2.0",
6628
- name: "Attribution-NoDerivs 2.0 Generic",
6629
- url: "http://creativecommons.org/licenses/by-nd/2.0",
6630
- },
6631
- {
6632
- type: "CC-BY-ND-1.0",
6633
- abbr: "CC BY-ND 1.0",
6634
- name: "Attribution-NoDerivs 1.0 Generic",
6635
- url: "http://creativecommons.org/licenses/by-nd/1.0",
6636
- },
6637
- {
6638
- type: "CC-BY-NC-4.0",
6639
- abbr: "CC BY-NC",
6640
- name: "Attribution-NonCommercial 4.0 International",
6641
- url: "https://creativecommons.org/licenses/by-nc/4.0",
6642
- },
6643
- {
6644
- type: "CC-BY-NC-3.0",
6645
- abbr: "CC BY-NC 3.0",
6646
- name: "Attribution-NonCommercial 3.0 Unported",
6647
- url: "https://creativecommons.org/licenses/by-nc/3.0",
6648
- },
6649
- {
6650
- type: "CC-BY-NC-2.5",
6651
- abbr: "CC BY-NC 2.5",
6652
- name: "Attribution-NonCommercial 2.5 Generic",
6653
- url: "https://creativecommons.org/licenses/by-nc/2.5",
6654
- },
6655
- {
6656
- type: "CC-BY-NC-2.0",
6657
- abbr: "CC BY-NC 2.0",
6658
- name: "Attribution-NonCommercial 2.0 Generic",
6659
- url: "https://creativecommons.org/licenses/by-nc/2.0",
6660
- },
6661
- {
6662
- type: "CC-BY-NC-1.0",
6663
- abbr: "CC BY-NC 1.0",
6664
- name: "Attribution-NonCommercial 1.0 Generic",
6665
- url: "https://creativecommons.org/licenses/by-nc/1.0",
6666
- },
6667
- {
6668
- type: "CC-BY-NC-SA-4.0",
6669
- abbr: "CC BY-NC-SA",
6670
- name: "Attribution-NonCommercial-ShareAlike 4.0 International",
6671
- url: "https://creativecommons.org/licenses/by-nc-sa/4.0",
6672
- },
6673
- {
6674
- type: "CC-BY-NC-SA-3.0",
6675
- abbr: "CC BY-NC-SA 3.0",
6676
- name: "Attribution-NonCommercial-ShareAlike 3.0 Unported",
6677
- url: "https://creativecommons.org/licenses/by-nc-sa/3.0",
6678
- },
6679
- {
6680
- type: "CC-BY-NC-SA-2.5",
6681
- abbr: "CC BY-NC-SA 2.5",
6682
- name: "Attribution-NonCommercial-ShareAlike 2.5 Generic",
6683
- url: "https://creativecommons.org/licenses/by-nc-sa/2.5",
6684
- },
6685
- {
6686
- type: "CC-BY-NC-SA-2.0",
6687
- abbr: "CC BY-NC-SA 2.0",
6688
- name: "Attribution-NonCommercial-ShareAlike 2.0 Generic",
6689
- url: "https://creativecommons.org/licenses/by-nc-sa/2.0",
6690
- },
6691
- {
6692
- type: "CC-BY-NC-SA-1.0",
6693
- abbr: "CC BY-NC-SA 1.0",
6694
- name: "Attribution-NonCommercial-ShareAlike 1.0 Generic",
6695
- url: "https://creativecommons.org/licenses/by-nc-sa/1.0",
6696
- },
6697
- {
6698
- type: "CC-BY-NC-ND-4.0",
6699
- abbr: "CC BY-NC-ND",
6700
- name: "Attribution-NonCommercial-NoDerivatives 4.0 International",
6701
- url: "https://creativecommons.org/licenses/by-nc-nd/4.0",
6702
- },
6703
- {
6704
- type: "CC-BY-NC-ND-3.0",
6705
- abbr: "CC BY-NC-ND 3.0",
6706
- name: "Attribution-NonCommercial-NoDerivs 3.0 Unported",
6707
- url: "https://creativecommons.org/licenses/by-nc-nd/3.0",
6708
- },
6709
- {
6710
- type: "CC-BY-NC-ND-2.5",
6711
- abbr: "CC BY-NC-ND 2.5",
6712
- name: "Attribution-NonCommercial-NoDerivs 2.5 Generic",
6713
- url: "https://creativecommons.org/licenses/by-nc-nd/2.5",
6714
- },
6715
- {
6716
- type: "CC-BY-NC-ND-2.0",
6717
- abbr: "CC BY-NC-ND 2.0",
6718
- name: "Attribution-NonCommercial-NoDerivs 2.0 Generic",
6719
- url: "https://creativecommons.org/licenses/by-nc-nd/2.0",
6720
- },
6721
- {
6722
- type: "CC-BY-NC-ND-1.0",
6723
- abbr: "CC BY-NC-ND 1.0",
6724
- name: "Attribution-NonCommercial-NoDerivs 1.0 Generic",
6725
- url: "https://creativecommons.org/licenses/by-nc-nd/1.0",
6726
- },
6727
- {
6728
- type: "PDDL-1.0",
6729
- abbr: "PDDL",
6730
- name: "ODC Public Domain Dedication and License",
6731
- url: "http://opendatacommons.org/licenses/pddl/summary",
6732
- },
6733
- {
6734
- type: "ODbL-1.0",
6735
- abbr: "ODbL",
6736
- name: "ODC Open Database License",
6737
- url: "http://opendatacommons.org/licenses/odbl/summary",
6738
- },
6739
- {
6740
- type: "ODC-BY-1.0",
6741
- abbr: "ODC BY",
6742
- name: "ODC Attribution License",
6743
- url: "http://opendatacommons.org/licenses/by/summary",
6744
- },
6840
+ /* Copyright (c) 2017-2019 Esri Inc.
6841
+ Licensed under the Apache License, Version 2.0 (the "License");
6842
+ you may not use this file except in compliance with the License.
6843
+ You may obtain a copy of the License at
6844
+ http://www.apache.org/licenses/LICENSE-2.0
6845
+ Unless required by applicable law or agreed to in writing, software
6846
+ distributed under the License is distributed on an "AS IS" BASIS,
6847
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6848
+ See the License for the specific language governing permissions and
6849
+ limitations under the License. */
6850
+
6851
+ var isDate = function (v) { return v instanceof Date; };
6852
+
6853
+ var isFunction = function (v) { return typeof v === 'function'; };
6854
+
6855
+ var isObject = function (v) { return typeof v === 'object'; };
6856
+
6857
+ var isRegExp = function (v) { return v instanceof RegExp; };
6858
+
6859
+ function deepMapValues(object, callback, propertyPath) {
6860
+ propertyPath = propertyPath || '';
6861
+ if(Array.isArray(object)){
6862
+ return object.map(deepMapValuesIteratee);
6863
+ }
6864
+ else if(object && isObject(object) && !isDate(object) && !isRegExp(object) && !isFunction(object)){
6865
+ return Object.assign({}, object, mapValues(object, deepMapValuesIteratee));
6866
+ }
6867
+ else {
6868
+ var output = callback(object, propertyPath);
6869
+ return output;
6870
+ }
6871
+
6872
+ function deepMapValuesIteratee(value, key){
6873
+ var valuePath = propertyPath ? propertyPath + '.' + key : key;
6874
+ return deepMapValues(value, callback, valuePath);
6875
+ }
6876
+ }
6877
+
6878
+ /* Copyright (c) 2017-2019 Esri Inc.
6879
+ Licensed under the Apache License, Version 2.0 (the "License");
6880
+ you may not use this file except in compliance with the License.
6881
+ You may obtain a copy of the License at
6882
+ http://www.apache.org/licenses/LICENSE-2.0
6883
+ Unless required by applicable law or agreed to in writing, software
6884
+ distributed under the License is distributed on an "AS IS" BASIS,
6885
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6886
+ See the License for the specific language governing permissions and
6887
+ limitations under the License. */
6888
+
6889
+ var isObject$1 = function (v) { return typeof v === 'object'; };
6890
+
6891
+ /**
6892
+ * Trim a tree decorated with `{{delete:NNN}}`
6893
+ */
6894
+ function arborist (object, propertyPath) {
6895
+
6896
+ if(Array.isArray(object)){
6897
+ // filter out any nulls...
6898
+ var arrResults = object.map(iteratee).filter(function (entry) {
6899
+ // need to ensure entry is actually NULL vs just falsey
6900
+ return entry !== null && entry !== undefined;
6901
+ });
6902
+ return pruneArray(arrResults);
6903
+
6904
+ } if(object && isObject$1(object) ) {
6905
+
6906
+ return pruneObject(mapValues(object, iteratee));
6907
+
6908
+ } else {
6909
+
6910
+ return getPropertyValue(object);
6911
+ }
6912
+
6913
+ function iteratee(value, key){
6914
+ return arborist(value);
6915
+ }
6916
+ }
6917
+
6918
+ /**
6919
+ * Prune an array
6920
+ * For all the entries in the array...
6921
+ * if the entry is a naked string and contains `{{delete:NNN}}`
6922
+ * get maximum NNN value
6923
+ * then
6924
+ * if maxN === 0
6925
+ * return an empty array
6926
+ * if maxN > 0
6927
+ * return `{{delete:maxN-1}}`
6928
+ * else
6929
+ * return array
6930
+ */
6931
+ function pruneArray (arrResults) {
6932
+ var res = arrResults;
6933
+ // is any entry a string w/ {{delete}}?
6934
+ var maxLevel = arrResults.reduce(function (maxLevel, e) {
6935
+ if (isString(e) && hasDelete(e)) {
6936
+ var lvl = getLevel(e);
6937
+ if (lvl > maxLevel) {
6938
+ maxLevel = lvl;
6939
+ }
6940
+ }
6941
+ return maxLevel;
6942
+ }, -1);
6943
+
6944
+ if (maxLevel > -1) {
6945
+ if (maxLevel === 0) {
6946
+ res = [];
6947
+ } else {
6948
+ res = "{{delete:" + (maxLevel - 1) + "}}";
6949
+ }
6950
+ }
6951
+
6952
+ return res;
6953
+ }
6954
+
6955
+
6956
+ function pruneObject (objResults) {
6957
+ // console.log(` pruneObject:: working on ${JSON.stringify(objResults)}`);
6958
+ var startVal = {obj: {}, maxLevel: -1 };
6959
+ var res;
6960
+ // cook a new clone object, and track the maxLevel
6961
+ var reduction = Object.keys(objResults).reduce(function (acc, key) {
6962
+ var val = objResults[key];
6963
+ if (isString(val) && hasDelete(val)) {
6964
+ var lvl = getLevel(val);
6965
+ if (lvl > acc.maxLevel) {
6966
+ acc.maxLevel = lvl;
6967
+ }
6968
+ } else {
6969
+ // only add the prop if it's not a `{{delete:NNN}}`
6970
+ acc.obj[key] = val;
6971
+ }
6972
+ return acc;
6973
+ }, startVal);
6974
+ // if -1, we return entire object...
6975
+ // if 0 we just remove the prop...
6976
+ // if 1 we return undefined...
6977
+ // if > 1 we return the deleteVal
6978
+ if (reduction.maxLevel > 0 ) {
6979
+ if (reduction.maxLevel === 1) {
6980
+ res = undefined;
6981
+ } else {
6982
+ res = "{{delete:" + (reduction.maxLevel - 1) + "}}";
6983
+ }
6984
+ } else {
6985
+ res = reduction.obj;
6986
+ }
6987
+
6988
+ // console.log(` returning ${JSON.stringify(res)}`);
6989
+ return res;
6990
+ }
6991
+
6992
+ /**
6993
+ * Get a value for a property, handling the `{{delete:NNN}}` syntax
6994
+ */
6995
+ function getPropertyValue (val){
6996
+ var output = val;
6997
+
6998
+ if (typeof val === 'string') {
6999
+ if (hasDelete(val)) {
7000
+ output = getDeleteValue(val);
7001
+ }
7002
+ }
7003
+ return output;
7004
+ }
7005
+
7006
+ /**
7007
+ * Given a string with `{{delete:NNN}}`
7008
+ * if NNN === 0 return undefined
7009
+ * else return `{{delete:NNN - 1}}`
7010
+ */
7011
+ function getDeleteValue (val) {
7012
+ var output = val;
7013
+ var level = getLevel(val);
7014
+ if (level === 0) {
7015
+ output = undefined;
7016
+ } else {
7017
+ output = "{{delete:" + level + "}}";
7018
+ }
7019
+ return output;
7020
+ }
7021
+
7022
+ /**
7023
+ * Extract the level from a `{{delete:NNN}}`
7024
+ */
7025
+ var getLevel = function (value) { return parseInt(value.replace(/{|}/g, '').split(':')[1]); };
7026
+
7027
+ /**
7028
+ * Simple check if a value has `{{delete` in it
7029
+ */
7030
+ function hasDelete (value) {
7031
+ if (value && typeof value === 'string') {
7032
+ return value.indexOf('{{delete') > -1;
7033
+ } else {
7034
+ return false;
7035
+ }
7036
+ }
7037
+
7038
+ var isString = function (v) { return typeof v === 'string'; };
7039
+
7040
+ /* Copyright (c) 2017-2019 Esri Inc.
7041
+ Licensed under the Apache License, Version 2.0 (the "License");
7042
+ you may not use this file except in compliance with the License.
7043
+ You may obtain a copy of the License at
7044
+ http://www.apache.org/licenses/LICENSE-2.0
7045
+ Unless required by applicable law or agreed to in writing, software
7046
+ distributed under the License is distributed on an "AS IS" BASIS,
7047
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7048
+ See the License for the specific language governing permissions and
7049
+ limitations under the License. */
7050
+
7051
+ /**
7052
+ * Optional Transform
7053
+ * Supports a declarative syntax for optional template properties
7054
+ *
7055
+ * {{some.object.key:optional:2}}
7056
+ *
7057
+ * In this example, if defined, the value of `some.object.key` is used.
7058
+ * If not defined, then the optional transform is utilized
7059
+ * and a post-processing step is executed which will remove two parent levels
7060
+ * from the output structure
7061
+ */
7062
+
7063
+ function optionalTransform(key, value, settings, level) {
7064
+ if ( level === void 0 ) level = 0;
7065
+
7066
+ // console.log(`optional: ${key}, ${value}, ${level}`);
7067
+ var val = value;
7068
+ if (!value) {
7069
+ val = "{{delete:" + level + "}}";
7070
+ }
7071
+ return val;
7072
+ }
7073
+
7074
+ /* Copyright (c) 2017-2019 Esri Inc.
7075
+ Licensed under the Apache License, Version 2.0 (the "License");
7076
+ you may not use this file except in compliance with the License.
7077
+ You may obtain a copy of the License at
7078
+ http://www.apache.org/licenses/LICENSE-2.0
7079
+ Unless required by applicable law or agreed to in writing, software
7080
+ distributed under the License is distributed on an "AS IS" BASIS,
7081
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7082
+ See the License for the specific language governing permissions and
7083
+ limitations under the License. */
7084
+
7085
+ /**
7086
+ * ```js
7087
+ * import { cloneObject } from "./cloneObject";
7088
+ * const original = { foo: "bar" }
7089
+ * const copy = cloneObject(original)
7090
+ * copy.foo // "bar"
7091
+ * copy === original // false
7092
+ * ```
7093
+ * Make a deep clone, including arrays. Does not handle functions!
7094
+ *
7095
+ * Copied from @esri/hub-common to avoid bringing along that package's
7096
+ * dependencies, @esri/hub-common should be made a dependency if more
7097
+ * functions are needed from it in the future
7098
+ */
7099
+ var cloneObject = function (obj) {
7100
+ var clone = {};
7101
+ // first check array
7102
+ if (Array.isArray(obj)) {
7103
+ clone = obj.map(cloneObject);
7104
+ } else if (typeof obj === "object") {
7105
+ for (var i in obj) {
7106
+ if (obj[i] != null && typeof obj[i] === "object") {
7107
+ clone[i] = cloneObject(obj[i]);
7108
+ } else {
7109
+ clone[i] = obj[i];
7110
+ }
7111
+ }
7112
+ } else {
7113
+ clone = obj;
7114
+ }
7115
+ return clone;
7116
+ };
7117
+
7118
+ /* Copyright (c) 2017-2019 Esri Inc.
7119
+ Licensed under the Apache License, Version 2.0 (the "License");
7120
+ you may not use this file except in compliance with the License.
7121
+ You may obtain a copy of the License at
7122
+ http://www.apache.org/licenses/LICENSE-2.0
7123
+ Unless required by applicable law or agreed to in writing, software
7124
+ distributed under the License is distributed on an "AS IS" BASIS,
7125
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7126
+ See the License for the specific language governing permissions and
7127
+ limitations under the License. */
7128
+ var HANDLEBARS = /{{\s*?[\w].*?}}/g;
7129
+
7130
+ var isString$1 = function (v) { return typeof v === 'string'; };
7131
+
7132
+ function _swap(parameter, settings, transforms) {
7133
+ var value;
7134
+ // console.info(`_swap: param: ${parameter}`);
7135
+ // Parameters can optionally call transform functions
7136
+ // e.g. "{{ipsum:translateLatin}}"
7137
+ // so extract {{<parameter>:<transformFunction>:<key||value>}}
7138
+ var transformCheck = parameter.split(':');
7139
+ if (transformCheck.length > 1) {
7140
+ // we have a request to use a transform...
7141
+ var key = transformCheck[0];
7142
+ var fn = transformCheck[1];
7143
+ // we default to using the value...
7144
+ var param;
7145
+ if (transformCheck[2]){
7146
+ param = transformCheck[2];
7147
+ }
7148
+ if(transforms && transforms[fn] && typeof transforms[fn] === 'function') {
7149
+ // get the value from the param
7150
+ value = getWithDefault(settings, key);
7151
+ // transform it...
7152
+ value = transforms[fn](key, value, settings, param);
7153
+ } else {
7154
+ throw new Error(("Attempted to apply non-existant transform " + fn + " on " + key + " with params " + parameter));
7155
+ }
7156
+ } else {
7157
+ // we just get the value
7158
+ value = getWithDefault(settings, parameter);
7159
+ }
7160
+ return value;
7161
+ }
7162
+
7163
+ /**
7164
+ * Does a propertyPath exist on a target
7165
+ */
7166
+ function _propertyPathExists (propertyPath, target) {
7167
+ // remove any transforms
7168
+ var cleanPath = propertyPath.split(':')[0];
7169
+ var value = getWithDefault(target, cleanPath, null);
7170
+ if (value !== null && value !== undefined) {
7171
+ return true;
7172
+ } else {
7173
+ return false;
7174
+ }
7175
+ }
7176
+
7177
+ /**
7178
+ * Is the value considered valid
7179
+ */
7180
+ function _isValue (val) {
7181
+ return val || val === '' || val === 0;
7182
+ }
7183
+
7184
+ // Combine a Template with Settings
7185
+ function adlib (template, settings, transforms) {
7186
+ if ( transforms === void 0 ) transforms = null;
7187
+
7188
+ transforms = cloneObject(transforms) || {};
7189
+ if (transforms.optional) {
7190
+ throw new Error('Please do not pass in an `optional` transform; adlib provides that internally.');
7191
+ } else {
7192
+ transforms.optional = optionalTransform;
7193
+ }
7194
+
7195
+ var res = deepMapValues(template, function(templateValue, templatePath){
7196
+ // Only string templates
7197
+ if (!isString$1(templateValue)) {
7198
+ return templateValue;
7199
+ }
7200
+
7201
+ // When we match "{{layer.fields..}}"
7202
+ var settingsValue;
7203
+
7204
+ var hbsEntries = templateValue.match(HANDLEBARS);
7205
+
7206
+ if (hbsEntries && hbsEntries.length) {
7207
+ // console.log(`Got a ${hbsEntries.length} handlebar entries...`);
7208
+ // iterate over the entries...
7209
+ var values = hbsEntries.map(function (entry) {
7210
+ var isStaticValue = false;
7211
+ // console.info(`Matched ${entry}...`);
7212
+ // strip off the curlies and trim any leading/trailing whitespace...
7213
+ var path = entry.replace(/{|}/g, '').trim();
7214
+ // check for || which indicate a hiearchy
7215
+ if (path.indexOf('||') > -1) {
7216
+ var paths = path.split('||').map(function (path) { return path.trim(); });
7217
+ var numberOfPaths = paths.length;
7218
+ // here we check each option, in order, and return the first with a value in the hash, OR the last
7219
+ path = paths.find(function (pathOption, idx) {
7220
+ // console.info(`Checking to see if ${pathOption} is in settings hash...`);
7221
+ var exists = _propertyPathExists(pathOption, settings);
7222
+ if (!exists) {
7223
+ if ((idx + 1) === numberOfPaths) {
7224
+ // console.info(`Got to last entry, and still did not find anything... assuming ${pathOption} is a static value...`);
7225
+ isStaticValue = true;
7226
+ // check if we can convert this into a number...
7227
+ if (!isNaN(pathOption)) {
7228
+ pathOption = parseInt(pathOption);
7229
+ }
7230
+ return pathOption;
7231
+ } else {
7232
+ return false;
7233
+ }
7234
+ } else {
7235
+ return pathOption;
7236
+ }
7237
+ });
7238
+ }
7239
+ // setup the return value...
7240
+ var result = {
7241
+ key: entry,
7242
+ value: path
7243
+ };
7244
+ // if we have a valid object path, value comes from _swap
7245
+ if (!isStaticValue) {
7246
+ var swap = _swap(path, settings, transforms);
7247
+ result.value = _isValue(swap) ? swap : entry;
7248
+ }
7249
+ // console.info(`Value: ${JSON.stringify(result)}`);
7250
+ return result;
7251
+ });
7252
+
7253
+ values.forEach(function (v) {
7254
+ // console.log(`Comparing ${templateValue} with ${v.key}`)
7255
+ if (templateValue === v.key) {
7256
+ // console.log(`template matches key, returning ${v.value}`);
7257
+ // if the value is a string...
7258
+ if (typeof v.value === 'string') {
7259
+ // and it's numeric-ish
7260
+ if(!isNaN(v.value) && v.value !== '') {
7261
+ // and has a . in it...
7262
+ if (v.value.indexOf('.') > -1) {
7263
+ // parse as a float...
7264
+ v.value = parseFloat(v.value);
7265
+ } else {
7266
+ // parse as an int
7267
+ v.value = parseInt(v.value);
7268
+ }
7269
+ }
7270
+ }
7271
+ settingsValue = v.value;
7272
+ } else {
7273
+ // a little extra regex dance to match the '||' because '|'
7274
+ // is a Very Special Regex Character and we need to super
7275
+ // escape them for the regex to work
7276
+ // console.log(`KEY ${v.key}`);
7277
+ // console.log(`TEMPLATE ${templateValue}`);
7278
+ templateValue = templateValue.replace(v.key, v.value);
7279
+ // console.log(`template did not match key, interpolating value ${v.value} into template to produce ${templateValue}`);
7280
+ }
7281
+ });
7282
+
7283
+ // if we have a value, let's return that...
7284
+ if (_isValue(settingsValue)) {
7285
+ // console.log(`We found a value so we return it ${settingsValue}`);
7286
+ return settingsValue;
7287
+ } else {
7288
+ // console.log(`We did not find a value so we return the template ${templateValue}`);
7289
+ // but if we don't, lets return the template itself
7290
+ return templateValue;
7291
+ }
7292
+ } else {
7293
+ // console.log(`We did not find a hbs match, so we return the template ${templateValue}`);
7294
+ // no match, return the templateValue...
7295
+ return templateValue;
7296
+ }
7297
+ });
7298
+ return arborist(res);
7299
+ }
7300
+
7301
+ /**
7302
+ * Interpolates handlebars-style placeholders on an object graph
7303
+ * @param template
7304
+ * @param settings
7305
+ * @param transforms
7306
+ */
7307
+ function interpolate(template, settings, transforms) {
7308
+ return adlib(template, settings, transforms);
7309
+ }
7310
+
7311
+ /**
7312
+ * Interpolate the item id back into any {{appid}} instances
7313
+ * in the item. Allows for self-referencing in templates
7314
+ * @param {object} model Item Model
7315
+ */
7316
+ function interpolateItemId(model) {
7317
+ var settings = { item: { id: model.item.id }, appid: model.item.id };
7318
+ var transforms = {
7319
+ toISO: function (_, v) {
7320
+ return v;
7321
+ }
7322
+ };
7323
+ return interpolate(model, settings, transforms);
7324
+ }
7325
+
7326
+ var itemPropsNotInTemplates = [
7327
+ "id",
7328
+ "isOrgItem",
7329
+ "proxyFilter",
7330
+ "ownerFolder",
7331
+ "protected",
7332
+ "owner",
7333
+ "created",
7334
+ "modified",
7335
+ "guid",
7336
+ "name",
7337
+ "access",
7338
+ "size",
7339
+ "listed",
7340
+ "numComments",
7341
+ "numRatings",
7342
+ "avgRating",
7343
+ "numViews",
7344
+ "scoreCompleteness",
7345
+ "groupDesignations",
7346
+ "listed",
7347
+ "screenshots",
7348
+ "banner",
7349
+ "appCategories",
7350
+ "industries",
7351
+ "languages",
7352
+ "largeThumbnail"
6745
7353
  ];
6746
7354
  /**
6747
- * generates the structured license of an item based on its
6748
- * configured "licenseInfo"
6749
- * @param rawLicense an item's raw licenseInfo string
6750
- * @returns {IStructuredLicense}
7355
+ * Given an item, remove a standard set of properties not needed in a template
7356
+ * TODO: This should land in a templating helper lib in hub.js
7357
+ * @param {Object} item Item to be normalized
6751
7358
  */
6752
- function getStructuredLicense(rawLicense) {
6753
- var structuredLicense;
6754
- rawLicense = rawLicense || "";
6755
- // (1) start by assuming it's either a custom license, or, if there's no
6756
- // raw license, then there's no license at all
6757
- structuredLicense = {
6758
- type: rawLicense ? "custom" : "none",
6759
- text: rawLicense,
6760
- };
6761
- // (2) Check for standard licenses: If the name, abbr, or url of any standard
6762
- // license is in the raw license text, we assume that is the license.
6763
- var hasStandardLicense = false;
6764
- var matchingStandardLicenses = STANDARD_LICENSES.filter(function (standardLicense) {
6765
- return licenseTextContainsStandardLicenseAttributes(rawLicense, standardLicense);
7359
+ function normalizeSolutionTemplateItem(item) {
7360
+ var template = cloneObject$1(item);
7361
+ itemPropsNotInTemplates.forEach(function (prop) {
7362
+ delete template[prop];
6766
7363
  });
6767
- if (matchingStandardLicenses.length) {
6768
- hasStandardLicense = true;
6769
- structuredLicense = matchingStandardLicenses.pop();
7364
+ // set a bunch of things we do want
7365
+ template.extent = "{{organization.defaultExtentBBox}}";
7366
+ return template;
7367
+ }
7368
+
7369
+ /**
7370
+ * Replaces instances of item ids on an item model
7371
+ * @param {Object} obj Object graph to traverse
7372
+ * @param {string} itemId id to replace with `{{appid}}`
7373
+ */
7374
+ function replaceItemId(obj, itemId, replacement) {
7375
+ if (replacement === void 0) { replacement = "{{appid}}"; }
7376
+ var clone = cloneObject$1(obj);
7377
+ var re = new RegExp(itemId, "g");
7378
+ return deepStringReplace(clone, re, replacement);
7379
+ }
7380
+
7381
+ /**
7382
+ * Share an item to a set of groups
7383
+ * @param {String} itemId Iten Id to share to the groups
7384
+ * @param {Array} groups Array of group id's to which the item will be shared
7385
+ * @param {*} requestOptions
7386
+ */
7387
+ function shareItemToGroups(itemId, groups, requestOptions) {
7388
+ return Promise.all(groups.map(function (groupId) {
7389
+ var opt = Object.assign({}, { id: itemId, groupId: groupId }, requestOptions);
7390
+ return shareItemWithGroup(opt);
7391
+ }));
7392
+ }
7393
+
7394
+ /**
7395
+ * Given a model, determine if it is protected, and unprotect it if it is.
7396
+ * Otherwise, just resolve with the same result.
7397
+ * @param {Object} model Model Object
7398
+ * @param {IRequestOptions} requestOptions
7399
+ */
7400
+ function unprotectModel(model, requestOptions) {
7401
+ if (model.item.protected) {
7402
+ var opts = Object.assign({ id: model.item.id }, requestOptions);
7403
+ return unprotectItem(opts);
6770
7404
  }
6771
- // (3) if not a standard license, we check if the raw license is a url or link
6772
- if (!hasStandardLicense) {
6773
- var url = void 0;
6774
- // a. check if the the raw license is simply a url
6775
- if (isParseableAsURL(rawLicense)) {
6776
- url = rawLicense;
6777
- }
6778
- // b. check if the raw license is simply a link (i.e. an anchor tag with an href)
6779
- else if (isSingleAnchorWithHrefAttribute(rawLicense)) {
6780
- var hrefRegex = new RegExp(/href\s?=\s?["'](.*?)["']/);
6781
- var match = rawLicense.match(hrefRegex);
6782
- var href = match[1];
6783
- url = href;
6784
- }
6785
- if (url) {
6786
- structuredLicense.url = url;
6787
- structuredLicense.text = "";
6788
- }
7405
+ else {
7406
+ // act as though we did it
7407
+ return Promise.resolve({ success: true });
6789
7408
  }
6790
- if (!structuredLicense.text)
6791
- delete structuredLicense.text;
6792
- return structuredLicense;
6793
7409
  }
7410
+
6794
7411
  /**
6795
- * helper function to determine if a raw license is one of the standard licenses.
6796
- * We say it is if the raw license includes the name, url or abbreviation of the
6797
- * standard license
6798
- * @param rawLicense an item's raw licenseInfo string
6799
- * @param standardLicense one of the standard licenses
6800
- * @returns {boolean}
7412
+ * Unshare an item from a set of groups
7413
+ * @param {String} itemId Item Id to unshare from groups
7414
+ * @param {Array} groups Array of group id's from which the item will be unshared
7415
+ * @param {IRequestOptions} requestOptions
6801
7416
  */
6802
- function licenseTextContainsStandardLicenseAttributes(rawLicense, standardLicense) {
6803
- rawLicense = rawLicense.toLowerCase();
6804
- return (rawLicense.includes(standardLicense.name.toLowerCase()) ||
6805
- rawLicense.includes(standardLicense.url.toLowerCase()) ||
6806
- rawLicense.includes(standardLicense.abbr.toLowerCase()));
7417
+ function unshareItemFromGroups(itemId, groups, requestOptions) {
7418
+ return Promise.all(groups.map(function (groupId) {
7419
+ var opt = Object.assign({}, { id: itemId, groupId: groupId }, requestOptions);
7420
+ return unshareItemWithGroup(opt);
7421
+ }));
6807
7422
  }
7423
+
6808
7424
  /**
6809
- * helper function to determine if an input string can be parsed
6810
- * as a URL with a protocol
6811
- * @param value string to check
6812
- * @returns {boolean}
7425
+ * Check if a site/page exists with a specific name
6813
7426
  */
6814
- function isParseableAsURL(value) {
6815
- try {
6816
- var url = new URL(value);
6817
- return !!url.protocol;
6818
- }
6819
- catch (err) {
6820
- // just return fals if the URL couldn't be parsed
6821
- return false;
7427
+ function doesItemExistWithTitle(itemTitle, options, authMgr) {
7428
+ // if options have multiple properties, put them into one string separated with 'AND'
7429
+ var optionsQuery = Object.keys(options)
7430
+ .map(function (key) {
7431
+ return key + ":\"" + options[key] + "\"";
7432
+ })
7433
+ .join(" AND ");
7434
+ var opts = {
7435
+ q: "title:\"" + itemTitle + "\" AND " + optionsQuery,
7436
+ authentication: authMgr
7437
+ };
7438
+ return searchItems(opts)
7439
+ .then(function (searchResponse) { return searchResponse.results.length > 0; })
7440
+ .catch(function (e) {
7441
+ throw Error("Error in doesItemExistWithTitle " + e);
7442
+ });
7443
+ }
7444
+
7445
+ /**
7446
+ * Given a title, construct a site/page title that is unique
7447
+ * if that title exists, this fn will add a number on the end, and increment until
7448
+ * an available title is found
7449
+ * @param {string} title site/page title to ensure if unique
7450
+ * @param {object} options an object that can be passed in to the q, eg. typekeywords, type
7451
+ * @param {object} authMgr auth info tells the function what url to use for the "root" of the API,
7452
+ * if missing, it will search against PROD
7453
+ * @param {number} step Number to increment. Defaults to 0
7454
+ */
7455
+ function getUniqueItemTitle(title, options, authMgr, step) {
7456
+ if (step === void 0) { step = 0; }
7457
+ var combinedName = title;
7458
+ if (step) {
7459
+ combinedName = title + " " + step;
6822
7460
  }
7461
+ return doesItemExistWithTitle(combinedName, options, authMgr)
7462
+ .then(function (result) {
7463
+ if (result) {
7464
+ step++;
7465
+ return getUniqueItemTitle(title, options, authMgr, step);
7466
+ }
7467
+ else {
7468
+ return combinedName;
7469
+ }
7470
+ })
7471
+ .catch(function (e) {
7472
+ throw Error("Error in getUniqueItemTitle " + e);
7473
+ });
6823
7474
  }
7475
+
7476
+ var MAX_NUM = 100;
6824
7477
  /**
6825
- * helper function to determine if the raw license is simply a link, i.e. a single
6826
- * anchor tag with an href attribute: <a href="https://google.com">Click</a> or <a href="https://google.com" />
6827
- * @param rawLicense an item's raw licenseInfo string
6828
- * @returns {boolean}
7478
+ * Fetches all the pages in a search request
7479
+ * @param {SearchFunction} searchFunc
7480
+ * @param {ISearchOptions} opts
7481
+ * @param {number} limit
7482
+ * @param {batchSize} number of concurrent requests at a time
7483
+ * @returns {Promise<SearchableType[]>}
6829
7484
  */
6830
- function isSingleAnchorWithHrefAttribute(rawLicense) {
6831
- var isSingleAnchorTagRegex = new RegExp(/^<a[\s]+(href\s?=\s?["'].*?["'])+([^>]?)>((?:.(?!\<\/a\>))*.)?<\/a>$|^<a[\s]+(href\s?=\s?["'].*?["'])+([^>]?)\/>/);
6832
- return isSingleAnchorTagRegex.test(rawLicense);
7485
+ function fetchAllPages(searchFunc, opts, limit, batchSize) {
7486
+ if (limit === void 0) { limit = -1; }
7487
+ var pageSize = opts.num || MAX_NUM;
7488
+ var firstStart = opts.start || 1;
7489
+ // If a limit is provided, we don't have to use the first request to get the
7490
+ // total count before sending things off to batch(). So instead we fake the first
7491
+ // response just to set things up.
7492
+ var promise = limit === -1
7493
+ ? searchFunc(__assign(__assign({}, opts), { num: pageSize, start: firstStart }))
7494
+ : Promise.resolve({
7495
+ nextStart: firstStart,
7496
+ total: limit,
7497
+ results: [],
7498
+ num: pageSize
7499
+ });
7500
+ return promise
7501
+ .then(function (firstResponse) {
7502
+ // no more requests needed, return the first response
7503
+ if (firstResponse.nextStart === -1)
7504
+ return [firstResponse];
7505
+ // generate batch requests for the remaining pages to fetch
7506
+ var starts = [];
7507
+ for (var i = firstResponse.nextStart; i <= firstResponse.total; i += pageSize) {
7508
+ starts.push(i);
7509
+ }
7510
+ var batchSearchFunc = function (start) {
7511
+ return searchFunc(__assign(__assign({}, opts), { start: start, num: pageSize }));
7512
+ };
7513
+ return batch(starts, batchSearchFunc, batchSize).then(function (responses) { return __spreadArrays([
7514
+ firstResponse
7515
+ ], responses); });
7516
+ })
7517
+ .then(function (responses) {
7518
+ // merge all the search results into a single array
7519
+ var results = responses.reduce(function (acc, response) { return __spreadArrays(acc, response.results); }, []);
7520
+ // discard results beyond the limit if applicable
7521
+ var clipLimit = limit === -1 ? results.length : limit;
7522
+ return results.slice(0, clipLimit);
7523
+ });
6833
7524
  }
6834
7525
 
6835
7526
  /**
@@ -7388,7 +8079,7 @@
7388
8079
  if (hubRequestOptions.isPortal) {
7389
8080
  throw new Error("isValidDomain is not available in ArcGIS Enterprise.");
7390
8081
  }
7391
- var url = hubRequestOptions.hubApiUrl + "/api/v3/domains/validate?hostname=" + hostname;
8082
+ var url = _getDomainServiceUrl(hubRequestOptions.hubApiUrl) + "/validate?hostname=" + hostname;
7392
8083
  var headers = _getAuthHeader(hubRequestOptions);
7393
8084
  return fetch(url, { method: "GET", headers: headers, mode: "cors" })
7394
8085
  .then(function (response) {
@@ -7482,7 +8173,7 @@
7482
8173
  prms = getUniqueDomainNamePortal(subdomain, hubRequestOptions);
7483
8174
  }
7484
8175
  else {
7485
- var baseDomain = hubRequestOptions.portalSelf.urlKey + "." + stripProtocol(hubRequestOptions.hubApiUrl);
8176
+ var baseDomain = hubRequestOptions.portalSelf.urlKey + "." + stripProtocol(getHubApiUrl(hubRequestOptions));
7486
8177
  prms = getUniqueDomainName(subdomain, baseDomain, hubRequestOptions);
7487
8178
  }
7488
8179
  return prms.then(function (uniqueDomain) {
@@ -7822,7 +8513,9 @@
7822
8513
  */
7823
8514
  function hubApiRequest(route, requestOptions) {
7824
8515
  // merge in default request options
7825
- var options = __assign({ hubApiUrl: "https://opendata.arcgis.com/api/v3/", httpMethod: "GET" }, requestOptions);
8516
+ var options = __assign({
8517
+ // why do we default to GET w/ our API?
8518
+ httpMethod: "GET" }, requestOptions);
7826
8519
  // use fetch override if any
7827
8520
  var _fetch = options.fetch || fetch;
7828
8521
  // merge in default headers
@@ -7840,14 +8533,14 @@
7840
8533
  }
7841
8534
  // build Hub API URL
7842
8535
  var url = buildUrl({
7843
- host: options.hubApiUrl,
8536
+ host: getHubApiUrl(options),
7844
8537
  path: ("/api/v3/" + route).replace(/\/\//g, "/"),
7845
- query: query
8538
+ query: query,
7846
8539
  });
7847
8540
  return _fetch(url, {
7848
8541
  method: options.httpMethod,
7849
8542
  headers: headers,
7850
- body: body
8543
+ body: body,
7851
8544
  }).then(function (resp) {
7852
8545
  if (resp.ok) {
7853
8546
  return resp.json();
@@ -8123,10 +8816,12 @@
8123
8816
  exports.Logger = Logger;
8124
8817
  exports.OperationError = OperationError;
8125
8818
  exports.OperationStack = OperationStack;
8819
+ exports.PORTAL_EXPORT_TYPES = PORTAL_EXPORT_TYPES;
8126
8820
  exports.REQUIRED_PRIVS = REQUIRED_PRIVS;
8127
8821
  exports.RemoteServerError = RemoteServerError;
8128
8822
  exports.SITE_SCHEMA_VERSION = SITE_SCHEMA_VERSION;
8129
8823
  exports.STANDARD_LICENSES = STANDARD_LICENSES;
8824
+ exports.WGS84_WKID = WGS84_WKID;
8130
8825
  exports._addTokenToResourceUrl = _addTokenToResourceUrl;
8131
8826
  exports._canEmailUser = _canEmailUser;
8132
8827
  exports._checkStatusAndParseJson = _checkStatusAndParseJson;
@@ -8163,9 +8858,12 @@
8163
8858
  exports.addUsersToGroup = addUsersToGroup;
8164
8859
  exports.applyPropertiesToItems = applyPropertiesToItems;
8165
8860
  exports.arrayToObject = arrayToObject;
8861
+ exports.atob = abab.atob;
8166
8862
  exports.autoAddUsers = autoAddUsers;
8167
8863
  exports.batch = batch;
8864
+ exports.btoa = abab.btoa;
8168
8865
  exports.buildDraft = buildDraft;
8866
+ exports.buildExistingExportsPortalQuery = buildExistingExportsPortalQuery;
8169
8867
  exports.buildUrl = buildUrl;
8170
8868
  exports.camelize = camelize;
8171
8869
  exports.canEditEvent = canEditEvent;
@@ -8183,6 +8881,8 @@
8183
8881
  exports.createExtent = createExtent;
8184
8882
  exports.createId = createId;
8185
8883
  exports.createOperationPipeline = createOperationPipeline;
8884
+ exports.datasetToContent = datasetToContent;
8885
+ exports.datasetToItem = datasetToItem;
8186
8886
  exports.deepSet = deepSet;
8187
8887
  exports.deepStringReplace = deepStringReplace;
8188
8888
  exports.deleteProp = deleteProp;
@@ -8205,12 +8905,16 @@
8205
8905
  exports.fetchSite = fetchSite;
8206
8906
  exports.filterBy = filterBy;
8207
8907
  exports.findBy = findBy;
8908
+ exports.flattenArray = flattenArray;
8208
8909
  exports.generateRandomString = generateRandomString;
8209
8910
  exports.getCategory = getCategory;
8210
8911
  exports.getCollection = getCollection;
8211
8912
  exports.getContentIdentifier = getContentIdentifier;
8212
8913
  exports.getCulture = getCulture;
8213
8914
  exports.getDomainsForSite = getDomainsForSite;
8915
+ exports.getExportItemTypeKeyword = getExportItemTypeKeyword;
8916
+ exports.getExportLayerTypeKeyword = getExportLayerTypeKeyword;
8917
+ exports.getFamily = getFamily;
8214
8918
  exports.getGeographicOrgExtent = getGeographicOrgExtent;
8215
8919
  exports.getHubApiUrl = getHubApiUrl;
8216
8920
  exports.getHubApiUrlFromPortal = getHubApiUrlFromPortal;
@@ -8222,6 +8926,7 @@
8222
8926
  exports.getItemDataUrl = getItemDataUrl;
8223
8927
  exports.getItemHomeUrl = getItemHomeUrl;
8224
8928
  exports.getItemHubId = getItemHubId;
8929
+ exports.getItemHubType = getItemHubType;
8225
8930
  exports.getItemLayerId = getItemLayerId;
8226
8931
  exports.getItemThumbnailUrl = getItemThumbnailUrl;
8227
8932
  exports.getLayerIdFromUrl = getLayerIdFromUrl;
@@ -8234,6 +8939,7 @@
8234
8939
  exports.getProps = getProps;
8235
8940
  exports.getServiceTypeFromUrl = getServiceTypeFromUrl;
8236
8941
  exports.getSiteById = getSiteById;
8942
+ exports.getSpatialRefTypeKeyword = getSpatialRefTypeKeyword;
8237
8943
  exports.getStructuredLicense = getStructuredLicense;
8238
8944
  exports.getSubscriptionType = getSubscriptionType;
8239
8945
  exports.getTypeCategories = getTypeCategories;
@@ -8262,6 +8968,7 @@
8262
8968
  exports.isValidDomain = isValidDomain;
8263
8969
  exports.isValidExtent = isValidExtent;
8264
8970
  exports.itemPropsNotInTemplates = itemPropsNotInTemplates;
8971
+ exports.itemToContent = itemToContent;
8265
8972
  exports.last = last;
8266
8973
  exports.lookupDomain = lookupDomain;
8267
8974
  exports.mapBy = mapBy;
@@ -8273,6 +8980,7 @@
8273
8980
  exports.objectToArray = objectToArray;
8274
8981
  exports.objectToJsonBlob = objectToJsonBlob;
8275
8982
  exports.parseDatasetId = parseDatasetId;
8983
+ exports.parseItemCategories = parseItemCategories;
8276
8984
  exports.processRevertableTasks = processRevertableTasks;
8277
8985
  exports.propifyString = propifyString;
8278
8986
  exports.removeContextFromSlug = removeContextFromSlug;
@@ -8281,6 +8989,7 @@
8281
8989
  exports.replaceItemId = replaceItemId;
8282
8990
  exports.runRevertableTask = runRevertableTask;
8283
8991
  exports.serializeModel = serializeModel;
8992
+ exports.serializeSpatialReference = serializeSpatialReference;
8284
8993
  exports.setProp = setProp;
8285
8994
  exports.shareItemToGroups = shareItemToGroups;
8286
8995
  exports.slugify = slugify;