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

update to create notebooks and link to stash

parent d085053a
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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);