From ee7246d7fef118b4000b53034c948149e544b620 Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Thu, 25 Jun 2020 17:14:50 +0200
Subject: [PATCH] FEAT #13671 TIME 3:30 front installer mail server

---
 .../customization.component.html              |   2 +-
 .../app/installer/installer.component.html    |  21 +-
 .../app/installer/installer.module.ts         |   2 +
 .../mailserver/mailserver.component.html      |  85 ++++++++
 .../mailserver/mailserver.component.scss      |  55 +++++
 .../mailserver/mailserver.component.ts        | 194 ++++++++++++++++++
 src/frontend/lang/lang-fr.ts                  |   3 +
 src/frontend/service/functions.service.ts     |  29 ++-
 8 files changed, 373 insertions(+), 18 deletions(-)
 create mode 100644 src/frontend/app/installer/mailserver/mailserver.component.html
 create mode 100644 src/frontend/app/installer/mailserver/mailserver.component.scss
 create mode 100644 src/frontend/app/installer/mailserver/mailserver.component.ts

diff --git a/src/frontend/app/installer/customization/customization.component.html b/src/frontend/app/installer/customization/customization.component.html
index a7f199212a2..0ad45beb5b9 100644
--- a/src/frontend/app/installer/customization/customization.component.html
+++ b/src/frontend/app/installer/customization/customization.component.html
@@ -3,7 +3,7 @@
     <div class="alert-message alert-message-info" role="alert" style="margin-top: 30px;min-width: 100%;">
         {{lang.stepCustomization_desc}}
     </div>
-    <form [formGroup]="stepFormGroup" style="display: content;">
+    <form [formGroup]="stepFormGroup" style="display: contents;">
         <div class="col-md-6">
             <mat-form-field appearance="outline">
                 <mat-label>{{lang.instanceId}}</mat-label>
diff --git a/src/frontend/app/installer/installer.component.html b/src/frontend/app/installer/installer.component.html
index 699069827c0..cd3aa4022e0 100644
--- a/src/frontend/app/installer/installer.component.html
+++ b/src/frontend/app/installer/installer.component.html
@@ -7,6 +7,20 @@
         <div class="container" [class.fullContainer]="appService.getViewMode()">
             <div class="container-content" style="overflow: hidden;">
                 <mat-horizontal-stepper [@.disabled]="true" linear #stepper style="height: 100vh;overflow: auto;" (selectionChange)="initStep($event)">
+                    <mat-step [stepControl]="appMailserver.getFormGroup()">
+                        <ng-template matStepLabel>{{lang.stepMailServer}}</ng-template>
+                        <div class="stepContainer">
+                            <div class="stepContent">
+                                <app-mailserver #appMailserver #stepContent (tiggerInstall)="endInstall()"></app-mailserver>
+                            </div>
+                            <button mat-fab matStepperPrevious class="previousStepButton" color="primary">
+                                <mat-icon class="fa fa-arrow-left"></mat-icon>
+                            </button>
+                            <button mat-fab matStepperNext class="nextStepButton" color="primary" [disabled]="!appMailserver.isValidStep()">
+                                <mat-icon class="fa fa-arrow-right"></mat-icon>
+                            </button>
+                        </div>
+                    </mat-step>
                     <mat-step label="install">
                         <ng-template matStepLabel>Installation</ng-template>
                         <div class="stepContainer">
@@ -88,13 +102,6 @@
                             </button>
                         </div>
                     </mat-step>
-                    <mat-step optional>
-                        <ng-template matStepLabel>Serveur mail</ng-template>
-                        Bonjour
-                        <div>
-                            <button mat-button matStepperPrevious>Back</button>
-                        </div>
-                    </mat-step>
                     <ng-template matStepperIcon="edit">
                         <mat-icon class="fa fa-check stepIcon"></mat-icon>
                     </ng-template>
