Pass subscriptionId when publishing/accessing published notebooks (#288)

We need to record `subscriptionId` when publishing a notebook, also we want to restrict notebooks to only from a particular `subscriptionId` when accessing `My published work` tab. This change passes the `subscriptionId` as part of the URL when publishing or accessing published notebooks.
This commit is contained in:
Tanuj Mittal 2020-10-21 17:01:22 -07:00 committed by GitHub
parent 1e19f02fd7
commit 734df3dd18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 35 deletions

View File

@ -1,9 +1,12 @@
import ko from "knockout"; import ko from "knockout";
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants"; import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
import { IPinnedRepo, JunoClient } from "./JunoClient"; import { IPinnedRepo, JunoClient, IPublishNotebookRequest } from "./JunoClient";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { DatabaseAccount } from "../Contracts/DataModels"; import { DatabaseAccount } from "../Contracts/DataModels";
import { updateUserContext, userContext } from "../UserContext";
const sampleSubscriptionId = "subscriptionId";
const sampleDatabaseAccount: DatabaseAccount = { const sampleDatabaseAccount: DatabaseAccount = {
id: "id", id: "id",
@ -131,11 +134,20 @@ describe("GitHub", () => {
describe("Gallery", () => { describe("Gallery", () => {
const junoClient = new JunoClient(ko.observable<DatabaseAccount>(sampleDatabaseAccount)); const junoClient = new JunoClient(ko.observable<DatabaseAccount>(sampleDatabaseAccount));
const originalSubscriptionId = userContext.subscriptionId;
beforeAll(() => {
updateUserContext({ subscriptionId: sampleSubscriptionId });
});
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
}); });
afterAll(() => {
updateUserContext({ subscriptionId: originalSubscriptionId });
});
it("getSampleNotebooks", async () => { it("getSampleNotebooks", async () => {
window.fetch = jest.fn().mockReturnValue({ window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK, status: HttpStatusCodes.OK,
@ -295,12 +307,15 @@ describe("Gallery", () => {
const authorizationHeader = getAuthorizationHeader(); const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK); expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toBeCalledWith(`${configContext.JUNO_ENDPOINT}/api/notebooks/gallery/published`, { expect(window.fetch).toBeCalledWith(
headers: { `${configContext.JUNO_ENDPOINT}/api/notebooks/${sampleSubscriptionId}/gallery/published`,
[authorizationHeader.header]: authorizationHeader.token, {
[HttpHeaders.contentType]: "application/json" headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json"
}
} }
}); );
}); });
it("deleteNotebook", async () => { it("deleteNotebook", async () => {
@ -330,17 +345,26 @@ describe("Gallery", () => {
const author = "author"; const author = "author";
const thumbnailUrl = "thumbnailUrl"; const thumbnailUrl = "thumbnailUrl";
const content = `{ "key": "value" }`; const content = `{ "key": "value" }`;
const addLinkToNotebookViewer = false;
window.fetch = jest.fn().mockReturnValue({ window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK, status: HttpStatusCodes.OK,
json: () => undefined as any json: () => undefined as any
}); });
const response = await junoClient.publishNotebook(name, description, tags, author, thumbnailUrl, content, false); const response = await junoClient.publishNotebook(
name,
description,
tags,
author,
thumbnailUrl,
content,
addLinkToNotebookViewer
);
const authorizationHeader = getAuthorizationHeader(); const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK); expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toBeCalledWith( expect(window.fetch).toBeCalledWith(
`${configContext.JUNO_ENDPOINT}/api/notebooks/${sampleDatabaseAccount.name}/gallery`, `${configContext.JUNO_ENDPOINT}/api/notebooks/${sampleSubscriptionId}/${sampleDatabaseAccount.name}/gallery`,
{ {
method: "PUT", method: "PUT",
headers: { headers: {
@ -353,8 +377,9 @@ describe("Gallery", () => {
tags, tags,
author, author,
thumbnailUrl, thumbnailUrl,
content: JSON.parse(content) content: JSON.parse(content),
}) addLinkToNotebookViewer
} as IPublishNotebookRequest)
} }
); );
}); });

View File

@ -5,6 +5,7 @@ import * as DataModels from "../Contracts/DataModels";
import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent"; import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent";
import { IGitHubResponse } from "../GitHub/GitHubClient"; import { IGitHubResponse } from "../GitHub/GitHubClient";
import { IGitHubOAuthToken } from "../GitHub/GitHubOAuthService"; import { IGitHubOAuthToken } from "../GitHub/GitHubOAuthService";
import { userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
export interface IJunoResponse<T> { export interface IJunoResponse<T> {
@ -55,13 +56,15 @@ export interface IUserGallery {
published: string[]; published: string[];
} }
interface IPublishNotebookRequest { // Only exported for unit test
export interface IPublishNotebookRequest {
name: string; name: string;
description: string; description: string;
tags: string[]; tags: string[];
author: string; author: string;
thumbnailUrl: string; thumbnailUrl: string;
content: any; content: any;
addLinkToNotebookViewer: boolean;
} }
export class JunoClient { export class JunoClient {
@ -331,7 +334,7 @@ export class JunoClient {
} }
public async getPublishedNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> { public async getPublishedNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
return await this.getNotebooks(`${this.getNotebooksUrl()}/gallery/published`, { return await this.getNotebooks(`${this.getNotebooksUrl()}/${this.getSubscriptionId()}/gallery/published`, {
headers: JunoClient.getHeaders() headers: JunoClient.getHeaders()
}); });
} }
@ -362,28 +365,22 @@ export class JunoClient {
content: string, content: string,
isLinkInjectionEnabled: boolean isLinkInjectionEnabled: boolean
): Promise<IJunoResponse<IGalleryItem>> { ): Promise<IJunoResponse<IGalleryItem>> {
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/gallery`, { const response = await window.fetch(
method: "PUT", `${this.getNotebooksUrl()}/${this.getSubscriptionId()}/${this.getAccount()}/gallery`,
headers: JunoClient.getHeaders(), {
body: isLinkInjectionEnabled method: "PUT",
? JSON.stringify({ headers: JunoClient.getHeaders(),
name, body: JSON.stringify({
description, name,
tags, description,
author, tags,
thumbnailUrl, author,
content: JSON.parse(content), thumbnailUrl,
addLinkToNotebookViewer: isLinkInjectionEnabled content: JSON.parse(content),
} as IPublishNotebookRequest) addLinkToNotebookViewer: isLinkInjectionEnabled
: JSON.stringify({ } as IPublishNotebookRequest)
name, }
description, );
tags,
author,
thumbnailUrl,
content: JSON.parse(content)
} as IPublishNotebookRequest)
});
let data: IGalleryItem; let data: IGalleryItem;
if (response.status === HttpStatusCodes.OK) { if (response.status === HttpStatusCodes.OK) {
@ -448,8 +445,16 @@ export class JunoClient {
return `${configContext.JUNO_ENDPOINT}/api/notebooks`; return `${configContext.JUNO_ENDPOINT}/api/notebooks`;
} }
private getAccount(): string {
return this.databaseAccount().name;
}
private getSubscriptionId(): string {
return userContext.subscriptionId;
}
private getNotebooksAccountUrl(): string { private getNotebooksAccountUrl(): string {
return `${configContext.JUNO_ENDPOINT}/api/notebooks/${this.databaseAccount().name}`; return `${this.getNotebooksUrl()}/${this.getAccount()}`;
} }
private static getHeaders(): HeadersInit { private static getHeaders(): HeadersInit {