Skip to content

Commit

Permalink
WIP: Better Handling for Permissions (#367)
Browse files Browse the repository at this point in the history
* Better Handling for Permissions

UI portion of dockstore/dockstore#1589

This has a dependency on PR dockstore/dockstore#1638, which has a new
endpoint.

Call new endpoint to get allowable actions. If SHARE action is one
of the actions, then user is an owner, and go ahead and fetch all
permissions for the workflow.

Unfortunately, generated TS code doesn't generate a type for the enum
returned by Actions.
  • Loading branch information
coverbeck authored Jul 27, 2018
1 parent 3e03f00 commit 9e3a806
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jdk:
- oraclejdk8
env:
global:
- WEBSERVICE_VERSION="1.5.0-alpha.7"
- WEBSERVICE_VERSION="1.5.0-alpha.8"
matrix:
- RUN_PROD=false
- RUN_PROD=true
Expand Down
18 changes: 9 additions & 9 deletions cypress/integration/sharedWorkflows.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ describe('Shared with me workflow test from my-workflows', function() {
cy
.route({
method: "GET",
url: /readertest\/permissions/,
response: [{"email":"user_A","role":"READER"}]
}).as('readerPermissions')
url: /readertest\/actions/,
response: ["READ"]
}).as('readerActions')

cy
.route({
method: "GET",
url: /writertest\/permissions/,
response: [{"email":"user_A","role":"WRITER"}]
}).as('writerPermissions')
url: /writertest\/actions/,
response: ["READ", "WRITE"]
}).as('writerActions')

cy
.route({
method: "GET",
url: /ownertest\/permissions/,
response: [{"email":"user_A","role":"OWNER"}]
}).as('ownerPermissions')
url: /ownertest\/actions/,
response: ["READ", "WRITE", "SHARE", "DELETE"]
}).as('ownerActions')

let readerWorkflow = createHostedWorkflow('readertest', 200)
let writerWorkflow = createHostedWorkflow('writertest', 201);
Expand Down
2 changes: 1 addition & 1 deletion src/app/workflow/workflow.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ <h3>
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> To see the DAG, please refresh the workflow.
</div>
</tab>
<tab *ngIf="!isPublic() && isHosted() && isUserOwner()" id="permissionsTab" heading="Permissions" (select)="setEntryTab('permissions')">
<tab *ngIf="!isPublic() && isHosted() && isOwner" id="permissionsTab" heading="Permissions" (select)="setEntryTab('permissions')">
<app-permissions [workflow]="workflow"></app-permissions>
</tab>
</tabset>
Expand Down
75 changes: 17 additions & 58 deletions src/app/workflow/workflow.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,10 @@ export class WorkflowComponent extends Entry {
this.resourcePath = this.location.prepareExternalUrl(this.location.path());
}

private processResponse(userPermissions: Permission[]): void {
private processPermissions(userPermissions: Permission[]): void {
this.owners = this.specificPermissionEmails(userPermissions, RoleEnum.OWNER);
this.writers = this.specificPermissionEmails(userPermissions, RoleEnum.WRITER);
this.readers = this.specificPermissionEmails(userPermissions, RoleEnum.READER);

this.canRead = this.canUserRead();
this.canWrite = this.canUserWrite();
this.isOwner = this.isUserOwner();
}

private specificPermissionEmails(permissions: Permission[], role: RoleEnum): string[] {
Expand Down Expand Up @@ -157,13 +153,22 @@ export class WorkflowComponent extends Entry {
if (this.publicPage) {
this.sortedVersions = this.dockstoreService.getValidVersions(this.sortedVersions);
}
this.workflowsService.getWorkflowPermissions(this.workflow.full_workflow_path).pipe(takeUntil(this.ngUnsubscribe)).subscribe(
(userPermissions: Permission[]) => {
this.processResponse(userPermissions);
},
() => {
}
);
this.canRead = this.canWrite = this.isOwner = false;
this.readers = this.writers = this.owners = [];
this.workflowsService.getWorkflowActions(this.workflow.full_workflow_path).pipe(takeUntil(this.ngUnsubscribe))
.subscribe((actions: Array<string>) => {
// Alas, Swagger codegen does not generate a type for the actions
this.canRead = actions.indexOf('READ') !== -1;
this.canWrite = actions.indexOf('WRITE') !== -1;
this.isOwner = actions.indexOf('SHARE') !== -1;
if (this.isOwner) {
this.workflowsService.getWorkflowPermissions(this.workflow.full_workflow_path).pipe(takeUntil(this.ngUnsubscribe))
.subscribe((userPermissions: Permission[]) => {
this.processPermissions(userPermissions);
}
);
}
});
}
}

Expand Down Expand Up @@ -361,50 +366,4 @@ export class WorkflowComponent extends Entry {
}
}

/**
* True if user is in users list, or username is in read,write,owner permissions, false otherwise
*/
canUserRead(): boolean {
const username = this.user && this.user.username;
if (this.isInUserArray(username)) {
return true;
}
return this.readers.includes(username) || this.writers.includes(username) || this.owners.includes(username) ;
}

/**
* True if user is in users list, or username is in write or owner permissions, false otherwise
*/
canUserWrite(): boolean {
const username = this.user && this.user.username;
if (this.isInUserArray(username)) {
return true;
}
return this.writers.includes(username) || this.owners.includes(username);
}

/**
* True if user is in users list, or username is in owner permissions, false otherwise
*/
isUserOwner(): boolean {
const username = this.user && this.user.username;
if (this.isInUserArray(username)) {
return true;
}
return this.owners.includes(username);
}

/**
* True if username is in the workflow user array, false otherwise
* @param username
*/
isInUserArray(username: string): boolean {
if (this.workflow.users) {
const match = this.workflow.users.find((user) => user.username === username);
if (match !== undefined) {
return true;
}
}
return false;
}
}
11 changes: 8 additions & 3 deletions travisci/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ bitbucketClientSecret: <bitbucket secret here>
googleClientID: <fill me in>
googleClientSecret: <fill me in>
googleRedirectURI: http://localhost:8080/auth/tokens/google.com
hostname: localhost
scheme: http
port: 8080

authorizerType: inmemory

externalConfig:
basePath: /
hostname: localhost
scheme: http
port: 8080

authenticationCachePolicy: maximumSize=10000, expireAfterAccess=10m

Expand Down

0 comments on commit 9e3a806

Please sign in to comment.