Skip to content

Commit

Permalink
feat(users): add user invitation functions
Browse files Browse the repository at this point in the history
AFFECTS PACKAGES:
@esri/arcgis-rest-common-types
@esri/arcgis-rest-users
  • Loading branch information
mjuniper committed Oct 8, 2018
1 parent cb20c9d commit 80aa6dc
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/arcgis-rest-common-types/src/group.ts
Expand Up @@ -42,7 +42,7 @@ export interface IGroup extends IGroupAdd {
protected: boolean;
isInvitationOnly: boolean;
isViewOnly: boolean;
isOpenData: boolean;
isOpenData?: boolean;
isFav: boolean;
autoJoin: boolean;
userMembership?: {
Expand Down
1 change: 1 addition & 0 deletions packages/arcgis-rest-users/src/index.ts
Expand Up @@ -3,3 +3,4 @@

export * from "./get";
export * from "./notification";
export * from "./invitation";
102 changes: 102 additions & 0 deletions packages/arcgis-rest-users/src/invitation.ts
@@ -0,0 +1,102 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { request, getPortalUrl } from "@esri/arcgis-rest-request";

import { IUserRequestOptions } from "@esri/arcgis-rest-auth";
import { IGroup } from "@esri/arcgis-rest-common-types";

export interface IInvitation {
id: string;
targetType: string;
targetId: string;
received: number;
accepted: boolean;
mustApprove: boolean;
email: string;
role: string;
type: string;
dateAccepted: number;
expiration: number;
created: number;
username: string;
fromUsername: {
username: string;
fullname?: string;
};
group?: IGroup;
groupId?: string;
}

export interface IInvitationResult {
userInvitations: IInvitation[];
}

/**
* Get invitations for a user.
*
* @param requestOptions - options to pass through in the request
* @returns A Promise that will resolve with the user's invitations
*/
export function getUserInvitations(
requestOptions: IUserRequestOptions
): Promise<IInvitationResult> {
let options = { httpMethod: "GET" } as IUserRequestOptions;

const username = encodeURIComponent(requestOptions.authentication.username);
const portalUrl = getPortalUrl(requestOptions);
const url = `${portalUrl}/community/users/${username}/invitations`;
options = { ...requestOptions, ...options };

// send the request
return request(url, options);
}

/**
* Get an invitation for a user by id.
*
* @param requestOptions - options to pass through in the request
* @returns A Promise that will resolve with the invitation
*/
export function getUserInvitation(
id: string,
requestOptions: IUserRequestOptions
): Promise<IInvitation> {
let options = { httpMethod: "GET" } as IUserRequestOptions;

const username = encodeURIComponent(requestOptions.authentication.username);
const portalUrl = getPortalUrl(requestOptions);
const url = `${portalUrl}/community/users/${username}/invitations/${id}`;
options = { ...requestOptions, ...options };

// send the request
return request(url, options);
}

/**
* Accept an invitation.
*
* @param requestOptions - Options for the request
* @returns A Promise that will resolve with the success/failure status of the request
*/
export function acceptInvitation(
id: string,
requestOptions: IUserRequestOptions
): Promise<any> {
const username = encodeURIComponent(requestOptions.authentication.username);
const portalUrl = getPortalUrl(requestOptions);
const url = `${portalUrl}/community/users/${username}/invitations/${id}/accept`;

return request(url, requestOptions);
}

export function declineInvitation(
id: string,
requestOptions: IUserRequestOptions
): Promise<any> {
const username = encodeURIComponent(requestOptions.authentication.username);
const portalUrl = getPortalUrl(requestOptions);
const url = `${portalUrl}/community/users/${username}/invitations/${id}/decline`;

return request(url, requestOptions);
}
169 changes: 169 additions & 0 deletions packages/arcgis-rest-users/test/invitation.test.ts
@@ -0,0 +1,169 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import {
getUserInvitations,
getUserInvitation,
acceptInvitation,
declineInvitation
} from "../src/index";

import {
UserInvitationsResponse,
UserInvitationResponse
} from "./mocks/responses";

import { encodeParam } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import * as fetchMock from "fetch-mock";

const TOMORROW = (function() {
const now = new Date();
now.setDate(now.getDate() + 1);
return now;
})();

describe("invitations", () => {
afterEach(fetchMock.restore);

const session = new UserSession({
username: "c@sey",
password: "123456",
portal: "https://myorg.maps.arcgis.com/sharing/rest"
});

fetchMock.postOnce(
"https://myorg.maps.arcgis.com/sharing/rest/generateToken",
{
token: "fake-token",
expires: TOMORROW.getTime(),
username: "c@sey"
}
);

describe("getUserInvitations", () => {
session.refreshSession();

it("should make an authenticated request for user invitations", done => {
fetchMock.once("*", UserInvitationsResponse);

getUserInvitations({ authentication: session })
.then(response => {
expect(fetchMock.called()).toEqual(true);
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/community/users/c%40sey/invitations?f=json&token=fake-token"
);
expect(options.method).toBe("GET");
expect(response.userInvitations.length).toEqual(1);
done();
})
.catch(e => {
fail(e);
});
});
});

describe("getUserInvitation", () => {
fetchMock.postOnce(
"https://myorg.maps.arcgis.com/sharing/rest/generateToken",
{
token: "fake-token",
expires: TOMORROW.getTime(),
username: "c@sey"
}
);

session.refreshSession();

it("should make an authenticated request for a user invitation", done => {
fetchMock.once("*", UserInvitationResponse);

getUserInvitation("3ef", { authentication: session })
.then(response => {
expect(fetchMock.called()).toEqual(true);
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/community/users/c%40sey/invitations/3ef?f=json&token=fake-token"
);
expect(options.method).toBe("GET");
expect(response.id).toEqual("G45ad52e7560e470598815499003c13f6");
expect(response.id).toEqual("G45ad52e7560e470598815499003c13f6");
done();
})
.catch(e => {
fail(e);
});
});
});

describe("acceptInvitation", () => {
fetchMock.postOnce(
"https://myorg.maps.arcgis.com/sharing/rest/generateToken",
{
token: "fake-token",
expires: TOMORROW.getTime(),
username: "c@sey"
}
);

session.refreshSession();

it("should accept an invitation", done => {
fetchMock.once("*", { success: true });

acceptInvitation("3ef", { authentication: session })
.then(response => {
expect(fetchMock.called()).toEqual(true);
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/community/users/c%40sey/invitations/3ef/accept"
);
expect(options.method).toBe("POST");
expect(options.body).toContain(encodeParam("f", "json"));
expect(options.body).toContain(encodeParam("token", "fake-token"));
expect(response.success).toEqual(true);
// expect(response.notificationId).toBe("3ef");
done();
})
.catch(e => {
fail(e);
});
});
});

describe("declineInvitation", () => {
fetchMock.postOnce(
"https://myorg.maps.arcgis.com/sharing/rest/generateToken",
{
token: "fake-token",
expires: TOMORROW.getTime(),
username: "c@sey"
}
);

session.refreshSession();

it("should decline an invitation", done => {
fetchMock.once("*", { success: true });

declineInvitation("3ef", { authentication: session })
.then(response => {
expect(fetchMock.called()).toEqual(true);
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/community/users/c%40sey/invitations/3ef/decline"
);
expect(options.method).toBe("POST");
expect(options.body).toContain(encodeParam("f", "json"));
expect(options.body).toContain(encodeParam("token", "fake-token"));
expect(response.success).toEqual(true);
// expect(response.notificationId).toBe("3ef");
done();
})
.catch(e => {
fail(e);
});
});
});
});
70 changes: 70 additions & 0 deletions packages/arcgis-rest-users/test/mocks/responses.ts
Expand Up @@ -3,6 +3,7 @@

