Skip to content

Commit

Permalink
Feature/private access (#173) (#175)
Browse files Browse the repository at this point in the history
* Display Request Access button and Contact Author button

* Add tests, moved functions to separate service
  • Loading branch information
garyluu authored Jan 22, 2018
1 parent ab43964 commit 30c985a
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 6 deletions.
32 changes: 26 additions & 6 deletions src/app/container/container.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<div class="row" *ngIf="error || missingWarning">
<div class="col-md-12" *ngIf="!isToolPublic">
<div class="alert alert-warning" ng-class="!editMode ? 'push-top' : ''" role="alert" *ngIf="missingWarning">
Expand All @@ -35,7 +34,7 @@ <h3 id="tool-path">
</a>
</span>
<span *ngIf="tool?.private_access" class="private-lock" tooltip="Private">
<app-private-icon></app-private-icon>
<app-private-icon></app-private-icon>
</span>
{{ tool?.tool_path }}
<app-starring *ngIf="isToolPublic" (change)="starGazersChange()"></app-starring>
Expand All @@ -59,7 +58,8 @@ <h3 id="tool-path">
<h3>
<div class="pull-right">
<div class="btn-group" role="group">
<button id="publishToolButton" type="button" [ngClass]="{'disabled': publishDisable()}" class="btn btn-warning" (click)="publish()" [(ngModel)]="published" [disabled]="!thisisValid" btnCheckbox>
<button id="publishToolButton" type="button" [ngClass]="{'disabled': publishDisable()}" class="btn btn-warning" (click)="publish()" [(ngModel)]="published"
[disabled]="!thisisValid" btnCheckbox>
{{tool?.is_published ? 'Unpublish' : 'Publish'}}
</button>

Expand All @@ -71,6 +71,24 @@ <h3>
</div>
</h3>
</div>
<div class="col-md-4">
<h3 class="pull-right">
<div class="button contact-button" *ngIf="publicPage && tool?.private_access">
<p>
<a [href]="requestAccessHREF">
Request Access
</a>
</p>
</div>
<div class="button contact-button" *ngIf="publicPage && tool?.email && !tool?.private_access">
<p>
<a [href]="contactAuthorHREF">
Contact Author
</a>
</p>
</div>
</h3>
</div>
</div>
<div class="row" *ngIf="!starGazersClicked">
<div class="ds-tabs col-sm-12" [ngClass]="{'col-md-9 col-lg-9': isToolPublic}">
Expand Down Expand Up @@ -100,7 +118,8 @@ <h3>
<div *ngIf="labelsEditMode && !isToolPublic">
<div class="form-group">
<label>Tool Labels:</label>
<input id="toolLabels" type="text" class="input-sm form-control" name="toolLabels" [(ngModel)]="containerEditData.labels" #name="ngModel" maxlength="512" [pattern]="labelPattern" placeholder="e.g. dockstore, oicr-icgc, pancancer" />
<input id="toolLabels" type="text" class="input-sm form-control" name="toolLabels" [(ngModel)]="containerEditData.labels" #name="ngModel" maxlength="512"
[pattern]="labelPattern" placeholder="e.g. dockstore, oicr-icgc, pancancer" />
</div>
<div *ngIf="name.errors && (name.dirty || name.touched)" class="alert alert-danger">
<div [hidden]="!name.errors.maxlength">
Expand Down Expand Up @@ -133,7 +152,7 @@ <h3>
<input type="text" class="form-control" [(ngModel)]="dockerPullCmd" value="{{dockerPullCmd}}" readonly>
<span class="input-group-btn">
<button class="btn btn-default" [ngClass]="{'btn-copy':toolCopyBtn === 'docker_pull_command'}" type="button" ngxClipboard [cbContent]="dockerPullCmd"
(cbOnSuccess)="toolCopyBtnClick('docker_pull_command')">
(cbOnSuccess)="toolCopyBtnClick('docker_pull_command')">
<span class="glyphicon glyphicon-copy"></span>
</button>
</span>
Expand Down Expand Up @@ -197,7 +216,8 @@ <h3>Sharing</h3>
</div>
<div class="panel-body">
<div class="container-sharing">
<share-buttons class="withCount" [url]="shareURL" [whatsApp]="false" [stumbleUpOn]="false" [pinterest]="false" [tumblr]="false" [showCount]="true" (count)="sumCounts($event)">
<share-buttons class="withCount" [url]="shareURL" [whatsApp]="false" [stumbleUpOn]="false" [pinterest]="false" [tumblr]="false" [showCount]="true"
(count)="sumCounts($event)">
</share-buttons>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/app/container/container.component.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EmailService } from './email.service';
import { ExtendedDockstoreTool } from './../shared/models/ExtendedDockstoreTool';
/*
* Copyright 2017 OICR
Expand Down Expand Up @@ -50,6 +51,8 @@ export class ContainerComponent extends Entry {
privateOnlyRegistry: boolean;
containerEditData: any;
thisisValid = true;
public requestAccessHREF: string;
public contactAuthorHREF: string;
public missingWarning: boolean;
public tool: ExtendedDockstoreTool;
private toolSubscription: Subscription;
Expand All @@ -62,6 +65,7 @@ export class ContainerComponent extends Entry {
private refreshService: RefreshService,
private updateContainer: ContainerService,
private containersService: ContainersService,
private emailService: EmailService,
trackLoginService: TrackLoginService,
communicatorService: CommunicatorService,
providerService: ProviderService,
Expand Down Expand Up @@ -144,6 +148,8 @@ export class ContainerComponent extends Entry {
toolRef.buildMode = this.containerService.getBuildMode(toolRef.mode);
toolRef.buildModeTooltip = this.containerService.getBuildModeTooltip(toolRef.mode);
this.initTool();
this.contactAuthorHREF = this.emailService.composeContactAuthorEmail(this.tool);
this.requestAccessHREF = this.emailService.composeRequestAccessEmail(this.tool);
}
}

Expand Down
39 changes: 39 additions & 0 deletions src/app/container/email.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { DockstoreService } from './../shared/dockstore.service';
import { sampleTool1 } from '../test/mocked-objects';
import { DockstoreTool } from './../shared/swagger/model/dockstoreTool';
import { ExtendedDockstoreTool } from './../shared/models/ExtendedDockstoreTool';
/* tslint:disable:no-unused-variable */

