From 5532c54b73b1dc87a3ae8b7e4cd1fbc5a9ae8e14 Mon Sep 17 00:00:00 2001 From: "florian.azizian" <florian.azizian@maarch.org> Date: Tue, 25 Jun 2019 15:37:41 +0100 Subject: [PATCH] FEAT #10734 TIME 3 Admin email configuration --- lang/en.json | 16 ++- lang/fr.json | 16 ++- .../controllers/ConfigurationController.php | 27 ++-- .../group/controllers/PrivilegeController.php | 2 +- .../sendmail/sendmail.component.html | 76 +++++++++++ .../sendmail/sendmail.component.scss | 2 + .../sendmail/sendmail.component.ts | 124 ++++++++++++++++++ src/frontend/app/app.module.ts | 5 +- 8 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 src/frontend/app/administration/sendmail/sendmail.component.html create mode 100644 src/frontend/app/administration/sendmail/sendmail.component.scss create mode 100644 src/frontend/app/administration/sendmail/sendmail.component.ts diff --git a/lang/en.json b/lang/en.json index 1dcd177140..0a70b5f5e2 100755 --- a/lang/en.json +++ b/lang/en.json @@ -215,6 +215,20 @@ "ldapInformations" : "Ldap informations", "ldapAdded" : "Ldap Connection added", "ldapUpdated" : "Ldap Connection updated", - "ldapDeleted" : "Ldap Connection deleted" + "ldapDeleted" : "Ldap Connection deleted", + "configurationType" : "Configuration type", + "smtpAuth" : "Authentication methode", + "host" : "Host", + "port" : "Port", + "enableAuth" : "Activate authentication", + "id" : "Login", + "mailFrom" : "Mail address used", + "passwordModification" : "Password modification", + "none" : "None", + "phpmail" : "Function php (mail)", + "qmail" : "Local mail server (Qmail)", + "smtprelay" : "Smtp relay (sendmail)", + "smtpclient" : "Smtp client (smtp)", + "emailConfigurationUpdated" : "Email configuration updated" } } diff --git a/lang/fr.json b/lang/fr.json index d2adb6ffd7..c81c0291a2 100755 --- a/lang/fr.json +++ b/lang/fr.json @@ -216,6 +216,20 @@ "ldapInformations" : "Informations utilisées par le ldap", "ldapAdded" : "Connexion ldap ajoutée", "ldapUpdated" : "Connexion ldap modifiée", - "ldapDeleted" : "Connexion ldap supprimée" + "ldapDeleted" : "Connexion ldap supprimée", + "configurationType" : "Type de configuration", + "smtpAuth" : "Méthode d'authentification", + "host" : "Hôte", + "port" : "Port", + "enableAuth" : "Activer l'authentification", + "id" : "Identification", + "mailFrom" : "Adresse d'envoi", + "passwordModification" : "Changement de mot de passe", + "none" : "Aucune", + "phpmail" : "Fonction php (mail)", + "qmail" : "Serveur mail local (Qmail)", + "smtprelay" : "Relais smtp (sendmail)", + "smtpclient" : "Client smtp (smtp)", + "emailConfigurationUpdated" : "Configuration du serveur mise à jour" } } diff --git a/src/app/configuration/controllers/ConfigurationController.php b/src/app/configuration/controllers/ConfigurationController.php index 1d60e52a5b..7f59793874 100755 --- a/src/app/configuration/controllers/ConfigurationController.php +++ b/src/app/configuration/controllers/ConfigurationController.php @@ -69,6 +69,15 @@ class ConfigurationController $configuration['value'] = json_decode($configuration['value'], true); + if ($configuration['identifier'] == 'emailServer') { + if (!empty($configuration['value']['password'])) { + $configuration['value']['password'] = ''; + $configuration['value']['passwordAlreadyExists'] = true; + } else { + $configuration['value']['passwordAlreadyExists'] = false; + } + } + return $response->withJson(['configuration' => $configuration]); } @@ -174,24 +183,24 @@ class ConfigurationController return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); } - $check = ConfigurationController::checkMailer($body); + $check = ConfigurationController::checkMailer($body['value']); if (!empty($check['errors'])) { return $response->withStatus(400)->withJson(['errors' => $check['errors']]); } - if ($body['auth'] && empty($body['password']) && !empty($configuration)) { + if ($body['value']['auth'] && empty($body['value']['password']) && !empty($configuration)) { $configuration['value'] = json_decode($configuration['value'], true); if (!empty($configuration['value']['password'])) { - $body['password'] = $configuration['value']['password']; + $body['value']['password'] = $configuration['value']['password']; } - } elseif ($body['auth'] && !empty($body['password'])) { - $body['password'] = AuthenticationModel::encrypt(['password' => $body['password']]); - } elseif (!$body['auth']) { - $body['user'] = null; - $body['password'] = null; + } elseif ($body['value']['auth'] && !empty($body['value']['password'])) { + $body['value']['password'] = AuthenticationModel::encrypt(['password' => $body['value']['password']]); + } elseif (!$body['value']['auth']) { + $body['value']['user'] = null; + $body['value']['password'] = null; } - if ($body['auth'] && empty($body['value']['password'])) { + if ($body['value']['auth'] && empty($body['value']['password'])) { $configuration['value'] = json_decode($configuration['value'], true); if (!empty($configuration['value']['password'])) { $body['value']['password'] = $configuration['value']['password']; diff --git a/src/app/group/controllers/PrivilegeController.php b/src/app/group/controllers/PrivilegeController.php index 7f81fdf5f0..1ad6664e28 100755 --- a/src/app/group/controllers/PrivilegeController.php +++ b/src/app/group/controllers/PrivilegeController.php @@ -26,7 +26,7 @@ class PrivilegeController ['id' => 'manage_users', 'type' => 'admin', 'icon' => 'fa fa-user', 'route' => '/administration/users'], ['id' => 'manage_groups', 'type' => 'admin', 'icon' => 'fa fa-users', 'route' => '/administration/groups'], ['id' => 'manage_connections', 'type' => 'admin', 'icon' => 'fas fa-database', 'route' => '/administration/connections'], - ['id' => 'manage_email_configuration', 'type' => 'admin', 'icon' => 'fa fa-paper-plane', 'route' => '/administration/configuration'], + ['id' => 'manage_email_configuration', 'type' => 'admin', 'icon' => 'fa fa-paper-plane', 'route' => '/administration/emailConfiguration'], ['id' => 'manage_documents', 'type' => 'simple'] ]; diff --git a/src/frontend/app/administration/sendmail/sendmail.component.html b/src/frontend/app/administration/sendmail/sendmail.component.html new file mode 100644 index 0000000000..bb7b17c3c3 --- /dev/null +++ b/src/frontend/app/administration/sendmail/sendmail.component.html @@ -0,0 +1,76 @@ +<mat-sidenav-container autosize> + <mat-sidenav #snav [disableClose]="!signaturesService.mobileMode" [mode]="signaturesService.mobileMode ? 'over': 'side'" fixedInViewport="true" + [opened]="!signaturesService.mobileMode" [style.width.px]="350"> + <app-admin-sidebar [snavLeftComponent]="this.snav" [snavRightComponent]="this.snavRight"></app-admin-sidebar> + </mat-sidenav> + <mat-sidenav-content class="mainView"> + <header class="header"> + <div class="header-title"> + <button *ngIf="signaturesService.mobileMode" mat-icon-button (click)="this.snav.toggle();"> + <mat-icon fontSet="fas" fontIcon="fa-bars" style="font-size: 24px;"></mat-icon> + </button> + <span *ngIf="!loading">{{title}}</span> + </div> + </header> + <div class="container"> + <div *ngIf="loading" class="loader"> + <mat-spinner></mat-spinner> + </div> + <form class="admin-form" *ngIf="!loading" (ngSubmit)="onSubmit()" #sendmailForm="ngForm"> + <mat-form-field class="input-row"> + <mat-select #smtpType name="smtpType" placeholder="{{'lang.configurationType' | translate}}" [(ngModel)]="sendmail.type" required> + <mat-option *ngFor="let type of smtpTypeList" [value]="type.id"> + {{type.label | translate}} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field> + <mat-select name="SMTPSecure" placeholder="{{'lang.smtpAuth' | translate}}" [disabled]="['smtp', 'mail'].indexOf(sendmail.type) == -1" + [(ngModel)]="sendmail.secure"> + <mat-option *ngFor="let security of smtpSecList" [value]="security.id"> + {{security.label| translate}} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field > + <input matInput name="host" [disabled]="['smtp', 'mail'].indexOf(sendmail.type) == -1" [(ngModel)]="sendmail.host" + placeholder="{{'lang.host' | translate}}" required> + </mat-form-field> + + <mat-form-field class="input-row col-md-1"> + <input name="port" type="number" matInput [(ngModel)]="sendmail.port" + [disabled]="['smtp', 'mail'].indexOf(sendmail.type) == -1" placeholder="{{'lang.port' | translate}}" required> + </mat-form-field> + + <mat-slide-toggle color="primary" name="SMTPAuth" [(ngModel)]="sendmail.auth" + [disabled]="['smtp', 'mail'].indexOf(sendmail.type) == -1"(change)="cleanAuthInfo($event)">{{'lang.enableAuth' | translate}}</mat-slide-toggle> + + <mat-form-field class="input-row"> + <input name="user" [(ngModel)]="sendmail.user" [disabled]="!sendmail.auth || ['smtp', 'mail'].indexOf(sendmail.type) == -1" + matInput placeholder="{{'lang.id' | translate}}" required> + </mat-form-field> + + <mat-form-field class="input-row"> + <input name="password" [type]="hidePassword ? 'password' : 'text'" [(ngModel)]="sendmail.password" + [disabled]="!sendmail.auth || ['smtp', 'mail'].indexOf(sendmail.type) == -1" matInput placeholder="{{passwordLanguage}}" [required]="!sendmail.passwordAlreadyExists"> + <mat-icon color="primary" style="cursor: pointer;" matSuffix (click)="hidePassword = !hidePassword" + class="fa fa-2x" [ngClass]="[hidePassword ? 'fa-eye-slash' : 'fa-eye']"></mat-icon> + </mat-form-field> + + <mat-form-field class="input-row"> + <input name="mailFrom" [(ngModel)]="sendmail.from" [disabled]="['smtp', 'mail'].indexOf(sendmail.type) == -1" + matInput placeholder="{{'lang.mailFrom' | translate}}" pattern="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"> + </mat-form-field> + + <div class="actions-form"> + <button mat-stroked-button type="submit" class="btn blue" [disabled]="!sendmailForm.form.valid || !canValidate()">{{'lang.validate' | translate}}</button> + <button mat-stroked-button type="button" class="btn" (click)="cancel()">{{'lang.cancel' | translate}}</button> + </div> + </form> + </div> + </mat-sidenav-content> + <mat-sidenav #snavRight disableClose [mode]="signaturesService.mobileMode ? 'over': 'side'" [opened]="false" fixedInViewport="true" position='end'> + </mat-sidenav> +</mat-sidenav-container> \ No newline at end of file diff --git a/src/frontend/app/administration/sendmail/sendmail.component.scss b/src/frontend/app/administration/sendmail/sendmail.component.scss new file mode 100644 index 0000000000..5c4c549ffa --- /dev/null +++ b/src/frontend/app/administration/sendmail/sendmail.component.scss @@ -0,0 +1,2 @@ +@import '../../../css/vars.scss'; + diff --git a/src/frontend/app/administration/sendmail/sendmail.component.ts b/src/frontend/app/administration/sendmail/sendmail.component.ts new file mode 100644 index 0000000000..27ecadeb5b --- /dev/null +++ b/src/frontend/app/administration/sendmail/sendmail.component.ts @@ -0,0 +1,124 @@ +import { Component, OnInit } from '@angular/core'; +import { SignaturesContentService } from '../../service/signatures.service'; +import { NotificationService } from '../../service/notification.service'; +import { HttpClient } from '@angular/common/http'; +import { MatDialog } from '@angular/material'; +import { map, finalize } from 'rxjs/operators'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; + + +export interface Sendmail { + auth: boolean, + from: string, + host: string, + port: number, + type: string, + user: string, + secure: string, + charset: string, + password: string, + passwordAlreadyExists: boolean +} + +@Component({ + selector: 'app-administration-sendmail', + templateUrl: 'sendmail.component.html', + styleUrls: ['../administration.scss', 'sendmail.component.scss'], +}) + +export class SendmailComponent implements OnInit { + + loading: boolean = true; + sendmail: Sendmail; + sendmailClone: Sendmail; + title: string = ''; + passwordLanguage: string = ''; + hidePassword: boolean = true; + sendmailLabel: string; + + smtpTypeList = [ + { + id: 'smtp', + label: 'lang.smtpclient' + }, + { + id: 'sendmail', + label: 'lang.smtprelay' + }, + { + id: 'qmail', + label: 'lang.qmail' + }, + { + id: 'mail', + label: 'lang.phpmail' + } + ]; + smtpSecList = [ + { + id : '', + label : 'lang.none' + }, + { + id : 'ssl', + label : 'ssl' + }, + { + id : 'tls', + label : 'tls' + } + ]; + + constructor(public http: HttpClient, private translate: TranslateService, private route: ActivatedRoute, private router: Router, public signaturesService: SignaturesContentService, public notificationService: NotificationService, public dialog: MatDialog) { + } + + ngOnInit(): void { + this.route.params.subscribe(() => { + this.http.get('../rest/configurations/1') + .pipe( + map((data: any) => data.configuration), + finalize(() => this.loading = false) + ) + .subscribe({ + next: data => { + this.sendmail = data.value; + this.sendmailLabel = data.label; + this.sendmailClone = JSON.parse(JSON.stringify(this.sendmail)); + this.title = this.translate.instant('lang.manage_email_configuration'); + if (this.sendmail.passwordAlreadyExists) { + this.passwordLanguage = this.translate.instant('lang.passwordModification'); + } else { + this.passwordLanguage = this.translate.instant('lang.password'); + } + }, + }); + }); + } + + canValidate() { + if (JSON.stringify(this.sendmail) === JSON.stringify(this.sendmailClone)) { + return false; + } else { + return true; + } + } + + onSubmit() { + this.loading = true; + this.http.patch('../rest/configurations/1', {'value': this.sendmail, 'label': this.sendmailLabel}) + .pipe( + finalize(() => this.loading = false) + ) + .subscribe({ + next: () => { + this.router.navigate(['/administration']); + this.notificationService.success('lang.emailConfigurationUpdated'); + }, + }); + } + + cancel() { + this.router.navigate(['/administration']); + } +} diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts index 3e7b24b948..d65bc68b15 100755 --- a/src/frontend/app/app.module.ts +++ b/src/frontend/app/app.module.ts @@ -61,6 +61,7 @@ import { UserComponent } from './administration/user/user.component'; import { ConnectionComponent } from './administration/connection/connection.component'; import { LdapListComponent } from './administration/connection/ldap/ldap-list.component'; import { LdapComponent } from './administration/connection/ldap/ldap.component'; +import { SendmailComponent } from './administration/sendmail/sendmail.component'; // SERVICES @@ -107,7 +108,8 @@ import { AlertComponent } from './plugins/alert.component'; AdminSidebarComponent, ConnectionComponent, LdapListComponent, - LdapComponent + LdapComponent, + SendmailComponent ], imports: [ FormsModule, @@ -138,6 +140,7 @@ import { AlertComponent } from './plugins/alert.component'; { path: 'administration/connections/ldaps', canActivate: [AuthGuard], component: LdapListComponent }, { path: 'administration/connections/ldaps/new', canActivate: [AuthGuard], component: LdapComponent }, { path: 'administration/connections/ldaps/:id', canActivate: [AuthGuard], component: LdapComponent }, + { path: 'administration/emailConfiguration', canActivate: [AuthGuard], component: SendmailComponent }, { path: 'documents/:id', canActivate: [AuthGuard], component: DocumentComponent }, { path: 'documents', canActivate: [AuthGuard], component: DocumentComponent }, { path: 'login', component: LoginComponent }, -- GitLab