Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access request upgrade #2530

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table account_request_info modify column function varchar(255) default NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<i *ngIf="mode == 'confirm'" class="fas fa-question-circle"></i>
{{ title }}
</div>
<div class="body">
<div class="body" *ngIf="message">
<p [innerHTML]="message"></p>
<a *ngIf="link" [href]="link">{{link}}</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,31 @@ export class ConfirmDialogComponent {
this._message = value?.split(' ').map(w => w.startsWith('https://') ? '<a target="_blank" href="' + w + '">' + w + '</a>' : w).join(' ');
}

public openConfirm(title: string, message: string, buttons?: {yes: string, cancel: string}): Promise<boolean> {
public openConfirm(title: string, message?: string, buttons?: {yes: string, cancel: string}): Promise<boolean> {
this.title = title;
this.message = message;
this.buttons = buttons;
this.mode = 'confirm';
return this.closePromise;
}

public openChoose(title: string, message: string, buttons?: {yes: string, no: string, cancel: string}): Promise<'yes' | 'no' | false> {
public openChoose(title: string, message?: string, buttons?: {yes: string, no: string, cancel: string}): Promise<'yes' | 'no' | false> {
this.title = title;
this.message = message;
this.buttons = buttons;
this.mode = 'choose';
return this.closePromise;
}

public openInfo(title: string, message: string): Promise<boolean> {
public openInfo(title: string, message?: string, button?: string): Promise<boolean> {
this.title = title;
this.message = message;
this.buttons = {yes: button, no: null, cancel: null};
this.mode = 'info';
return this.closePromise;
}

public openError(title: string, message: string, link?: string): Promise<boolean> {
public openError(title: string, message?: string, link?: string): Promise<boolean> {
this.title = title;
this.message = message;
this.link = link;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ConfirmDialogService {
constructor() {
}

public confirm(title: string, message: string, buttons?: {yes: string, cancel: string}): Promise<boolean> {
public confirm(title: string, message?: string, buttons?: {yes: string, cancel: string}): Promise<boolean> {
const ref: ComponentRef<ConfirmDialogComponent> = ServiceLocator.rootViewContainerRef.createComponent(ConfirmDialogComponent);
let dialog: ConfirmDialogComponent = ref.instance;
return dialog.openConfirm(title, message, buttons).then(answer => {
Expand All @@ -31,7 +31,7 @@ export class ConfirmDialogService {
});
}

public choose(title: string, message: string, buttons?: {yes: string, no: string, cancel: string}): Promise<'yes' | 'no' | false> {
public choose(title: string, message?: string, buttons?: {yes: string, no: string, cancel: string}): Promise<'yes' | 'no' | false> {
const ref: ComponentRef<ConfirmDialogComponent> = ServiceLocator.rootViewContainerRef.createComponent(ConfirmDialogComponent);
let dialog: ConfirmDialogComponent = ref.instance;
return dialog.openChoose(title, message, buttons).then(answer => {
Expand All @@ -40,16 +40,16 @@ export class ConfirmDialogService {
});
}

public inform(title: string, message: string): Promise<boolean> {
public inform(title: string, message?: string, button?: string): Promise<boolean> {
const ref: ComponentRef<ConfirmDialogComponent> = ServiceLocator.rootViewContainerRef.createComponent(ConfirmDialogComponent);
let dialog: ConfirmDialogComponent = ref.instance;
return dialog.openInfo(title, message).then(answer => {
return dialog.openInfo(title, message, button).then(answer => {
ref.destroy();
return answer;
});
}

public error(title: string, message: string, link?: string): Promise<boolean> {
public error(title: string, message?: string, link?: string): Promise<boolean> {
const ref: ComponentRef<ConfirmDialogComponent> = ServiceLocator.rootViewContainerRef.createComponent(ConfirmDialogComponent);
let dialog: ConfirmDialogComponent = ref.instance;
return dialog.openError(title, message, link).then(answer => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export abstract class EntityComponent<T extends Entity> implements OnDestroy, On
protected confirmDialogService: ConfirmDialogService;
private entityRoutes: EntityRoutes;
protected router: Router;
private location: Location;
protected location: Location;
protected formBuilder: UntypedFormBuilder;
public keycloakService: KeycloakService;
protected consoleService: ConsoleService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class KeycloakService {

static init(): Promise<any> {

if (window.location.href.endsWith('/account-request')) {
if (window.location.href.includes('/account-request')) {
return Promise.resolve();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ fieldset + fieldset { margin-top: 30px; }
.fix-icon i { margin-left: 4px; }
.user-icon i { color: var(--color-a-light); }
.close { position: absolute; display: inline-block; right: 0; top: 0; color: var(--color-a); cursor: pointer; padding: 2px 6px; }
.invite-button { margin-left: 20px; height: auto; }
.invite-button { height: auto; }
.info-txt { margin-top: 5px; padding: 1px 16px 10px; background-color: var(--color-b-light); border-radius: 2px; }
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@
-->

<ol>
<li *ngIf="mode == 'edit' && !studyOptions" class="info-txt">
<h3>Invite a new user</h3>
Username or Email address : <input type="text" [(ngModel)]="invitationMail" placeholder="email address / username">
<tool-tip>If an user with such email/username already exists, he will be directly added to the study, otherwise an email with an invitation will be sent.</tool-tip>
<br/>Function in the study (researcher, mri manipulator, ...) : <input type="text" [(ngModel)]="invitationRole" placeholder="function in the study">
<br/><button type="button" class="invite-button right-icon" (click)="inviteUser()">Invite & Add<i class="fa-solid fa-plus"></i></button>
</li>
<li *ngIf="mode != 'view' && studyOptions">
<label>List of studies</label>
<span class="right-col">
<select-box placeholder="Add a study ..." (onAddClick)="onStudyAdd($event)" [options]="studyOptions">
</select-box>
</span>
</li>
<li *ngIf="mode == 'edit' && !studyOptions">
<span>Invite a new user : </span>
<input type="text" [(ngModel)]="invitationMail" placeholder="email address / username">
<button type="button" class="invite-button right-icon" (click)="inviteUser()">Invite & Add<i class="fa-solid fa-plus"></i></button>
<tool-tip>If an user with such email/username already exists, he will be directly added to the study, otherwise an email with an invitation will be sent.</tool-tip>
</li>
<li>
<shanoir-table #memberTable
[getPage]="getPage.bind(this)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class StudyUserListComponent implements ControlValueAccessor, OnChanges {
StudyUserRight = StudyUserRight;
isAdmin: boolean;
invitationMail: string;
invitationRole: string;

private onTouchedCallback = () => {};
private onChangeCallback = (_: any) => {};
Expand Down Expand Up @@ -265,8 +266,8 @@ export class StudyUserListComponent implements ControlValueAccessor, OnChanges {
}

public inviteUser() {
let stud = new IdName(this.study.id, this.study.name);
this.accessRequestService.inviteUser(this.invitationMail, stud).then(request => {
let study = new IdName(this.study.id, this.study.name);
this.accessRequestService.inviteUser(this.invitationMail, this.invitationRole, study).then(request => {
if (!request) {
this.consoleService.log('info', "No user found with such email, an invitation was sent.");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { EntityService } from 'src/app/shared/components/entity/entity.abstract.
import { ActivatedRoute } from '@angular/router';
import { AccessRequestService } from './access-request.service';
import { IdName } from 'src/app/shared/models/id-name.model';
import { Study } from 'src/app/studies/shared/study.model';

@Component({
selector: 'access-request',
Expand Down Expand Up @@ -63,6 +64,7 @@ export class AccessRequestComponent extends EntityComponent<AccessRequest> {
if (this.activatedRoute.snapshot.params['id']) {
this.accessRequest.studyId = this.activatedRoute.snapshot.params['id'];
this.fromStudy = true;
this.checkAccess(this.accessRequest.studyId);
return Promise.resolve();
}
return this.studyService.getPublicStudiesConnected().then(result => {
Expand All @@ -78,6 +80,24 @@ export class AccessRequestComponent extends EntityComponent<AccessRequest> {
});
}

checkAccess(studyId: number) {
this.studyService.getStudiesNames().then(studies => {
if (studies.find(s => s.id == studyId)) {
this.confirmDialogService.inform('You already have access to this study', 'No need to request an access.', 'Go to the study').then(() => {
this.router.navigate(['study/details', studyId]);
});
} else {
this.userService.getAccessRequests().then(accessRequests => {
if (accessRequests.find(ar => ar.studyId == studyId)) {
this.confirmDialogService.inform('Access request pending', 'You already have asked an access request for this study, wait for the administrator to confirm your access.').then(() => {
this.router.navigate(['study/list']);
});
}
});
}
});
}

buildForm(): UntypedFormGroup {
return this.formBuilder.group({
'motivation': [this.accessRequest.motivation, []],
Expand Down Expand Up @@ -129,6 +149,6 @@ export class AccessRequestComponent extends EntityComponent<AccessRequest> {
}

protected chooseRouteAfterSave() {
this.goBack();
this.router.navigate(['study/list']);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
*/
import { HttpClient } from '@angular/common/http';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { Subscription } from 'rxjs';
import { IdName } from 'src/app/shared/models/id-name.model';

import { KeycloakService } from 'src/app/shared/keycloak/keycloak.service';
import { EntityService } from '../../shared/components/entity/entity.abstract.service';
import * as AppUtils from '../../utils/app.utils';
import { UserService } from '../shared/user.service';
import { AccessRequest } from './access-request.model';

@Injectable()
Expand All @@ -36,11 +36,13 @@ export class AccessRequestService extends EntityService<AccessRequest> implement
super(http);
}

public inviteUser(mail: string, study: IdName): Promise<AccessRequest> {
public inviteUser(mail: string, role: string, study: IdName): Promise<AccessRequest> {
const formData: FormData = new FormData();
formData.set("email", mail);
formData.set("studyId", "" + study.id);
formData.set("studyName", study.name);
formData.set("issuer", KeycloakService.auth.authz.tokenParsed.name);
formData.set("role", role);
return this.http.put(this.API_URL + "/invitation/", formData).toPromise()
.then(response =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@
-->

<fieldset *ngIf="info && form" [formGroup]="form">

<ol>
<li *ngIf="presetStudyId">
<span>You have been invited to join a study in Shanoir, you have to create an account before accessing the data.</span>
</li>
<li *ngIf="!presetStudyId">
<li *ngIf="!presetStudyId">
<label *ngIf="editMode" i18n="Edit user|Study label@@editUserStudy" [class.required-label]="editMode">List of available studies</label>
<span class="right-col">
<ng-container *ngIf="editMode">
Expand All @@ -36,13 +32,13 @@
<span *ngIf="!editMode">{{info.studyName}}</span>
</span>
</li>
<li *ngIf="presetStudyId">
<li *ngIf="presetStudyId" class="hidden">
<input type = "hidden"
[(ngModel)]="info.studyId"
formControlName="studyId">
[(ngModel)]="info.studyId"
formControlName="studyId">
<input type = "hidden"
[(ngModel)]="info.studyName"
formControlName="studyName">
[(ngModel)]="info.studyName"
formControlName="studyName">
</li>
<li>
<label i18n="Edit user|Institution label@@editUserInstitution" [class.required-label]="editMode">Institution / Employer</label>
Expand All @@ -56,24 +52,14 @@
</span>
</li>
<li>
<label i18n="Edit user|Function label@@editUserFunction" [class.required-label]="editMode">Expertise / Role in the study</label>
<label i18n="Edit user|Function label@@editUserFunction" [class.required-label]="editMode">Role in the study</label>
<span class="right-col">
<ng-container *ngIf="editMode">
<input type="text" formControlName="function" [(ngModel)]="info.function" (change)="onInfoChange()"/>
<label *ngIf="hasError('function', ['required'])" class="form-validation-alert" i18n="Edit user|Function required error@@editUserFunctionRequiredError">Function is required!</label>
<label *ngIf="hasError('function', ['length'])" class="form-validation-alert" i18n="Edit user|Function length error@@editUserFunctionLengthError">Function length must be less than 200!</label>
</ng-container>
<span *ngIf="!editMode">{{info.function}}</span>
</span>
</li>
<li>
<label i18n="Edit user|Contact label@@editUserContact">Shanoir study manager</label>
<label i18n="Edit user|Contact label@@editUserContact">Invitation issuer</label>
<span class="right-col">
<ng-container *ngIf="editMode">
<input type="text" formControlName="contact" [(ngModel)]="info.contact" (change)="onInfoChange()"/>
<label *ngIf="hasError('contact', ['required'])" class="form-validation-alert" i18n="Edit user|Contact required error@@editUserContactRequiredError">Contact is required!</label>
<label *ngIf="hasError('contact', ['length'])" class="form-validation-alert" i18n="Edit user|Contact length error@@editUserContactLengthError">Contact length must be less than 200!</label>
</ng-container>
<span *ngIf="!editMode">{{info.contact}}</span>
</span>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ export class AccountRequestInfoComponent implements ControlValueAccessor, OnInit
}
this.form = this.formBuilder.group({
'institution': [this.info.institution, [Validators.required, Validators.maxLength(200)]],
'function': [this.info.function, [Validators.required, Validators.maxLength(200)]],
'contact': [this.info.contact, [Validators.maxLength(200)]],
// 'function': [this.info.function, [Validators.required, Validators.maxLength(200)]],
// 'contact': [this.info.contact, [Validators.maxLength(200)]],
'studyId': [this.info.studyId, [Validators.required]],
'studyName': [this.info.studyName]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
.language span { margin: 0 20px 0 0; color: var(--dark-grey); text-decoration: underline; cursor: pointer; }
.language span.selected { color: var(--color-a); font-weight: bold; }
.console { display: none; }
.subtitle { margin: 30px 0 40px; font-size: 16px; }
.subtitle span { font-weight: bold; color: var(--color-a); }
.main-fieldset { margin-bottom: -30px; }
Loading
Loading