Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(hub-sites): prevent surveys and their feature services from being… #669

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51,751 changes: 18,919 additions & 32,832 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/sites/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"@esri/arcgis-rest-request": "^2.13.0 || 3",
"@esri/hub-common": "^8.2.0 || 9",
"@esri/hub-initiatives": "^8.0.0 || 9",
"@esri/hub-teams": "^8.0.0 || 9"
"@esri/hub-teams": "^8.0.0 || 9",
"@esri/hub-surveys": "^8.0.0 || 9"
rweber-esri marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"@esri/arcgis-rest-auth": "^3.1.1",
Expand All @@ -28,6 +29,7 @@
"@esri/hub-initiatives": "^9.1.1",
"@esri/hub-teams": "^9.1.1",
"@esri/hub-types": "^6.10.0",
"@esri/hub-surveys": "^9.1.1",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
Expand Down
48 changes: 48 additions & 0 deletions packages/sites/src/_get-sharing-eligible-models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { IModel, IHubRequestOptions } from "@esri/hub-common";
import { getSurveyModels } from "@esri/hub-surveys";

function _getIneligibleModelIds(
siteModel: IModel,
models: IModel[],
hubRequestOptions: IHubRequestOptions
) {
const fetchSurveyModels = (model: IModel) =>
getSurveyModels(model.item, hubRequestOptions).then(
({ form, featureService, fieldworker, stakeholder }) =>
[form, featureService, fieldworker, stakeholder].filter(Boolean)
);

const inEligibleModelCollectionPromises = models.reduce(
(acc, model) =>
model.item.type === "Form" ? [...acc, fetchSurveyModels(model)] : acc,
[Promise.resolve([siteModel])]
);

return Promise.all(inEligibleModelCollectionPromises).then(
(ineligibleModelCollections) =>
ineligibleModelCollections.reduce(
(acc, ineligibleModelCollection) => [
...acc,
...ineligibleModelCollection,
],
[]
)
);
}

export function _getSharingEligibleModels(
siteModel: IModel,
models: IModel[],
hubRequestOptions: IHubRequestOptions
) {
return _getIneligibleModelIds(siteModel, models, hubRequestOptions).then(
(ineligibleModels) =>
models.reduce(
(acc, model) =>
ineligibleModels.find(({ item: { id } }) => model.item.id === id)
? acc
: [...acc, model],
[]
)
);
}
42 changes: 25 additions & 17 deletions packages/sites/src/_share-items-to-site-groups.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IModel, IHubRequestOptions, failSafe } from "@esri/hub-common";
import { shareItemWithGroup, ISharingResponse } from "@esri/arcgis-rest-portal";
import { _getSecondPassSharingOptions } from "./_get-second-pass-sharing-options";
import { _getSharingEligibleModels } from "./_get-sharing-eligible-models";