import { IUser } from "@esri/arcgis-rest-common-types";
import { INotificationResult } from "../../src/notification";
import { IInvitation, IInvitationResult } from "../../src/invitation";

export const AnonUserResponse: IUser = {
username: "jsmith",
Expand Down Expand Up @@ -205,3 +206,72 @@ export const IDeleteSuccessResponse: any = {
success: true,
notificationId: "3ef"
};

export const UserInvitationsResponse: IInvitationResult = {
userInvitations: [
{
id: "G45ad52e7560e470598815499003c13f6",
targetType: "group",
targetId: "5d780fcf924e4e7ab1952a71472bc950",
received: 1538516323000,
accepted: false,
mustApprove: false,
email: null,
role: "group_member",
type: "user",
dateAccepted: -1,
expiration: 1539725923000,
created: 1538516323000,
username: "mjuniper_dcqa",
fromUsername: {
username: "dcadminqa"
},
groupId: "5d780fcf924e4e7ab1952a71472bc950"
}
]
};

export const UserInvitationResponse: IInvitation = {
id: "G45ad52e7560e470598815499003c13f6",
targetType: "group",
targetId: "5d780fcf924e4e7ab1952a71472bc950",
received: 1538516323000,
accepted: false,
mustApprove: false,
email: null,
role: "group_member",
type: "user",
dateAccepted: -1,
expiration: 1539725923000,
created: 1538516323000,
username: "mjuniper_dcqa",
fromUsername: {
username: "dcadminqa",
fullname: "DcAdminQA QaExtDc"
},
group: {
id: "5d780fcf924e4e7ab1952a71472bc950",
title: "Jupe test group 2",
isInvitationOnly: true,
owner: "dcadminqa",
description: null,
snippet: null,
tags: ["hub"],
phone: null,
sortField: "title",
sortOrder: "asc",
isViewOnly: false,
thumbnail: null,
created: 1538516296000,
modified: 1538516296000,
access: "public",
capabilities: [],
isFav: false,
isReadOnly: false,
protected: false,
autoJoin: false,
notificationsEnabled: false,
provider: null,
providerGroupName: null
}
};

0 comments on commit 80aa6dc

Please sign in to comment.