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