/**
* Share all the other models to the Site's content and collaboration groups, if
Expand Down Expand Up @@ -35,26 +36,33 @@ export function shareItemsToSiteGroups(
solutionModels: IModel[],
hubRequestOptions: IHubRequestOptions
) {
const otherModels = solutionModels.filter(m => {
return m.item.id !== siteModel.item.id;
});
// Create Fail-safe version of share b/c this is not critical
const failSafeShare = failSafe(shareItemWithGroup, { success: true });

const groupsToShareTo = _getSecondPassSharingOptions(siteModel);
// share all items in the solution to the groups
return Promise.all(
otherModels.reduce((acc: Array<Promise<ISharingResponse>>, m: IModel) => {
const itemSharePromises = groupsToShareTo.map(g => {
const opts = {
id: m.item.id,
groupId: g.id,
confirmItemControl: g.confirmItemControl,
authentication: hubRequestOptions.authentication
};
return failSafeShare(opts) as Promise<ISharingResponse>;
});
return acc.concat(itemSharePromises);
}, [])
// share all items in the solution to the groups, excluding the the site, form
// and any form feature services
return _getSharingEligibleModels(
siteModel,
solutionModels,
hubRequestOptions
).then((eligibleModels) =>
Promise.all(
eligibleModels.reduce(
(acc: Array<Promise<ISharingResponse>>, m: IModel) => {
const itemSharePromises = groupsToShareTo.map((g) => {
const opts = {
id: m.item.id,
groupId: g.id,
confirmItemControl: g.confirmItemControl,
authentication: hubRequestOptions.authentication,
};
return failSafeShare(opts) as Promise<ISharingResponse>;
});
return acc.concat(itemSharePromises);
},
[]
)
)
);
}
54 changes: 54 additions & 0 deletions packages/sites/test/_get-sharing-eligible-models.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { IModel, IHubRequestOptions } from "@esri/hub-common";
import * as hubSurveys from "@esri/hub-surveys";
import { _getSharingEligibleModels } from "../src/_get-sharing-eligible-models";
import { getSurveyModels } from "@esri/hub-surveys";

describe("_getSharingEligibleModels", function () {
let models: IModel[];
let siteModel: IModel;
let hubRequestOptions: IHubRequestOptions;

beforeEach(() => {
siteModel = { item: { id: "site-id" } } as IModel;

models = [
siteModel,
{ item: { id: "123", type: "Web Map" } },
{ item: { id: "456", type: "Form" } },
{ item: { id: "789", type: "Feature Service" } },
{ item: { id: "101", type: "Feature Service" } },
{ item: { id: "121", type: "Feature Service" } },
] as IModel[];

hubRequestOptions = { authentication: {} } as IHubRequestOptions;
});

it("resolves an array of sharing eligible models", async function () {
const getSurveyModelsSpy = spyOn(
hubSurveys,
"getSurveyModels"
).and.returnValue(
Promise.resolve({
form: models[2],
featureService: models[3],
fieldworker: models[4],
stakeholder: models[5],
})
);
const results = await _getSharingEligibleModels(
siteModel,
models,
hubRequestOptions
);
expect(getSurveyModelsSpy.calls.count()).toBe(1);
expect(getSurveyModelsSpy).toHaveBeenCalledWith(
models[2].item,
hubRequestOptions
);
expect(results.length).toBe(1);
expect(results[0]).toEqual(models[1]);
});
});
90 changes: 26 additions & 64 deletions packages/sites/test/_share-items-to-site-groups.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { _shareItemsToSiteGroups, shareItemsToSiteGroups } from "../src";
import * as portalModule from "@esri/arcgis-rest-portal";
import { IModel, IHubRequestOptions } from "@esri/hub-common";
import * as sharingEligibleModelsModule from "../src/_get-sharing-eligible-models";

describe("_shareItemsToSiteGroups", () => {
it("shares items to groups", async () => {
it("shares items to groups using shareItemsToSiteGroups", async () => {
const shareSpy = spyOn(portalModule, "shareItemWithGroup").and.returnValue(
Promise.resolve({})
);
Expand All @@ -13,76 +14,37 @@ describe("_shareItemsToSiteGroups", () => {
id: "site-id",
properties: {
contentGroupId: "content-id",
collaborationGroupId: "collab-id"
}
}
collaborationGroupId: "collab-id",
},
},
} as IModel;

const hubRequestOptions = {
authentication: {},
} as IHubRequestOptions;

const toShare = [
siteModel,
{ item: { id: "foo" } },
{ item: { id: "bar" } }
{ item: { id: "bar" } },
] as IModel[];

await _shareItemsToSiteGroups(siteModel, toShare, {
authentication: {}
} as IHubRequestOptions);
const _getSharingEligibleModelsSpy = spyOn(
sharingEligibleModelsModule,
"_getSharingEligibleModels"
).and.returnValue(Promise.resolve(toShare.slice(1, 3)));

expect(shareSpy.calls.count()).toBe(
4,
"share called correct number of times"
);
expect(shareSpy).toHaveBeenCalledWith({
id: "foo",
groupId: "content-id",
confirmItemControl: false,
authentication: {}
});
expect(shareSpy).toHaveBeenCalledWith({
id: "bar",
groupId: "collab-id",
confirmItemControl: true,
authentication: {}
});
expect(shareSpy).toHaveBeenCalledWith({
id: "foo",
groupId: "content-id",
confirmItemControl: false,
authentication: {}
});
expect(shareSpy).toHaveBeenCalledWith({
id: "bar",
groupId: "collab-id",
confirmItemControl: true,
authentication: {}
});
});
await shareItemsToSiteGroups(siteModel, toShare, hubRequestOptions);

it("shares items to groups using shareItemsToSiteGroups", async () => {
const shareSpy = spyOn(portalModule, "shareItemWithGroup").and.returnValue(
Promise.resolve({})
expect(_getSharingEligibleModelsSpy.calls.count()).toBe(
1,
"calls _getSharingEligibleModelsSpy once"
);

const siteModel = {
item: {
id: "site-id",
properties: {
contentGroupId: "content-id",
collaborationGroupId: "collab-id"
}
}
} as IModel;

const toShare = [
expect(_getSharingEligibleModelsSpy).toHaveBeenCalledWith(
siteModel,
{ item: { id: "foo" } },
{ item: { id: "bar" } }
] as IModel[];

await shareItemsToSiteGroups(siteModel, toShare, {
authentication: {}
} as IHubRequestOptions);

toShare,
hubRequestOptions
);
expect(shareSpy.calls.count()).toBe(
4,
"share called correct number of times"
Expand All @@ -91,25 +53,25 @@ describe("_shareItemsToSiteGroups", () => {
id: "foo",
groupId: "content-id",
confirmItemControl: false,
authentication: {}
authentication: {},
});
expect(shareSpy).toHaveBeenCalledWith({
id: "bar",
groupId: "collab-id",
confirmItemControl: true,
authentication: {}
authentication: {},
});
expect(shareSpy).toHaveBeenCalledWith({
id: "foo",
groupId: "content-id",
confirmItemControl: false,
authentication: {}
authentication: {},
});
expect(shareSpy).toHaveBeenCalledWith({
id: "bar",
groupId: "collab-id",
confirmItemControl: true,
authentication: {}
authentication: {},
});
});
});
21 changes: 13 additions & 8 deletions packages/surveys/src/items/get-survey-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Apache-2.0 */

