Commit 7f5d7026 authored by Moises Sacal's avatar Moises Sacal
Browse files

update to create notebooks and link to stash

parent d085053a
This diff is collapsed.
......@@ -5,7 +5,8 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"build": "ng build",
"build:prod": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
......
import {Input, Output, Component, OnInit, Inject, Injector, EventEmitter} from '@angular/core';
import {SimpleComponent} from '../shared/form/field-simple.component';
import {FieldBase} from '../shared/form/field-base';
import {FormGroup, FormControl, Validators} from '@angular/forms';
import * as _ from "lodash-es";
import {Checks} from './helpers';
import {LabarchivesService} from '../labarchives.service';
// STEST-22
declare var jQuery: any;
/**
* Contributor Model
*
* @author <a target='_' href='https://github.com/moisbo'>moisbo</a>
*
*/
export class LabarchivesCreateField extends FieldBase<any> {
createNotebookHelp: string;
createNotebookHelp2: string;
createNotebookLabel: string;
notebookLabel: string;
supervisorLabel: string;
creatingLabel: string;
linkingLabel: string;
closeLabel: string;
processing: boolean = false;
workspaceDetailsTitle: string;
workspaceDefinition: string;
currentWorkspace: any;
processingLabel: string;
processingMessage: string;
processingStart: boolean = true;
processingSuccess: boolean;
processingFinished: boolean = false;
processingFail: string;
processingStatus: string;
processingNoPermission: string;
supervisorFailMessage: string;
checks: Checks;
rdmp: string;
userEmail: string;
notebookName: string;
supervisorEmail: string;
errorMessages: Array<string> = [];
@Input() LinkItem: EventEmitter<any> = new EventEmitter<any>();
@Output() link: EventEmitter<any> = new EventEmitter<any>();
labarchivesService: LabarchivesService;
constructor(options: any, injector: any) {
super(options, injector);
this.labarchivesService = this.getFromInjector(LabarchivesService);
this.closeLabel = 'Close';
this.processing = false;
this.workspaceDetailsTitle = 'Workspace';
this.workspaceDefinition = '';
this.currentWorkspace = {};
this.createNotebookHelp = options['createNotebookHelp'] || '';
this.createNotebookHelp2 = options['createNotebookHelp2'] || '';
this.createNotebookLabel = options['createNotebookLabel'] || '';
this.notebookLabel = options['notebookLabel'] || '';
this.supervisorLabel = options['supervisorLabel'] || '';
this.creatingLabel = options['creatingLabel'] || '';
this.linkingLabel = options['linkingLabel'] || '';
this.supervisorFailMessage = options['supervisorFailMessage'] || 'Supervisor has not logged in to LabArchives';
this.processingSuccess = options['processingSuccess'] || 'Success';
this.processingFail = options['processingFail'] || 'There was a problem linking your workspace, please try again later';
this.processingStatus = '';
this.processingNoPermission = options['processingNoPermission'] || 'You are not allowed to modify this item'
this.processingLabel = options['processingLabel'] || 'Processing...';
this.processingMessage = '';
this.checks = new Checks();
}
init() {
this.rdmp = this.fieldMap._rootComp.rdmp;
}
registerEvents() {
this.fieldMap['List'].field['create'].subscribe(this.createModal.bind(this));
}
createFormModel(valueElem: any = undefined): any {
if (valueElem) {
this.value = valueElem;
}
this.formModel = new FormControl(this.value || []);
if (this.value) {
this.setValue(this.value);
}
return this.formModel;
}
setValue(value: any) {
this.formModel.patchValue(value, {emitEvent: false});
this.formModel.markAsTouched();
}
setEmptyValue() {
this.value = [];
return this.value;
}
async createModal() {
const rdmpInfo = await this.labarchivesService.rdmpInfo(this.rdmp);
const userInfo = await this.labarchivesService.getUserInfo();
const user = userInfo['user'];
this.userEmail = user['email'];
const recordMetadata = rdmpInfo['recordMetadata'];
if (recordMetadata['contributor_ci'] && recordMetadata['contributor_ci']['email']) {
this.supervisorEmail = recordMetadata['contributor_ci']['email'];
}
jQuery('#createModal').modal('show');
}
async createNotebook() {
this.processing = false;
if (this.validate()) {
this.processing = true;
this.processingStart = true;
try {
this.processingStatus = 'Creating Notebook...';
const createNotebook = await this.labarchivesService.createNotebook(this.rdmp, this.notebookName, this.supervisorEmail, this.userEmail);
console.log(createNotebook);
this.processingStart = false;
this.processingFinished = true;
this.processingStatus = 'Your notebook has been created';
jQuery('#createModal').modal('hide');
this.link.emit({name: createNotebook.name, id: createNotebook.nb});
} catch (e) {
this.processingStatus = 'There was an error creating your notebook';
}
} else {
this.processingFail = '';
}
}
validate() {
this.errorMessages = [];
if (this.notebookName) {
//other validations
} else {
this.errorMessages.push('verify Notebook Name');
}
if (this.supervisorEmail) {
//other validations
} else {
this.errorMessages.push('supervisor Email is blank');
}
if (this.errorMessages.length > 0) {
return false;
} else {
return true;
}
}
}
/**
* Component that Links Workspaces to Workspace Records in Stash
*/
@Component({
selector: 'ws-labarchivescreate',
template: `
<div id="createModal" class="modal fade" data-keyboard="false">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Create Workspace</h4>
</div>
<div class="modal-body">
<div *ngIf="field.processingStart">
<h5>{{ field.createNotebookHelp }}</h5>
<p>{{ field.createNotebookHelp2 }}</p>
<div class="form-group">
<label>{{ field.notebookLabel }}</label>
<input type="text" class="form-control" [(ngModel)]="field.notebookName" name="notebookName" ngModel
attr.aria-label="{{ field.notebookName }}">
</div>
<div class="form-group">
<label>{{ field.supervisorLabel }}</label>
<input type="text" class="form-control" [(ngModel)]="field.supervisorEmail" name="supervisorLabel"
ngModel
attr.aria-label="{{ field.supervisorEmail }}" disabled="true">
</div>
<div class="form-group">
<button *ngIf="waitForProcessing" type="button" class="form-control btn btn-block btn-primary"
(click)="field.createNotebook()"
attr.aria-label="{{ field.createNotebookLabel }}">{{ field.createNotebookLabel }}</button>
</div>
<div class="form-group">
<div>{{ field.processingStatus }}</div>
</div>
<div class="form-group">
<div class="alert-danger">
<ul class="list-group">
<li class="list-group-item" *ngFor="let msg of field.errorMessages">{{msg}}</li>
</ul>
</div>
</div>
</div>
<div *ngIf="field.processingFinished"></div>
</div>
<div class="modal-footer">
<span *ngIf="field.processing; then waitForProcessing; else finishProcessing"></span>
<ng-template #finishProcessing>
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ field.closeLabel }}</button>
</ng-template>
<ng-template #waitForProcessing>
<button type="button" class="btn btn-secondary disabled" data-dismiss="modal">{{ field.closeLabel }}
</button>
</ng-template>
</div>
</div>
</div>
</div>
`
})
export class LabarchivesCreateComponent extends SimpleComponent {
field: LabarchivesCreateField;
ngOnInit() {
this.field.init();
this.field.registerEvents();
}
}
......@@ -60,6 +60,7 @@ export class LabarchivesLinkField extends FieldBase<any> {
registerEvents() {
this.fieldMap['List'].field['link'].subscribe(this.linkItem.bind(this));
this.fieldMap['Create'].field['link'].subscribe(this.linkItem.bind(this));
}
createFormModel(valueElem: any = undefined): any {
......
......@@ -23,10 +23,12 @@ export class LabarchivesListField extends FieldBase<any> {
linkLabel: string;
linkProblem: string;
defaultNotebookLabel: string;
createNotebookLabel: string;
@Input() user: any;
@Output() link: EventEmitter<any> = new EventEmitter<any>();
@Output() checkLoggedIn: EventEmitter<any> = new EventEmitter<any>();
@Output() create: EventEmitter<any> = new EventEmitter<any>();
labarchivesService: LabarchivesService;
......@@ -44,6 +46,7 @@ export class LabarchivesListField extends FieldBase<any> {
this.linkLabel = options['linkLabel'] || 'Link Workspace';
this.linkProblem = options['linkProblem'] || 'There was a problem checking the link';
this.defaultNotebookLabel = options['defaultNotebookLabel'] || 'Default Notebook';
this.createNotebookLabel = options['createNotebookLabel'] || 'Create Notebook';
}
registerEvents() {
......@@ -89,6 +92,10 @@ export class LabarchivesListField extends FieldBase<any> {
this.link.emit(item);
}
createWorkspace() {
this.create.emit();
}
checkLinks() {
this.workspaces.reduce((promise, w, index) => {
return promise.then(() => {
......@@ -178,6 +185,10 @@ export class LabarchivesListField extends FieldBase<any> {
you do not have access to</p>
</div>
</div>
<div>
<button class="btn btn-primary" type="button" (click)="field.createWorkspace()">{{field.createNotebookLabel}}</button>
</div>
<div class="row">&nbsp;</div>
</div>
</div>
`
......
......@@ -11,6 +11,7 @@ import {TranslationService} from './shared/translation-service';
import {LabarchivesLoginComponent, LabarchivesLoginField} from './components/labarchives-login.component';
import {LabarchivesListComponent, LabarchivesListField} from './components/labarchives-list.component';
import {LabarchivesLinkField, LabarchivesLinkComponent} from './components/labarchives-link.component';
import {LabarchivesCreateField, LabarchivesCreateComponent} from './components/labarchives-create.component';
import * as jQuery from 'jquery';
......@@ -135,7 +136,8 @@ export class LabarchivesFormComponent extends LoadableComponent {
this.fcs.addComponentClasses({
'LabarchivesLoginField': {'meta': LabarchivesLoginField, 'comp': LabarchivesLoginComponent},
'LabarchivesListField': {'meta': LabarchivesListField, 'comp': LabarchivesListComponent},
'LabarchivesLinkField': {'meta': LabarchivesLinkField, 'comp': LabarchivesLinkComponent}
'LabarchivesLinkField': {'meta': LabarchivesLinkField, 'comp': LabarchivesLinkComponent},
'LabarchivesCreateField': {'meta': LabarchivesCreateField, 'comp': LabarchivesCreateComponent}
});
this.RecordsService.getForm(this.oid, this.recordType, this.editMode).then((obs: any) => {
......
......@@ -9,13 +9,14 @@ import {LabarchivesFormComponent} from './labarchives-form.component';
import {LabarchivesLoginComponent} from './components/labarchives-login.component';
import {LabarchivesListComponent} from './components/labarchives-list.component';
import {LabarchivesLinkComponent} from "./components/labarchives-link.component";
import {LabarchivesCreateComponent} from "./components/labarchives-create.component";
@NgModule({
imports: [
BrowserModule, ReactiveFormsModule, FormsModule, SharedModule
],
declarations: [
LabarchivesFormComponent, LabarchivesLoginComponent, LabarchivesListComponent, LabarchivesLinkComponent
LabarchivesFormComponent, LabarchivesLoginComponent, LabarchivesListComponent, LabarchivesLinkComponent, LabarchivesCreateComponent
],
exports: [],
providers: [
......@@ -25,7 +26,7 @@ import {LabarchivesLinkComponent} from "./components/labarchives-link.component"
LabarchivesFormComponent
],
entryComponents: [
LabarchivesFormComponent, LabarchivesListComponent, LabarchivesLoginComponent, LabarchivesLinkComponent
LabarchivesFormComponent, LabarchivesListComponent, LabarchivesLoginComponent, LabarchivesLinkComponent, LabarchivesCreateComponent
]
})
export class LabarchivesModule {
......
......@@ -115,4 +115,32 @@ export class LabarchivesService extends BaseService {
}
}
public async createNotebook(rdmp: string, nbName: string, supervisorEmail: string, userEmail: string) {
const wsUrl = this.brandingAndPortalUrl + '/ws/labarchives/create';
try {
const result = await this.http.post(
wsUrl,
{name: nbName, supervisor: supervisorEmail, rdmp: rdmp, userEmail: userEmail},
this.options
).toPromise();
return Promise.resolve((this.extractData(result)));
} catch (e) {
return Promise.reject(new Error(e));
}
}
public async rdmpInfo(rdmp: string) {
const wsUrl = this.brandingAndPortalUrl + '/ws/labarchives/rdmp';
try {
const result = await this.http.post(
wsUrl,
{rdmp: rdmp},
this.options
).toPromise();
return Promise.resolve((this.extractData(result)));
} catch (e) {
return Promise.reject(new Error(e));
}
}
}
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const rxjs_1 = require("rxjs");
require("rxjs/add/operator/map");
......@@ -12,10 +20,12 @@ var Controllers;
super();
this._exportedMethods = [
'info',
'rdmpInfo',
'login',
'link',
'checkLink',
'list'
'list',
'createNotebook'
];
this.config = new Config_1.Config(sails.config.workspaces);
}
......@@ -23,6 +33,23 @@ var Controllers;
this.config.brandingAndPortalUrl = BrandingService.getFullPath(req);
this.ajaxOk(req, res, null, { location: this.config.location, status: true });
}
rdmpInfo(req, res) {
sails.log.debug('rdmpInfo');
const userId = req.user.id;
const rdmp = req.param('rdmp');
let recordMetadata = {};
this.config.brandingAndPortalUrl = BrandingService.getFullPath(req);
return WorkspaceService.getRecordMeta(this.config, rdmp)
.subscribe(response => {
sails.log.debug('recordMetadata');
recordMetadata = response;
this.ajaxOk(req, res, null, { status: true, recordMetadata: recordMetadata });
}, error => {
sails.log.error('recordMetadata: error');
sails.log.error(error);
this.ajaxFail(req, res, error.message, { status: false, message: error.message });
});
}
login(req, res) {
const user = {
username: req.param('username'),
......@@ -148,11 +175,11 @@ var Controllers;
const tree = response['tree-tools'];
const node = tree['node'];
metadataContent = `
<div id="${workspace.oid}">
<h1>UTS</h1>
<h3>Workspace <strong>${nbName}</strong> is linked to:</h3>
<h2>Research Data Management Plan <a href="${this.config.brandingAndPortalUrl}/record/view/${rdmp}">${rdmpTitle}</a></h2>
<p>Stash Id: ${workspace.oid}</p>
<div id="${workspace.oid}">
<h1>UTS</h1>
<h3>Workspace <strong>${nbName}</strong> is linked to:</h3>
<h2>Research Data Management Plan <a href="${this.config.brandingAndPortalUrl}/record/view/${rdmp}">${rdmpTitle}</a></h2>
<p>Stash Id: ${workspace.oid}</p>
</div>
`;
const partType = 'text entry';
......@@ -215,6 +242,74 @@ var Controllers;
this.ajaxFail(req, res, error.message, { status: false, message: error.message });
});
}
createNotebook(req, res) {
const userId = req.user.id;
const name = req.param('name');
const userEmail = req.param('userEmail');
let supervisor = req.param('supervisor');
const rdmp = req.param('rdmp');
let recordMetadata = {};
let rdmpTitle = '';
let info = {};
let nb;
this.config.brandingAndPortalUrl = BrandingService.getFullPath(req);
return WorkspaceService.getRecordMeta(this.config, rdmp)
.flatMap(response => {
sails.log.debug('recordMetadata');
recordMetadata = response;
rdmpTitle = recordMetadata['title'];
const supervisorFromRDMP = recordMetadata['contributor_ci']['email'];
if (supervisor === supervisorFromRDMP) {
return WorkspaceService.workspaceAppFromUserId(userId, this.config.appName);
}
else {
rxjs_1.Observable.throwError(new Error('Supervisor email does not match workspace'));
}
sails.log.debug(recordMetadata);
})
.flatMap((response) => __awaiter(this, void 0, void 0, function* () {
sails.log.debug('workspaceAppFromUserId');
info = response.info;
sails.log.debug('userHasEmail');
const supervisorHasEmail = yield LabarchivesService.userHasEmail(this.config.key, supervisor);
if (supervisorHasEmail && supervisorHasEmail['users'] && supervisorHasEmail['users']['account-for-email']['_']) {
sails.log.debug('createNotebook');
const result = yield LabarchivesService.createNotebook(this.config.key, info['id'], name);
if (result && result.notebooks) {
nb = result.notebooks;
if (userEmail.toLowerCase() === supervisor.toLowerCase()) {
return rxjs_1.Observable.of(nb);
}
else {
const addUser = yield LabarchivesService.addUserToNotebook(this.config.key, info['id'], nb['nbid'], supervisor, 'OWNER');
sails.log.debug('addUser');
if (addUser) {
const nbu = addUser.notebooks['notebook-user'];
sails.log.debug(nbu);
return rxjs_1.Observable.of(nb);
}
else {
rxjs_1.Observable.throwError(new Error('Cannot add user to notebook'));
}
}
}
else {
rxjs_1.Observable.throwError(new Error('Notebook not created'));
}
}
else {
rxjs_1.Observable.throwError(new Error('Supervisor not on LabArchives'));
}
}))
.subscribe(response => {
sails.log.debug('create notebook');
this.ajaxOk(req, res, null, { status: true, nb: nb['nbid'], name: name, message: 'createNotebook' });
}, error => {
sails.log.error('createNotebook: error');
sails.log.error(error);
this.ajaxFail(req, res, error.message, { status: false, message: error.message });
});
}
}
Controllers.LabarchivesController = LabarchivesController;
})(Controllers = exports.Controllers || (exports.Controllers = {}));
......
......@@ -22,7 +22,10 @@ var Services;
'insertNode',
'addEntry',
'getNotebookInfo',
'getNotebookTree'
'getNotebookTree',
'createNotebook',
'addUserToNotebook',
'userHasEmail'
];
this.config = new Config_1.Config(sails.config.workspaces);
}
......@@ -116,6 +119,51 @@ var Services;
}
});
}
createNotebook(key, userId, name) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (key && key['akid'] && key['password']) {
return yield la.createNotebook(key, userId, name);
}
else {
return Promise.reject(new Error('missing keys for accessing lab archives APIs'));
}
}
catch (e) {
return Promise.reject(new Error(e));
}
});
}
addUserToNotebook(key, uid, nbid, email, userRole) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (key && key['akid'] && key['password']) {
return yield la.addUserToNotebook(key, uid, nbid, email, userRole);
}
else {
return Promise.reject(new Error('missing keys for accessing lab archives APIs'));
}
}
catch (e) {
return Promise.reject(new Error(e));
}
});
}
userHasEmail(key, email) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (key && key['akid'] && key['password']) {
return yield la.emailHasAccount(key, email);