Skip to content
Snippets Groups Projects
Commit 2c6b0c58 authored by Alex ORLUC's avatar Alex ORLUC
Browse files

FEAT #16982 TIME 3 WIP otp user creation

parent aa4e3451
No related branches found
No related tags found
No related merge requests found
Showing
with 99 additions and 28 deletions
......@@ -476,9 +476,13 @@
"receiveActivationNotification": "Recevoir le courriel d'activation",
"newOtp": "Ajouter un OTP",
"otpUser": "Utilisateur OTP",
"notifyUserBy": "Notifier l'utilisateur par",
"securityCodeSendMode": "Mode d'envoi du code de sécurité",
"phoneAlt": "Mobile",
"sms": "Sms",
"source": "Source"
"source": "Source",
"otp_visa_yousignUser": "viseur (yousign)",
"otp_sign_yousignUser": "signataire (yousign)",
"role": "Role",
"otpMsg": "L'utilisateur sera notifié par <b>mail</b> et recevra un <b>code de sécurité</b> par <b>{{security}}</b> au moment de son tour dans le circuit."
}
}
......@@ -9,6 +9,11 @@
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card>
<ion-item color="primary">
<ion-label class="info" [innerHTML]="'lang.otpMsg' | translate : { security : appOtpYousign?.getSecurityMode()}"></ion-label>
</ion-item>
</ion-card>
<ion-card>
<ion-item>
<ion-label color="secondary">{{'lang.source' | translate}}</ion-label>
......
.my-custom-class {
--min-width: 400px;
}
\ No newline at end of file
}
.info {
white-space: initial;
line-height: 24px;
}
\ No newline at end of file
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { catchError, tap } from 'rxjs/operators';
import { of } from 'rxjs';
import { NotificationService } from '../../../service/notification.service';
@Injectable({
providedIn: 'root'
})
export class OtpService {
constructor(
public http: HttpClient,
public notificationService: NotificationService,
) { }
getUserOtpIcon(id: string) {
return new Promise((resolve) => {
this.http.get(`assets/${id}.png`, { responseType: 'blob' }).pipe(
tap((response: any) => {
const reader = new FileReader();
reader.readAsDataURL(response);
reader.onloadend = () => {
resolve(reader.result as any);
};
}),
catchError(err => {
this.notificationService.handleErrors(err);
return of(false);
})
).subscribe();
});
}
}
......@@ -14,26 +14,25 @@
<ion-label color="secondary" position="floating">{{'lang.phoneAlt' | translate}} <ng-container
*ngIf="otp.mode === 'sms'">*</ng-container>
</ion-label>
<ion-input name="phone" pattern="^\+?[1-9]\d{1,14}$" [(ngModel)]="otp.phone" placeholder="+33646342143"
<ion-input name="phone" pattern="^\+?[1-9]\d{1,14}$" [(ngModel)]="otp.phone" placeholder="+33646342143" (keyup)="formatPhone($event)"
[required]="otp.mode === 'sms'"></ion-input>
</ion-item>
<ion-item>
<ion-label color="secondary" position="floating">{{'lang.email' | translate}} <ng-container
*ngIf="otp.mode === 'email'">*</ng-container>
<ion-label color="secondary" position="floating">{{'lang.email' | translate}} *
</ion-label>
<ion-input name="email" pattern="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
placeholder="alain.dupont@gmail.com" [(ngModel)]="otp.email" [required]="otp.mode === 'email'">
placeholder="alain.dupont@gmail.com" [(ngModel)]="otp.email" required>
</ion-input>
</ion-item>
</ion-list>
<ion-list>
<ion-radio-group [(ngModel)]="otp.role" [value]="otp.role">
<ion-radio-group name="role" [(ngModel)]="otp.role" [value]="otp.role">
<ion-list-header>
<ion-label color="secondary">{{'lang.role' | translate}}</ion-label>
<ion-label color="secondary">{{'lang.role' | translate}} *</ion-label>
</ion-list-header>
<div style="display:flex;">
<ion-item *ngFor="let role of roles" style="flex:1;">
<ion-label>{{'lang.' + role | translate}}</ion-label>
<ion-label>{{'lang.' + role + 'User' | translate}}</ion-label>
<ion-radio slot="start" [value]="role"></ion-radio>
</ion-item>
</div>
......@@ -46,11 +45,11 @@
</ion-list>
<ion-list>
<ion-item>
<ion-label color="secondary" position="floating">{{'lang.notifyUserBy' | translate}}</ion-label>
<ion-select name="mode" [(ngModel)]="otp.notify" [value]="otp.notify"
cancelText="{{'lang.cancel' | translate}}" [disabled]="notificationModes.length === 1">
<ion-select-option *ngFor="let mode of notificationModes" [value]="mode">
{{'lang.' + mode | translate}}</ion-select-option>
<ion-label color="secondary" position="floating">{{'lang.securityCodeSendMode' | translate}} *</ion-label>
<ion-select name="mode" [(ngModel)]="otp.security" [value]="otp.security"
cancelText="{{'lang.cancel' | translate}}" [disabled]="securityModes.length === 1">
<ion-select-option *ngFor="let security of securityModes" [value]="security">
{{'lang.' + security | translate}}</ion-select-option>
</ion-select>
</ion-item>
</ion-list>
......
......@@ -12,7 +12,7 @@ import { NgForm } from '@angular/forms';
export class OtpYousignComponent implements OnInit {
@ViewChild('otpForm', { static: false }) otpForm: NgForm;
notificationModes: any[] = [];
securityModes: any[] = [];
roles: any[] = [
'otp_visa_yousign',
......@@ -20,11 +20,12 @@ export class OtpYousignComponent implements OnInit {
];
otp: any = {
type: 'yousign',
firstname: '',
lastname: '',
email: '',
phone: '',
notify: 'sms',
security: 'sms',
role: 'otp_sign_yousign'
};
......@@ -40,11 +41,11 @@ export class OtpYousignComponent implements OnInit {
getConfig() {
// FOR TEST
this.notificationModes = [
this.securityModes = [
'sms',
'email'
];
this.otp.mode = this.notificationModes[0];
this.otp.security = this.securityModes[0];
/* this.http.get(`../rest/???`).pipe(
tap((data: any) => {
......@@ -60,7 +61,17 @@ export class OtpYousignComponent implements OnInit {
return this.otp;
}
getSecurityMode() {
return this.translate.instant('lang.' + this.otp.security);
}
isValid() {
return this.otpForm.valid;
}
formatPhone(ev: any) {
if (this.otp.phone.length > 1 && this.otp.phone[0] === '0') {
this.otp.phone = this.otp.phone.replace('0', '+33');
}
}
}
......@@ -14,22 +14,21 @@
<ion-searchbar #searchInput [(ngModel)]="visaUsersSearchVal" [placeholder]="'lang.searchUser' | translate"
(ionChange)="getVisaUsers($event)" (ionFocus)="visaUsersSearchVal=''"></ion-searchbar>
<ion-buttons slot="end">
<ion-button fill="clear" slot="icon-only" shape="round" color="primary" [matMenuTriggerFor]="menu"
[title]="'lang.circuitModels' | translate">
<ion-icon slot="icon-only" name="albums-outline"></ion-icon>
<ion-button fill="clear" slot="icon-only" shape="round" color="primary" [matMenuTriggerFor]="menu">
<ion-icon slot="icon-only" name="ellipsis-vertical-outline"></ion-icon>
</ion-button>
</ion-buttons>
<mat-menu #menu="matMenu">
<ion-item button (click)="openOtpModal()" lines="none">
<ion-icon name="person-circle-outline" slot="start" color="primary"></ion-icon>
<ion-label>{{'lang.newOtp' | translate}}</ion-label>
<ion-label style="font-size: 14px;">{{'lang.newOtp' | translate}}</ion-label>
</ion-item>
<button mat-menu-item [matMenuTriggerFor]="model"
(menuOpened)="getVisaUserModels()">{{'lang.circuitModels' | translate}}</button>
</mat-menu>
<mat-menu #model="matMenu">
<ion-item button lines="none" *ngFor="let model of visaWorkflowModels" (click)="loadVisaWorkflow(model)">
<ion-label>{{model.title}}</ion-label>
<ion-label style="font-size: 14px;">{{model.title}}</ion-label>
<ion-buttons slot="end">
<ion-button fill="clear" slot="icon-only" shape="round" color="danger"
(click)="$event.stopPropagation();removeModel(model)">
......@@ -38,7 +37,7 @@
</ion-buttons>
</ion-item>
<ion-item button (click)="createModel()" [disabled]="visaWorkflow.length === 0">
<ion-label>{{'lang.newTemplate' | translate}}</ion-label>
<ion-label style="font-size: 14px;">{{'lang.newTemplate' | translate}}</ion-label>
</ion-item>
</mat-menu>
</ion-item>
......
......@@ -9,6 +9,7 @@ import { AlertController, IonReorderGroup, ModalController, PopoverController }
import { ItemReorderEventDetail } from '@ionic/core';
import { TranslateService } from '@ngx-translate/core';
import { OtpCreateComponent } from './otps/otp-create.component';
import { OtpService } from './otps/otp.service';
@Component({
selector: 'app-visa-workflow',
......@@ -40,6 +41,7 @@ export class VisaWorkflowComponent implements OnInit {
public authService: AuthService,
public notificationService: NotificationService,
public modalController: ModalController,
private otpService: OtpService,
) { }
ngOnInit(): void {
......@@ -156,15 +158,17 @@ export class VisaWorkflowComponent implements OnInit {
await modal.present();
modal.onDidDismiss()
.then((result: any) => {
.then(async (result: any) => {
if (typeof result.data === 'object') {
const obj: any = {
'userId': null,
'userDisplay': `${result.data.firstname} ${result.data.lastname}`,
'userPicture': await this.otpService.getUserOtpIcon(result.data.type),
'role': result.data.role,
'processDate': null,
'current': false,
'modes': [result.data.role]
'modes': [result.data.role],
'otp': result.data
};
this.visaWorkflow.push(obj);
}
......
......@@ -255,6 +255,7 @@ export class IndexationComponent implements OnInit {
encodedDocument: item.content
})),
workflow: this.appVisaWorkflow.getCurrentWorkflow().map((item: any, index: number) => ({
externalInformations: item.otp,
userId: item.userId,
mode: this.authService.getWorkflowMode(item.role),
signatureMode: this.authService.getSignatureMode(item.role),
......
......@@ -137,7 +137,16 @@ export class AuthService {
}
getWorkflowMode(id: string) {
return this.signatureRoles.filter((item: any) => item.id === id)[0].type;
const type = this.signatureRoles.filter((item: any) => item.id === id)[0]?.type;
const isOtp = /otp_[.]*/g;
const isSign = /_sign_/g;
// OTP user
if (id.match(isOtp) !== null) {
return id.match(isSign) !== null ? 'sign' : 'sign';
} else {
return type;
}
}
setCachedUrl(url: string) {
......
src/frontend/assets/yousign.png

4.65 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment