Skip to content

Commit

Permalink
fix(sharing): rework group membership checking, fix UserSession.getUs…
Browse files Browse the repository at this point in the history
…er scope issue

AFFECTS PACKAGES:
@esri/arcgis-rest-sharing

:nailcare:
  • Loading branch information
dbouwman authored and jgravois committed Sep 10, 2018
1 parent 40bc5c1 commit 909a37e
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 53 deletions.
2 changes: 1 addition & 1 deletion packages/arcgis-rest-auth/src/UserSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ export class UserSession implements IAuthenticationManager {
*/
getUser(requestOptions?: IRequestOptions): Promise<IUser> {
if (this._user && this._user.username === this.username) {
return new Promise(resolve => resolve(this._user));
return Promise.resolve(this._user);
} else {
const url = `${this.portal}/community/users/${encodeURIComponent(
this.username
Expand Down
5 changes: 4 additions & 1 deletion packages/arcgis-rest-common-types/src/group.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

// if you want to get *really* pedantic, nonmember is more _derived_
export type GroupMembership = "owner" | "admin" | "member" | "nonmember";

/**
* A [Group](https://developers.arcgis.com/rest/users-groups-and-items/common-parameters.htm) that has not been created yet.
*/
Expand Down Expand Up @@ -44,7 +47,7 @@ export interface IGroup extends IGroupAdd {
autoJoin: boolean;
userMembership?: {
username?: string;
memberType?: string;
memberType?: GroupMembership;
applications?: number;
};
hasCategorySchema?: boolean;
Expand Down
14 changes: 8 additions & 6 deletions packages/arcgis-rest-sharing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@
"types": "dist/esm/index.d.ts",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^1.7.1"
"tslib": "^1.8.0"
},
"peerDependencies": {
"@esri/arcgis-rest-auth": "^1.7.1",
"@esri/arcgis-rest-common-types": "^1.7.1",
"@esri/arcgis-rest-request": "^1.7.1"
"@esri/arcgis-rest-auth": "^1.8.0",
"@esri/arcgis-rest-common-types": "^1.8.0",
"@esri/arcgis-rest-request": "^1.8.0",
"@esri/arcgis-rest-groups": "^1.8.0"
},
"devDependencies": {
"@esri/arcgis-rest-auth": "^1.8.0",
"@esri/arcgis-rest-common-types": "^1.7.1",
"@esri/arcgis-rest-request": "^1.8.0"
"@esri/arcgis-rest-common-types": "^1.8.0",
"@esri/arcgis-rest-request": "^1.8.0",
"@esri/arcgis-rest-groups": "^1.8.0"
},
"files": [
"dist/**"
Expand Down
11 changes: 7 additions & 4 deletions packages/arcgis-rest-sharing/src/group-sharing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function changeGroupSharing(
}`;
} else {
// if they are a group admin/owner, use the bare item url
if (membership === "admin") {
if (membership === "admin" || membership === "owner") {
return `${getPortalUrl(requestOptions)}/content/items/${
requestOptions.id
}/${requestOptions.action}`;
Expand Down Expand Up @@ -179,15 +179,18 @@ function isItemSharedWithGroup(
sortField: "title"
};

// we need to append some params into requestOptions, so make a clone
// instead of mutating the params on the inbound requestOptions object
const options = { ...requestOptions };
// instead of calling out to "@esri/arcgis-rest-items, make the request manually to forgoe another dependency
requestOptions.params = {
options.params = {
...query,
...requestOptions.params
};

const url = `${getPortalUrl(requestOptions)}/search`;
const url = `${getPortalUrl(options)}/search`;

return request(url, requestOptions).then(searchResponse => {
return request(url, options).then(searchResponse => {
// if there are no search results at all, we know the item hasnt already been shared with the group
if (searchResponse.total === 0) {
return false;
Expand Down
69 changes: 33 additions & 36 deletions packages/arcgis-rest-sharing/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */
import {
request,
IRequestOptions,
getPortalUrl
} from "@esri/arcgis-rest-request";

import { IRequestOptions, getPortalUrl } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import { IUser, IGroup } from "@esri/arcgis-rest-common-types";
import { IGroup, IUser, GroupMembership } from "@esri/arcgis-rest-common-types";
import { getGroup } from "@esri/arcgis-rest-groups";
import { IGroupSharingRequestOptions } from "./group-sharing";

export interface ISharingRequestOptions extends IRequestOptions {
Expand All @@ -24,6 +22,13 @@ export interface ISharingRequestOptions extends IRequestOptions {
owner?: string;
}

export interface IGroupIdRequestOptions extends IRequestOptions {
/**
* Group identifier
*/
groupId: string;
}

export interface ISharingResponse {
notSharedWith?: string[];
notUnsharedFrom?: string[];
Expand All @@ -44,12 +49,17 @@ export function isItemOwner(requestOptions: ISharingRequestOptions): boolean {
return owner === username;
}

/**
* Check it the user is a full org_admin
* @param requestOptions
* @returns {Promise<string>} Promise resolving in a boolean indicating if the user is a full Org Admin
*/
export function isOrgAdmin(
requestOptions: ISharingRequestOptions
): Promise<boolean> {
const session = requestOptions.authentication as UserSession;

return session.getUser(requestOptions).then(user => {
return session.getUser(requestOptions).then((user: IUser) => {
if (!user || user.role !== "org_admin") {
return false;
} else {
Expand All @@ -58,35 +68,22 @@ export function isOrgAdmin(
});
}

/**
* Get the User Membership for a particular group. Use this if all you have is the groupId.
* If you have the group object, check the `userMembership.memberType` property instead of calling this method.
*
* @param IGroupIdRequestOptions options to pass through in the request
* @returns A Promise that resolves with "owner" | "admin" | "member" | "nonmember"
*/
export function getUserMembership(
requestOptions: IGroupSharingRequestOptions
): Promise<string> {
// start by assuming the user does not belong to the group
let result = "nonmember";
const session = requestOptions.authentication as UserSession;

// the response to this call is cached. yay!
return session
.getUser(requestOptions)
.then((user: IUser) => {
if (user.groups) {
user.groups.some(function(group: IGroup) {
const matchedGroup = group.id === requestOptions.groupId;
if (matchedGroup) {
result = group.userMembership.memberType;
}
return matchedGroup;
});
}
return result;
requestOptions: IGroupIdRequestOptions
): Promise<GroupMembership> {
// fetch the group...
return getGroup(requestOptions.groupId, requestOptions)
.then((group: IGroup) => {
return group.userMembership.memberType;
})
.catch(
/* istanbul ignore next */ err => {
throw Error(
`failure determining membership of ${session.username} in group:${
requestOptions.groupId
}: ${err}`
);
}
);
.catch(() => {
return "nonmember" as GroupMembership;
});
}
Loading

0 comments on commit 909a37e

Please sign in to comment.