diff --git a/src/frontend/app/installer/installer.module.ts b/src/frontend/app/installer/installer.module.ts
index 8cbe8921142..c27c72afb70 100644
--- a/src/frontend/app/installer/installer.module.ts
+++ b/src/frontend/app/installer/installer.module.ts
@@ -8,6 +8,7 @@ import { DatabaseComponent } from './database/database.component';
 import { DocserversComponent } from './docservers/docservers.component';
 import { CustomizationComponent } from './customization/customization.component';
 import { UseradminComponent } from './useradmin/useradmin.component';
+import { MailserverComponent } from './mailserver/mailserver.component';
 import { InstallerRoutingModule } from './installer-routing.module';
 
 @NgModule({
@@ -24,6 +25,7 @@ import { InstallerRoutingModule } from './installer-routing.module';
         DocserversComponent,
         CustomizationComponent,
         UseradminComponent,
+        MailserverComponent
     ],
     entryComponents: [InstallActionComponent]
 })
diff --git a/src/frontend/app/installer/mailserver/mailserver.component.html b/src/frontend/app/installer/mailserver/mailserver.component.html
new file mode 100644
index 00000000000..7d7a167a615
--- /dev/null
+++ b/src/frontend/app/installer/mailserver/mailserver.component.html
@@ -0,0 +1,85 @@
+<div class="stepContent">
+    <h2 class="stepContentTitle"><i class="fa fa-mail-bulk"></i> {{lang.stepMailServer}}</h2>
+    <div class="alert-message alert-message-info" role="alert" style="margin-top: 30px;min-width: 100%;"
+        [innerHTML]="lang.stepMailServer_desc">
+    </div>
+    <div class="alert-message alert-message-danger" role="alert" style="margin-top: 30px;min-width: 100%;"
+    [innerHTML]="lang.stepMailServer_warning">
+</div>
+    <mat-drawer-container autosize>
+        <mat-drawer-content>
+            <div style="width: 99%;">
+                <form [formGroup]="stepFormGroup" style="display: contents;">
+                    <mat-form-field>
+                        <mat-select #smtpType name="smtpType" [placeholder]="lang.configurationType"
+                            formControlName="type" required>
+                            <mat-option *ngFor="let type of smtpTypeList" [value]="type.id">
+                                {{type.label}}
+                            </mat-option>
+                        </mat-select>
+                    </mat-form-field>
+                    <div class="row" style="margin:0px;">
+                        <div class="col-md-2">
+                            <mat-form-field>
+                                <mat-select name="SMTPSecure" [placeholder]="lang.smtpAuth" formControlName="secure">
+                                    <mat-option *ngFor="let security of smtpSecList" [value]="security.id">
+                                        {{security.label}}
+                                    </mat-option>
+                                </mat-select>
+                            </mat-form-field>
+                        </div>
+                        <div class="col-md-9">
+                            <mat-form-field>
+                                <input matInput name="host" formControlName="host" [placeholder]="lang.host" required>
+                            </mat-form-field>
+                        </div>
+                        <div class="col-md-1">
+                            <mat-form-field>
+                                <input name="port" type="number" matInput formControlName="port"
+                                    [placeholder]="lang.port" required>
+                            </mat-form-field>
+                        </div>
+                    </div>
+                    <mat-slide-toggle color="primary" name="SMTPAuth" formControlName="auth">
+                        {{lang.enableAuth}}
+                    </mat-slide-toggle>
+                    <mat-form-field>
+                        <input name="user" formControlName="user" matInput placeholder="{{lang.id}}" required>
+                    </mat-form-field>
+                    <mat-form-field>
+                        <input name="password" [type]="hidePassword ? 'password' : 'text'" formControlName="password"
+                            matInput [placeholder]="this.lang.password" required>
+                        <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>
+                        <input name="mailFrom" formControlName="from" required matInput [placeholder]="lang.mailFrom">
+                    </mat-form-field>
+                </form>
+            </div>
+        </mat-drawer-content>
+        <mat-drawer #checkMailserverContent mode="side" position="end" style="padding:10px;width: 350px;">
+            <mat-nav-list disableRipple="true" style="display: flex;flex-direction: column;">
+                <h3 mat-subheader>{{lang.emailSendTest}}</h3>
+                <mat-form-field>
+                    <input name="recipientTest" matInput placeholder="{{lang.mailTo}}" [(ngModel)]="recipientTest"
+                        [disabled]="emailSendLoading">
+                    <mat-icon *ngIf="!emailSendLoading" title="{{lang.beginSendTest}}" (click)="testEmailSend()"
+                        color="primary" style="cursor: pointer;" matSuffix class="fa fa-paper-plane fa-2x"></mat-icon>
+                </mat-form-field>
+                <mat-list-item *ngIf="emailSendResult.msg != ''">
+                    <mat-icon mat-list-icon class="fas {{emailSendResult.icon}} fa-2x"></mat-icon>
+                    <p mat-line> {{emailSendResult.msg}} </p>
+                </mat-list-item>
+            </mat-nav-list>
+            <div class="bash" *ngIf="this.emailSendResult.msg === lang.emailSendFailed">
+                {{this.emailSendResult.debug}}
+            </div>
+        </mat-drawer>
+    </mat-drawer-container>
+    <div class="text-center">
+        <button mat-raised-button type="button" color="primary" (click)="checkMailserverContent.open()"
+            [disabled]="!stepFormGroup.valid">{{lang.checkSendmail}}</button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/installer/mailserver/mailserver.component.scss b/src/frontend/app/installer/mailserver/mailserver.component.scss
new file mode 100644
index 00000000000..af9d1274baf
--- /dev/null
+++ b/src/frontend/app/installer/mailserver/mailserver.component.scss
@@ -0,0 +1,55 @@
+@import '../../../css/vars.scss';
+
+
+.stepContent {
+    // max-width: 850px;
+    margin: auto;
+
+    .stepContentTitle {
+        color: $primary;
+        margin-bottom: 30px;
+        border-bottom: solid 1px;
+        padding: 0;
+    }
+}
+
+.backgroundList {
+    display: grid;
+    grid-template-columns: repeat(5, 1fr);
+    grid-gap: 10px;
+}
+
+.selected {
+    transition: all 0.3s;
+    opacity: 1 !important;
+    border: solid 10px $secondary !important;
+}
+
+.backgroundItem {
+    border: solid 0px $secondary;
+    opacity: 0.5;
+    transition: all 0.3s;
+    cursor: pointer;
+    height: 120px;
+    background-size: cover !important;
+}
+
+.backgroundItem:hover {
+    transition: all 0.3s;
+    opacity: 1 !important;
+}
+
+.bash {
+    background: #34495e;
+    height: 310px;
+    border-radius: 5px;
+    top: 40px;
+    display: absolute;
+    color: #fff;
+    padding: 10px;
+    margin: 10px;
+}
+
+mat-drawer-container {
+    background: none !important;
+}
\ No newline at end of file
diff --git a/src/frontend/app/installer/mailserver/mailserver.component.ts b/src/frontend/app/installer/mailserver/mailserver.component.ts
new file mode 100644
index 00000000000..760071c86b8
--- /dev/null
+++ b/src/frontend/app/installer/mailserver/mailserver.component.ts
@@ -0,0 +1,194 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators, ValidatorFn } from '@angular/forms';
+import { LANG } from '../../translate.component';
+import { StepAction } from '../types';
+import { DomSanitizer } from '@angular/platform-browser';
+import { NotificationService } from '../../../service/notification/notification.service';
+import { environment } from '../../../environments/environment';
+import { ScanPipe } from 'ngx-pipes';
+import { debounceTime, filter, tap, catchError } from 'rxjs/operators';
+import { HttpClient } from '@angular/common/http';
+import { of } from 'rxjs/internal/observable/of';
+import { MatDrawer } from '@angular/material/sidenav';
+
+declare var tinymce: any;
+
+@Component({
+    selector: 'app-mailserver',
+    templateUrl: './mailserver.component.html',
+    styleUrls: ['./mailserver.component.scss'],
+})
+export class MailserverComponent implements OnInit {
+    lang: any = LANG;
+
+    hidePassword: boolean = true;
+    stepFormGroup: FormGroup;
+
+    testRecipient: string = '';
+    emailSendLoading: boolean = false;
+    emailSendResult: any = {
+        msg: '',
+        debug: ''
+    };
+
+    smtpTypeList = [
+        {
+            id: 'smtp',
+            label: this.lang.smtpclient
+        },
+        {
+            id: 'sendmail',
+            label: this.lang.smtprelay
+        },
+        {
+            id: 'qmail',
+            label: this.lang.qmail
+        },
+        {
+            id: 'mail',
+            label: this.lang.phpmail
+        }
+    ];
+    smtpSecList = [
+        {
+            id: '',
+            label: this.lang.none
+        },
+        {
+            id: 'ssl',
+            label: 'ssl'
+        },
+        {
+            id: 'tls',
+            label: 'tls'
+        }
+    ];
+
+    @ViewChild('checkMailserverContent', { static: true }) checkMailserverContent: MatDrawer;
+
+    constructor(
+        private _formBuilder: FormBuilder,
+        private notify: NotificationService,
+        public http: HttpClient,
+    ) {
+        const valEmail: ValidatorFn[] = [Validators.pattern(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/), Validators.required];
+
+        this.stepFormGroup = this._formBuilder.group({
+            firstCtrl: ['success', Validators.required],
+            type: ['smtp', Validators.required],
+            host: ['', Validators.required],
+            auth: [true],
+            user: ['', Validators.required],
+            password: ['', Validators.required],
+            secure: ['ssl', Validators.required],
+            port: ['465', Validators.required],
+            charset: ['utf-8', Validators.required],
+            from: ['', valEmail],
+        });
+    }
+
+    ngOnInit(): void {
+        this.stepFormGroup.valueChanges.subscribe(() => {
+            if (this.checkMailserverContent.opened) {
+                this.checkMailserverContent.close();
+                this.emailSendLoading = false;
+                this.emailSendResult = {
+                    icon: 'fa-paper-plane primary',
+                    msg: this.lang.emailSendInProgress,
+                    debug: ''
+                };
+            }
+        });
+        this.stepFormGroup.controls['type'].valueChanges.pipe(
+            tap((data: any) => {
+                if (['smtp', 'mail'].indexOf(data) === -1) {
+                    this.stepFormGroup.controls['secure'].disable();
+                    this.stepFormGroup.controls['host'].disable();
+                    this.stepFormGroup.controls['port'].disable();
+                    this.stepFormGroup.controls['auth'].disable();
+                    this.stepFormGroup.controls['user'].disable();
+                    this.stepFormGroup.controls['password'].disable();
+                } else {
+                    this.stepFormGroup.controls['secure'].enable();
+                    this.stepFormGroup.controls['host'].enable();
+                    this.stepFormGroup.controls['port'].enable();
+                    this.stepFormGroup.controls['auth'].enable();
+                    if (this.stepFormGroup.controls['auth'].value) {
+                        this.stepFormGroup.controls['user'].enable();
+                        this.stepFormGroup.controls['password'].enable();
+                    }
+                }
+            })
+        ).subscribe();
+        this.stepFormGroup.controls['auth'].valueChanges.pipe(
+            tap((data: any) => {
+                if (!data) {
+                    this.stepFormGroup.controls['user'].disable();
+                    this.stepFormGroup.controls['password'].disable();
+                } else {
+                    this.stepFormGroup.controls['user'].enable();
+                    this.stepFormGroup.controls['password'].enable();
+                }
+            })
+        ).subscribe();
+    }
+
+    testEmailSend() {
+        this.emailSendResult = {
+            icon: 'fa-paper-plane primary',
+            msg: this.lang.emailSendInProgress,
+            debug: ''
+        };
+        const email = {
+            'sender': { 'email': this.stepFormGroup.controls['from'] },
+            'recipients': [this.testRecipient],
+            'object': '[' + this.lang.doNotReply + '] ' + this.lang.emailSendTest,
+            'status': 'EXPRESS',
+            'body': this.lang.emailSendTest,
+            'isHtml': false
+        };
+        this.emailSendLoading = true;
+
+        this.http.get(`../rest/emails`).pipe(
+            tap((data: any) => {
+                this.emailSendLoading = false;
+                this.emailSendResult = {
+                    icon: 'fa-check green',
+                    msg: this.lang.emailSendSuccess,
+                    debug: ''
+                };
+            }),
+            catchError((err: any) => {
+                console.log(err);
+
+                this.emailSendLoading = false;
+                this.emailSendResult = {
+                    icon: 'fa-times red',
+                    msg: this.lang.emailSendFailed,
+                    debug: err.error.errors
+                };
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    initStep() {
+        return false;
+    }
+
+    isValidStep() {
+        return this.stepFormGroup === undefined ? false : this.stepFormGroup.valid;
+    }
+
+    getFormGroup() {
+        return this.stepFormGroup;
+    }
+
+    checkStep() {
+        return this.stepFormGroup.valid;
+    }
+
+    getInfoToInstall(): StepAction[] {
+        return [];
+    }
+}
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index d18b0046f8d..b6433f79030 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -1804,4 +1804,7 @@ export const LANG_FR = {
     "customAlreadyExist": "Ce custom semble déjà exister.",
     "onlySpecialCharAllowed": "Seul les caractères spéciaux {0} sont autorisés.",
     "dbNotEmpty": "Cette base de données existe déjà et n'est pas vide",
+    "stepMailServer": "Serveur de mail",
+    "stepMailServer_desc": "Configurer votre serveur de mail afin de prévenir les utilisateurs par mail des différents échanges survenus dans l'application.<br/>Cette étape peut être passé et être configurée plus tard.",
+    "stepMailServer_warning": "Si aucun serveur de mail n'est renseigné, les nouveaux utilisateurs ne recevront pas leur jeton de première connexion !",
 };
diff --git a/src/frontend/service/functions.service.ts b/src/frontend/service/functions.service.ts
index 2cbcde82a5c..fbb57282969 100644
--- a/src/frontend/service/functions.service.ts
+++ b/src/frontend/service/functions.service.ts
@@ -120,18 +120,27 @@ export class FunctionsService {
     }
 
     debug(msg: string, route: string) {
-        const info: any = {
+        let info: any = {
             route : route,
-            session : {
-                id : this.authService.getAppSession(),
-                expireIn : new Date((JSON.parse(atob(this.authService.getToken().split('.')[1])).exp) * 1000)
-            },
-            refreshSession : {
-                id : this.authService.getAppSession(),
-                expireIn : new Date((JSON.parse(atob(this.authService.getRefreshToken().split('.')[1])).exp) * 1000)
-            },
-            user : this.headerService.user,
+            session : 'No user logged !',
+            refreshSession : 'No user logged !',
+            user : 'No user logged !'
         };
+        if (this.authService.getToken() != null) {
+            info = {
+                route : route,
+                session : {
+                    id : this.authService.getAppSession(),
+                    expireIn : new Date((JSON.parse(atob(this.authService.getToken().split('.')[1])).exp) * 1000)
+                },
+                refreshSession : {
+                    id : this.authService.getAppSession(),
+                    expireIn : new Date((JSON.parse(atob(this.authService.getRefreshToken().split('.')[1])).exp) * 1000)
+                },
+                user : this.headerService.user,
+            };
+        }
+
         if (msg !== '') {
             console.log(msg, info);
         } else {
-- 
GitLab