@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.
- package/dist/es2017/api.js +5 -0
- package/dist/es2017/api.js.map +1 -1
- package/dist/es2017/content.js +341 -2
- package/dist/es2017/content.js.map +1 -1
- package/dist/es2017/downloads/build-existing-exports-portal-query.js +187 -0
- package/dist/es2017/downloads/build-existing-exports-portal-query.js.map +1 -0
- package/dist/es2017/downloads/index.js +2 -0
- package/dist/es2017/downloads/index.js.map +1 -0
- package/dist/es2017/index.js +2 -0
- package/dist/es2017/index.js.map +1 -1
- package/dist/es2017/request.js +8 -5
- package/dist/es2017/request.js.map +1 -1
- package/dist/es2017/sites/domains/_get-domain-service-url.js.map +1 -1
- package/dist/es2017/sites/domains/ensure-unique-domain-name.js +2 -1
- package/dist/es2017/sites/domains/ensure-unique-domain-name.js.map +1 -1
- package/dist/es2017/sites/domains/is-valid-domain.js +2 -1
- package/dist/es2017/sites/domains/is-valid-domain.js.map +1 -1
- package/dist/es2017/util.js +8 -0
- package/dist/es2017/util.js.map +1 -1
- package/dist/esm/api.js +5 -0
- package/dist/esm/api.js.map +1 -1
- package/dist/esm/content.js +342 -2
- package/dist/esm/content.js.map +1 -1
- package/dist/esm/downloads/build-existing-exports-portal-query.js +187 -0
- package/dist/esm/downloads/build-existing-exports-portal-query.js.map +1 -0
- package/dist/esm/downloads/index.js +2 -0
- package/dist/esm/downloads/index.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/request.js +7 -4
- package/dist/esm/request.js.map +1 -1
- package/dist/esm/sites/domains/_get-domain-service-url.js.map +1 -1
- package/dist/esm/sites/domains/ensure-unique-domain-name.js +2 -1
- package/dist/esm/sites/domains/ensure-unique-domain-name.js.map +1 -1
- package/dist/esm/sites/domains/is-valid-domain.js +2 -1
- package/dist/esm/sites/domains/is-valid-domain.js.map +1 -1
- package/dist/esm/util.js +8 -0
- package/dist/esm/util.js.map +1 -1
- package/dist/node/api.js +5 -0
- package/dist/node/api.js.map +1 -1
- package/dist/node/content.js +346 -1
- package/dist/node/content.js.map +1 -1
- package/dist/node/downloads/build-existing-exports-portal-query.js +195 -0
- package/dist/node/downloads/build-existing-exports-portal-query.js.map +1 -0
- package/dist/node/downloads/index.js +5 -0
- package/dist/node/downloads/index.js.map +1 -0
- package/dist/node/index.js +4 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/request.js +8 -5
- package/dist/node/request.js.map +1 -1
- package/dist/node/sites/domains/_get-domain-service-url.js.map +1 -1
- package/dist/node/sites/domains/ensure-unique-domain-name.js +2 -1
- package/dist/node/sites/domains/ensure-unique-domain-name.js.map +1 -1
- package/dist/node/sites/domains/is-valid-domain.js +2 -1
- package/dist/node/sites/domains/is-valid-domain.js.map +1 -1
- package/dist/node/util.js +10 -1
- package/dist/node/util.js.map +1 -1
- package/dist/types/content.d.ts +61 -0
- package/dist/types/downloads/build-existing-exports-portal-query.d.ts +86 -0
- package/dist/types/downloads/index.d.ts +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/sites/domains/_get-domain-service-url.d.ts +1 -1
- package/dist/types/types.d.ts +19 -7
- package/dist/types/util.d.ts +6 -0
- package/dist/umd/common.umd.js +2394 -1685
- package/dist/umd/common.umd.js.map +1 -1
- package/dist/umd/common.umd.min.js +1 -1
- package/dist/umd/common.umd.min.js.map +1 -1
- package/package.json +5 -3
package/dist/umd/common.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* @preserve
|
|
2
|
-
* @esri/hub-common - v8.
|
|
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.
|
|
2530
|
-
return /\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.
|
|
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
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
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
|
-
*
|
|
4973
|
-
*
|
|
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
|
|
4984
|
-
|
|
4985
|
-
return categories[category.toLowerCase()];
|
|
4978
|
+
function extentToBBox(envelope) {
|
|
4979
|
+
return [[envelope.xmin, envelope.ymin], [envelope.xmax, envelope.ymax]];
|
|
4986
4980
|
}
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
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
|
-
|
|
5021
|
-
}
|
|
4989
|
+
};
|
|
5022
4990
|
/**
|
|
5023
|
-
*
|
|
5024
|
-
*
|
|
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
|
|
5034
|
-
|
|
5035
|
-
var
|
|
5036
|
-
var
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
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
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
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
|
-
*
|
|
5076
|
-
* @param {
|
|
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
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
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
|
-
*
|
|
5108
|
-
* @param
|
|
5109
|
-
* @
|
|
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
|
-
*
|
|
5348
|
-
*
|
|
5349
|
-
*
|
|
5350
|
-
*
|
|
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
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
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
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
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
|
-
|
|
5320
|
+
if (!structuredLicense.text)
|
|
5321
|
+
delete structuredLicense.text;
|
|
5322
|
+
return structuredLicense;
|
|
5461
5323
|
}
|
|
5462
|
-
|
|
5463
5324
|
/**
|
|
5464
|
-
*
|
|
5465
|
-
*
|
|
5466
|
-
*
|
|
5467
|
-
*
|
|
5468
|
-
*
|
|
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
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
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
|
-
*
|
|
5494
|
-
*
|
|
5495
|
-
* @
|
|
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
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
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
|
-
*
|
|
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
|
|
5518
|
-
|
|
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
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
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
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
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
|
-
*
|
|
5582
|
-
*
|
|
5583
|
-
*
|
|
5584
|
-
*
|
|
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
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
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
|
-
*
|
|
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
|
|
5601
|
-
|
|
5602
|
-
return
|
|
5414
|
+
function getTypes(category) {
|
|
5415
|
+
if (category === void 0) { category = ""; }
|
|
5416
|
+
return categories[category.toLowerCase()];
|
|
5603
5417
|
}
|
|
5604
|
-
|
|
5605
5418
|
/**
|
|
5606
|
-
*
|
|
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
|
|
5612
|
-
if (
|
|
5613
|
-
var
|
|
5614
|
-
var
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
5625
|
-
*
|
|
5626
|
-
*
|
|
5627
|
-
*
|
|
5628
|
-
*
|
|
5629
|
-
*
|
|
5630
|
-
*
|
|
5631
|
-
*
|
|
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
|
|
5684
|
-
|
|
5685
|
-
var
|
|
5686
|
-
|
|
5687
|
-
|
|
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
|
-
*
|
|
5693
|
-
*
|
|
5694
|
-
*
|
|
5695
|
-
*
|
|
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
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
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
|
-
*
|
|
5729
|
-
*
|
|
5730
|
-
* @
|
|
5506
|
+
* Case-insensitive check if the type is "Feature Service"
|
|
5507
|
+
* @param {string} type - item's type
|
|
5508
|
+
* @returns {boolean}
|
|
5731
5509
|
*/
|
|
5732
|
-
function
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
return serialized;
|
|
5736
|
-
}
|
|
5737
|
-
|
|
5510
|
+
var isFeatureService = function (type) {
|
|
5511
|
+
return type && type.toLowerCase() === "feature service";
|
|
5512
|
+
};
|
|
5738
5513
|
/**
|
|
5739
|
-
*
|
|
5740
|
-
*
|
|
5741
|
-
*
|
|
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
|
|
5746
|
-
var
|
|
5747
|
-
|
|
5748
|
-
|
|
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
|
-
*
|
|
5756
|
-
* @param {
|
|
5757
|
-
* @
|
|
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
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
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
|
-
*
|
|
5774
|
-
*
|
|
5775
|
-
*
|
|
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
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
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
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
5824
|
-
|
|
5825
|
-
.reduce(function (o, p) { return o ? o[p] : defaultValue; }, obj);
|
|
5826
|
-
};
|
|
6075
|
+
const keystr$1 =
|
|
6076
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
5827
6077
|
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
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
|
-
*
|
|
6087
|
+
* btoa() as defined by the HTML and Infra specs, which mostly just references
|
|
6088
|
+
* RFC 4648.
|
|
5841
6089
|
*/
|
|
5842
|
-
function
|
|
5843
|
-
|
|
5844
|
-
//
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
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
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
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
|
-
|
|
6132
|
+
function btoaLookup(index) {
|
|
6133
|
+
if (index >= 0 && index < 64) {
|
|
6134
|
+
return keystr[index];
|
|
6135
|
+
}
|
|
5866
6136
|
|
|
5867
|
-
|
|
6137
|
+
// Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
|
|
6138
|
+
return undefined;
|
|
6139
|
+
}
|
|
5868
6140
|
|
|
5869
|
-
var
|
|
6141
|
+
var btoa_1 = btoa;
|
|
5870
6142
|
|
|
5871
|
-
var
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
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
|
-
*
|
|
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
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
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
|
-
*
|
|
5934
|
-
*
|
|
5935
|
-
*
|
|
5936
|
-
*
|
|
5937
|
-
*
|
|
5938
|
-
*
|
|
5939
|
-
*
|
|
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
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
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
|
-
|
|
5956
|
-
|
|
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
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
var
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
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
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
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
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
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
|
-
*
|
|
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
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
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
|
-
*
|
|
6022
|
-
*
|
|
6023
|
-
*
|
|
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
|
|
6026
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
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
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
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
|
-
*
|
|
6067
|
-
* Supports a declarative syntax for optional template properties
|
|
6377
|
+
* @private
|
|
6068
6378
|
*
|
|
6069
|
-
*
|
|
6379
|
+
* Coerce autoAdd response into a more similar interface as
|
|
6380
|
+
* the other rest calls.
|
|
6070
6381
|
*
|
|
6071
|
-
*
|
|
6072
|
-
*
|
|
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
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
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
|
-
|
|
6414
|
+
/**
|
|
6415
|
+
* @private
|
|
6416
|
+
*/
|
|
6417
|
+
function _isOrgAdmin(user) {
|
|
6418
|
+
return user.role === "org_admin" && !user.roleId;
|
|
6419
|
+
}
|
|
6145
6420
|
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
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
|
-
*
|
|
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
|
|
6195
|
-
|
|
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
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
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
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
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
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
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
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
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
|
-
*
|
|
6317
|
-
*
|
|
6318
|
-
*
|
|
6319
|
-
*
|
|
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
|
|
6322
|
-
|
|
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
|
-
*
|
|
6327
|
-
*
|
|
6328
|
-
*
|
|
6582
|
+
* @private
|
|
6583
|
+
*
|
|
6584
|
+
* A user will be invited if they cannot be auto-added
|
|
6329
6585
|
*/
|
|
6330
|
-
function
|
|
6331
|
-
var
|
|
6332
|
-
|
|
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
|
-
*
|
|
6370
|
-
*
|
|
6371
|
-
*
|
|
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
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
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
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6603
|
+
if (includeSelf) {
|
|
6604
|
+
emailUsers.push(requestingUser);
|
|
6605
|
+
}
|
|
6606
|
+
return emailUsers;
|
|
6381
6607
|
}
|
|
6382
6608
|
|
|
6383
6609
|
/**
|
|
6384
|
-
*
|
|
6385
|
-
*
|
|
6386
|
-
*
|
|
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
|
|
6389
|
-
|
|
6390
|
-
var
|
|
6391
|
-
|
|
6392
|
-
|
|
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
|
-
*
|
|
6397
|
-
*
|
|
6398
|
-
*
|
|
6399
|
-
*
|
|
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
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
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
|
-
*
|
|
6410
|
-
*
|
|
6411
|
-
* @param {
|
|
6412
|
-
* @param {
|
|
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
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
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
|
-
*
|
|
6427
|
-
*
|
|
6428
|
-
* @param {
|
|
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
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
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
|
-
*
|
|
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
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
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
|
-
*
|
|
6461
|
-
*
|
|
6462
|
-
*
|
|
6463
|
-
*
|
|
6464
|
-
* @param {
|
|
6465
|
-
* @param {
|
|
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
|
|
6470
|
-
|
|
6471
|
-
var
|
|
6472
|
-
if
|
|
6473
|
-
|
|
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
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
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
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
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
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
{
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
{
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
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
|
-
*
|
|
6748
|
-
*
|
|
6749
|
-
* @param
|
|
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
|
|
6753
|
-
var
|
|
6754
|
-
|
|
6755
|
-
|
|
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
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
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
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
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
|
-
*
|
|
6796
|
-
*
|
|
6797
|
-
*
|
|
6798
|
-
* @param
|
|
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
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
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
|
-
*
|
|
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
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
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
|
-
*
|
|
6826
|
-
*
|
|
6827
|
-
* @param
|
|
6828
|
-
* @
|
|
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
|
|
6831
|
-
|
|
6832
|
-
|
|
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 + "/
|
|
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
|
|
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({
|
|
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
|
|
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;
|