diff --git a/apps/maarch_entreprise/Views/securities-administration.component.html b/apps/maarch_entreprise/Views/securities-administration.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d49652013da3c81bf0955ff9f7b820c221108fcb --- /dev/null +++ b/apps/maarch_entreprise/Views/securities-administration.component.html @@ -0,0 +1,76 @@ +<div class="admin-container" [class.admin-is-mobile]="mobileQuery.matches"> + <mat-toolbar color="primary" class="admin-toolbar"> + <button mat-button (click)="snav.toggle()"> + <mat-icon class="maarchLogo" [svgIcon]="mobileQuery.matches ? 'maarchLogoOnly' : 'maarchLogo'"></mat-icon> + </button> + <h1 class="admin-toolbar-title">{{lang.securitiesAdministration}} + </h1> + <span style="flex: 1 1 auto;"></span> + <menu-top></menu-top> + </mat-toolbar> + <mat-sidenav-container class="admin-sidenav-container" [style.marginTop.px]="mobileQuery.matches ? 56 : 0"> + <mat-sidenav #snav [mode]="mobileQuery.matches ? 'over' : 'side'" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56" + [opened]="mobileQuery.matches ? false : true" style="width:400px;"> + <menu-nav></menu-nav> + <mat-divider></mat-divider> + <mat-nav-list> + <h3 mat-subheader>{{lang.securityConstraints}}</h3> + <ng-container *ngFor="let rule of passwordRulesList"> + <a mat-list-item disableRipple="true" *ngIf="rule.label != 'lockTime'"> + <mat-icon color="primary" mat-list-icon style="margin-bottom: 20px;"> + <mat-slide-toggle [checked]="rule.enabled" color="primary" (change)="toggleRule(rule);"></mat-slide-toggle> + </mat-icon> + <p mat-line [ngStyle]="{'opacity': rule.enabled ? '' : '0.5'}" (click)="toggleRule(rule);"> + {{passwordRules[rule.label].label}} + </p> + </a> + </ng-container> + </mat-nav-list> + </mat-sidenav> + <mat-sidenav-content> + <div *ngIf="loading" style="display:flex;height:100%;"> + <mat-spinner style="margin:auto;"></mat-spinner> + </div> + <mat-card *ngIf="!loading" class="card-app-content"> + <mat-tab-group> + <mat-tab label="Mot de passe"> + <form (ngSubmit)="onSubmit()" #passwordForm="ngForm"> + <ng-container *ngFor="let rule of passwordRulesList"> + <mat-form-field style="padding:10px;" *ngIf="rule.enabled && (rule.label == 'minLength' || rule.label == 'historyLastUse' || rule.label == 'renewal')"> + <input type="number" [name]="rule.label" [(ngModel)]="rule.value" min="1" matInput placeholder="{{passwordRules[rule.label].label}}" + required> + <span matSuffix *ngIf="rule.label == 'minLength'"> caractère(s)</span> + <span matSuffix *ngIf="rule.label == 'renewal'"> jour(s)</span> + </mat-form-field> + <div class="col-md-6" *ngIf="rule.enabled && rule.label == 'lockAttempts'"> + <mat-form-field> + <input type="number" [name]="rule.label" [(ngModel)]="rule.value" min="1" matInput placeholder="{{passwordRules[rule.label].label}}" + required> + <span matSuffix *ngIf="rule.label == 'minLength'"> caractère(s)</span> + <span matSuffix *ngIf="rule.label == 'renewal'"> jour(s)</span> + </mat-form-field> + </div> + <div class="col-md-6" *ngIf="rule.enabled && rule.label == 'lockTime'"> + <mat-form-field> + <input type="number" [name]="rule.label" [(ngModel)]="rule.value" min="1" matInput placeholder="{{passwordRules[rule.label].label}}" + required> + <span matSuffix> minute(s)</span> + </mat-form-field> + </div> + </ng-container> + <div class="col-md-12 text-center" style="padding:10px;"> + <button mat-raised-button type="submit" color="primary" [disabled]="!passwordForm.valid || checkModif()">{{lang.validate}}</button> + <button mat-raised-button type="button" color="default" [disabled]="checkModif()" (click)="cancelModification()">{{lang.cancel}}</button> + </div> + </form> + </mat-tab> + </mat-tab-group> + </mat-card> + </mat-sidenav-content> + <mat-sidenav #snav2 [mode]="mobileQuery.matches ? 'over' : 'side'" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56" + position='end' [opened]="mobileQuery.matches ? false : false" style="overflow-x:hidden;max-width:500px;"> + <mat-list> + </mat-list> + </mat-sidenav> + </mat-sidenav-container> +</div> \ No newline at end of file diff --git a/apps/maarch_entreprise/js/angular/app/administration/securities-administration.component.ts b/apps/maarch_entreprise/js/angular/app/administration/securities-administration.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bc7dccf7f9d5a3e8830787a5e760c1a55e8ad8c --- /dev/null +++ b/apps/maarch_entreprise/js/angular/app/administration/securities-administration.component.ts @@ -0,0 +1,102 @@ +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { MediaMatcher } from '@angular/cdk/layout'; +import { HttpClient } from '@angular/common/http'; +import { LANG } from '../translate.component'; +import { NotificationService } from '../notification.service'; + +declare function $j(selector: any): any; + +declare var angularGlobals: any; + + +@Component({ + templateUrl: "../../../../Views/securities-administration.component.html", + providers: [NotificationService] +}) +export class SecuritiesAdministrationComponent implements OnInit { + + mobileQuery : MediaQueryList; + private _mobileQueryListener : () => void; + + coreUrl : string; + lang : any = LANG; + loading : boolean = false; + + passwordRules: any = { + minLength: { enabled: false, value: 0 }, + complexityUpper: { enabled: false, value: 0 }, + complexityNumber: { enabled: false, value: 0 }, + complexitySpecial: { enabled: false, value: 0 }, + renewal: { enabled: false, value: 0 }, + historyLastUse: { enabled: false, value: 0 }, + lockTime: { enabled: false, value: 0 }, + lockAttempts: { enabled: false, value: 0 }, + }; + + passwordRulesList : any[] = []; + passwordRulesListClone : any[] = []; + + + constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher, public http: HttpClient, private notify: NotificationService) { + $j("link[href='merged_css.php']").remove(); + this.mobileQuery = media.matchMedia('(max-width: 768px)'); + this._mobileQueryListener = () => changeDetectorRef.detectChanges(); + this.mobileQuery.addListener(this._mobileQueryListener); + } + + ngOnDestroy(): void { + this.mobileQuery.removeListener(this._mobileQueryListener); + } + + ngOnInit(): void { + this.loading = true; + this.coreUrl = angularGlobals.coreUrl; + + this.http.get(this.coreUrl + 'rest/passwordRules') + .subscribe((data: any) => { + this.passwordRulesList = data.rules; + this.passwordRulesListClone = JSON.parse(JSON.stringify(this.passwordRulesList)); + data.rules.forEach((rule: any) => { + this.passwordRules[rule.label].value = rule.value; + this.passwordRules[rule.label].label = this.lang['password'+rule.label+'Required'] + + this.loading = false; + }); + }, (err) => { + this.notify.error(err.error.errors); + }); + } + + cancelModification() { + this.passwordRulesList = JSON.parse(JSON.stringify(this.passwordRulesListClone)); + } + + checkModif() { + if (JSON.stringify(this.passwordRulesList) === JSON.stringify(this.passwordRulesListClone)) { + return true + } else { + return false; + } + } + + toggleRule(rule:any) { + rule.enabled = !rule.enabled; + if (rule.label == 'lockAttempts') { + this.passwordRulesList.forEach((rule2: any) => { + if (rule2.label == 'lockTime') { + rule2.enabled = !rule2.enabled; + } + }); + } + } + + onSubmit() { + this.http.put(this.coreUrl + "rest/passwordRules", {rules:this.passwordRulesList}) + .subscribe((data: any) => { + this.passwordRulesListClone = JSON.parse(JSON.stringify(this.passwordRulesList)); + this.notify.success(this.lang.passwordRulesUpdated); + }, (err: any) => { + this.notify.error(err.error.errors); + }); + } +}