import { TestBed, async, inject } from '@angular/core/testing';
import { EmailService } from './email.service';

describe('Service: Email', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [EmailService, DockstoreService]
});
});

const tool: ExtendedDockstoreTool = sampleTool1;
tool.tool_maintainer_email = 'fake@maintainer.email.ca';
tool.email = 'fake@email.ca';
tool.path = 'registry.hub.docker.com/postgres/postgres';
tool.registry = DockstoreTool.RegistryEnum.DOCKERHUB;
tool.imgProvider = 'Docker Hub';

it('should get the right request access email href', inject([EmailService], (service: EmailService) => {
expect(service).toBeTruthy();
expect(service.composeRequestAccessEmail(tool)).toEqual('mailto:fake@maintainer.email.ca' +
'?subject=Dockstore%20Request%20for%20Access%20to%20registry.hub.docker.com/postgres/postgres' +
'&body=I%20would%20like%20to%20request%20access%20to%20your%20Docker%20image%20registry.hub.docker.com/postgres/postgres.%20' +
'My%20user%20name%20on%20Docker%20Hub%20is%20%3Cusername%3E');
}));

it('should get the right contact author email href', inject([EmailService], (service: EmailService) => {
expect(service).toBeTruthy();
expect(service.composeContactAuthorEmail(tool)).toEqual('mailto:fake@email.ca' +
'?subject=Dockstore%20registry.hub.docker.com/postgres/postgres%20inquiry' +
'&body=');
}));

});
94 changes: 94 additions & 0 deletions src/app/container/email.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { ExtendedDockstoreTool } from './../shared/models/ExtendedDockstoreTool';
import { DockstoreService } from './../shared/dockstore.service';
import { Injectable } from '@angular/core';

@Injectable()
export class EmailService {

constructor(private dockstoreService: DockstoreService) { }
/**
* Compose the href for an email
* @param email The mailto address
* @param subject The subject of the email
* @param body The body of the the email
*/
private composeEmail(email: string, subject: string, body: string): string {
return `mailto:${email}?subject=${subject}&body=${body}`;
}

/**
* Composes the href for the Request Access email
* @param tool The tool to request access for
*/
public composeRequestAccessEmail(tool: ExtendedDockstoreTool): string {
const email = this.getRequestEmailMailTo(tool.tool_maintainer_email, tool.email);
const subject = this.getRequestEmailSubject(tool.path);
const body = this.getRequestEmailBody(tool.path, tool.imgProvider);
return this.composeEmail(email, subject, body);
}

/**
* Composes the href for the Contact Author email
* @param tool The tool to contact author for
*/
public composeContactAuthorEmail(tool: ExtendedDockstoreTool): string {
const email = this.getInquiryEmailMailTo(tool.email);
const subject = this.getInquiryEmailSubject(tool.path);
const body = this.getInquiryEmailBody();
return this.composeEmail(email, subject, body);
}

// Request Access button methods
/**
* This gets the mailto address when the Request Access button is clicked
* @param maintainerEmail The maintainer email
* @param email The tool author's email address
*/
private getRequestEmailMailTo(maintainerEmail: string, email: string): string {
return this.dockstoreService.getRequestAccessEmail(maintainerEmail, email);
}

/**
* This gets the email subject when the Request Access button is clicked
* @param path The path of the tool whose access is being requested
*/
private getRequestEmailSubject(path: string): string {
return encodeURI(`Dockstore Request for Access to ${path}`);
}

/**
* This gets the email body when the Request Access button is clicked
* @param path The path of the tool whose access is being requested
* @param toolRegistry The tool registry (Quay.io, GitLab, etc) of the tool whose access is being requested
*/
private getRequestEmailBody(path: string, toolRegistry: string): string {
return encodeURI(`I would like to request access to your Docker image ${path}. ` +
`My user name on ${toolRegistry} is <username>`);
}

// Contact Author button methods
/**
* This gets the mailto address when the Contact Author button is clicked. console.log(tool);
* This method is mostly redundant, but keeping it to mirror the Request Access button methods and in case modifications are needed
* @param email The tool author's email address
*/
private getInquiryEmailMailTo(email): string {
return email;
}

/**
* This gets the email subject when the Contact Author button is clicked
* @param path The path of the tool whose access is being requested
*/
private getInquiryEmailSubject(path: string): string {
return encodeURI(`Dockstore ${path} inquiry`);
}

/**
* This gets the email body when the Contact Author button is clicked
* This method is mostly redundant, but keeping it to mirror the Request Access button methods and in case modifications are needed
*/
private getInquiryEmailBody(): string {
return '';
}
}
8 changes: 8 additions & 0 deletions src/app/shared/dockstore.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,12 @@ export class DockstoreService {
return 'glyphicon-sort';
}
}

getRequestAccessEmail(tool_maintainer_email: string, email: string) {
if (tool_maintainer_email) {
return this.stripMailTo(tool_maintainer_email);
} else {
return this.stripMailTo(email);
}
}
}
1 change: 1 addition & 0 deletions src/app/shared/models/ExtendedDockstoreTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface ExtendedDockstoreTool extends DockstoreTool {
lastUpdatedDate?: string;
versionVerified?: any;
verifiedSources?: any;
imgProvider?: string;
imgProviderUrl?: string;
// The transformed git url
provider?: string;
Expand Down
2 changes: 2 additions & 0 deletions src/app/shared/modules/container.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EmailService } from '../../container/email.service';
/*
* Copyright 2017 OICR
*
Expand Down Expand Up @@ -107,6 +108,7 @@ import { SelectModule } from './select.module';
{provide: TooltipConfig, useFactory: getTooltipConfig},
HighlightJsService,
ErrorService,
EmailService,
DateService,
FileService,
ToolLaunchService,
Expand Down

0 comments on commit 30c985a

Please sign in to comment.