import { IRequestOptions } from "@esri/arcgis-rest-request";
import { getItem } from "@esri/arcgis-rest-portal";
import { getItem, IItem } from "@esri/arcgis-rest-portal";
import { IModel, IGetSurveyModelsResponse } from "@esri/hub-common";
import { getInputFeatureServiceModel } from "./get-input-feature-service-model";
import { getSourceFeatureServiceModelFromFieldworker } from "./get-source-feature-service-model-from-fieldworker";
Expand All @@ -16,18 +16,23 @@ import { isFieldworkerView } from "../utils/is-fieldworker-view";
* @returns {Promise<IGetSurveyModelsResponse>}
*/
export const getSurveyModels = (
formId: string,
formItemOrId: string | IItem,
requestOptions: IRequestOptions
): Promise<IGetSurveyModelsResponse> => {
let fieldworker: IModel;
let stakeholder: IModel;

return getItem(formId, requestOptions).then(item => {
const getForm = () =>
typeof formItemOrId === "string"
? getItem(formItemOrId, requestOptions)
: Promise.resolve(formItemOrId);

return getForm().then((form) => {
const promises: Array<Promise<IModel>> = [
// the primary input will be the fieldworker (if it exists), otherwise
// the source feature service.
getInputFeatureServiceModel(formId, requestOptions),
getStakeholderModel(formId, requestOptions)
getInputFeatureServiceModel(form.id, requestOptions),
getStakeholderModel(form.id, requestOptions),
];

return Promise.all(promises)
Expand All @@ -49,12 +54,12 @@ export const getSurveyModels = (
return featureServiceOrFieldworkerModelResult;
}
})
.then(featureService => {
.then((featureService) => {
return {
form: { item },
form: { item: form },
featureService,
fieldworker,
stakeholder
stakeholder,
};
});
});
Expand Down
Loading