From 61cb5c82417f327242e1334b040a4a30f4366352 Mon Sep 17 00:00:00 2001
From: Damien <damien.burel@maarch.org>
Date: Mon, 9 Jul 2018 10:41:55 +0200
Subject: [PATCH] FEAT #7659 Renewal + password modification

---
 .../password-modification.component.html      | 24 ++++++++
 apps/maarch_entreprise/index.php              |  6 +-
 .../js/angular/app/app-routing.module.ts      | 12 ++--
 .../js/angular/app/app.module.ts              |  4 +-
 .../app/password-modification.component.ts    | 60 +++++++++++++++++++
 core/class/class_security.php                 | 18 +++++-
 sql/data_fr.sql                               |  2 +-
 sql/develop.sql                               |  4 +-
 sql/structure.sql                             |  2 +-
 src/core/models/PasswordModel.php             |  4 +-
 10 files changed, 121 insertions(+), 15 deletions(-)
 create mode 100644 apps/maarch_entreprise/Views/password-modification.component.html
 create mode 100644 apps/maarch_entreprise/js/angular/app/password-modification.component.ts

diff --git a/apps/maarch_entreprise/Views/password-modification.component.html b/apps/maarch_entreprise/Views/password-modification.component.html
new file mode 100644
index 00000000000..8b607ef09a8
--- /dev/null
+++ b/apps/maarch_entreprise/Views/password-modification.component.html
@@ -0,0 +1,24 @@
+<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.myProfile}}
+            <small [class.hide-for-mobile]="mobileQuery.matches">{{user.firstname}} {{user.lastname}}</small>
+        </h1>
+        <span style="flex: 1 1 auto;"></span>
+        <menu-top></menu-top>
+        <button mat-icon-button (click)="snav2.toggle()">
+            <mat-icon class="fa fa-cog fa-2x"></mat-icon>
+        </button>
+    </mat-toolbar>
+    <mat-sidenav-container class="admin-sidenav-container" [style.marginTop.px]="mobileQuery.matches ? 56 : 0">
+        <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-card>
+        </mat-sidenav-content>
+    </mat-sidenav-container>
+</div>
\ No newline at end of file
diff --git a/apps/maarch_entreprise/index.php b/apps/maarch_entreprise/index.php
index 9dc0081bc56..837374dda96 100755
--- a/apps/maarch_entreprise/index.php
+++ b/apps/maarch_entreprise/index.php
@@ -335,7 +335,7 @@ if (file_exists($path)) {
                 && $_SESSION['abs_user_status'] == true) {
                 include
                     'modules/basket/advert_missing.php';
-            } else {
+            } elseif (empty($_REQUEST['trigger'])) {
                 $core->insert_page();
             }
             ?>
@@ -359,7 +359,9 @@ if (file_exists($path)) {
     </div>
 </body>
     <?php
-    if ($_SESSION['user']['UserId'] == 'superadmin' && !empty($_REQUEST['administration'])) {
+    if (!empty($_REQUEST['trigger']) && $_REQUEST['trigger'] == 'changePass') {
+        ?><script>triggerAngular('#/password-modification')</script><?php
+    } elseif ($_SESSION['user']['UserId'] == 'superadmin' && !empty($_REQUEST['administration'])) {
         ?>
         <script>triggerAngular('#/administration')</script>
     <?php
diff --git a/apps/maarch_entreprise/js/angular/app/app-routing.module.ts b/apps/maarch_entreprise/js/angular/app/app-routing.module.ts
index 52fa0a3905c..edca9400eef 100755
--- a/apps/maarch_entreprise/js/angular/app/app-routing.module.ts
+++ b/apps/maarch_entreprise/js/angular/app/app-routing.module.ts
@@ -1,15 +1,17 @@
-import { NgModule }              from '@angular/core';
-import { RouterModule }  from '@angular/router';
+import { NgModule }                         from '@angular/core';
+import { RouterModule }                     from '@angular/router';
 
-import { ProfileComponent }                     from './profile.component';
-import { SignatureBookComponent }  from './signature-book.component';
-import { SaveNumericPackageComponent }  from './save-numeric-package.component';
+import { ProfileComponent }                 from './profile.component';
+import { PasswordModificationComponent }    from './password-modification.component';
+import { SignatureBookComponent }           from './signature-book.component';
+import { SaveNumericPackageComponent }      from './save-numeric-package.component';
 
 
 @NgModule({
     imports: [
         RouterModule.forRoot([
             { path: 'profile', component: ProfileComponent },
+            { path: 'password-modification', component: PasswordModificationComponent },
             { path: 'saveNumericPackage', component: SaveNumericPackageComponent },
             { path: 'groups/:groupId/baskets/:basketId/signatureBook/:resId', component: SignatureBookComponent },
             { path: '**',   redirectTo: '', pathMatch: 'full' },
diff --git a/apps/maarch_entreprise/js/angular/app/app.module.ts b/apps/maarch_entreprise/js/angular/app/app.module.ts
index 71ac7c732c4..b8f41b0675d 100755
--- a/apps/maarch_entreprise/js/angular/app/app.module.ts
+++ b/apps/maarch_entreprise/js/angular/app/app.module.ts
@@ -10,6 +10,7 @@ import { AppRoutingModule }                     from './app-routing.module';
 import { AdministrationModule }                 from './administration/administration.module';
 
 import { ProfileComponent }                     from './profile.component';
+import { PasswordModificationComponent }        from './password-modification.component';
 import { SignatureBookComponent, SafeUrlPipe }  from './signature-book.component';
 import { SaveNumericPackageComponent }          from './save-numeric-package.component';
 
@@ -22,9 +23,10 @@ import { SaveNumericPackageComponent }          from './save-numeric-package.com
     declarations: [
         AppComponent,
         ProfileComponent,
-        SaveNumericPackageComponent,
+        PasswordModificationComponent,
         SignatureBookComponent,
         SafeUrlPipe,
+        SaveNumericPackageComponent,
         CustomSnackbarComponent,
         ConfirmModalComponent
     ],
diff --git a/apps/maarch_entreprise/js/angular/app/password-modification.component.ts b/apps/maarch_entreprise/js/angular/app/password-modification.component.ts
new file mode 100644
index 00000000000..34e2091a72d
--- /dev/null
+++ b/apps/maarch_entreprise/js/angular/app/password-modification.component.ts
@@ -0,0 +1,60 @@
+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';
+import { MatDialog } from '@angular/material';
+
+declare function $j(selector: any): any;
+
+declare var tinymce: any;
+declare var angularGlobals: any;
+
+
+@Component({
+    templateUrl: "../../../Views/password-modification.component.html",
+    providers: [NotificationService]
+})
+export class PasswordModificationComponent implements OnInit {
+
+    private _mobileQueryListener: () => void;
+    mobileQuery                 : MediaQueryList;
+
+    coreUrl         : string;
+    lang            : any = LANG;
+    loading         : boolean = false;
+
+    passwordModel   : any = {
+        currentPassword : "",
+        newPassword     : "",
+        reNewPassword   : "",
+    };
+
+    constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher, public http: HttpClient, private notify: NotificationService, public dialog: MatDialog) {
+        $j("link[href='merged_css.php']").remove();
+        this.mobileQuery = media.matchMedia('(max-width: 768px)');
+        this._mobileQueryListener = () => changeDetectorRef.detectChanges();
+        this.mobileQuery.addListener(this._mobileQueryListener);
+    }
+
+    prepare() {
+        $j('#inner_content').remove();
+        $j('#inner_content_contact').parent('div').remove(); 
+        $j('#inner_content_contact').remove(); 
+        $j('#menunav').hide();
+        $j('#divList').remove();
+        $j('#magicContactsTable').remove();
+        $j('#manageBasketsOrderTable').remove();
+        $j('#controlParamTechnicTable').remove();
+        $j('#container').width("99%");
+        if ($j('#content h1')[0] && $j('#content h1')[0] != $j('my-app h1')[0]) {
+            $j('#content h1')[0].remove();
+        }
+    }
+
+    ngOnInit(): void {
+        this.prepare();
+        this.coreUrl = angularGlobals.coreUrl;
+
+    }
+}
diff --git a/core/class/class_security.php b/core/class/class_security.php
index 75a6d012e56..444d7464b21 100755
--- a/core/class/class_security.php
+++ b/core/class/class_security.php
@@ -229,12 +229,28 @@ class security extends Database
                     );
                 }
 
+                $passwordRules = \SrcCore\models\PasswordModel::getEnabledRules();
+
+                if (!empty($passwordRules['renewal'])) {
+                    $currentDate = new \DateTime();
+                    $lastModificationDate = new \DateTime($user->__get('password_modification_date'));
+                    $lastModificationDate->add(new DateInterval("P{$passwordRules['renewal']}D"));
+
+                    if ($currentDate > $lastModificationDate) {
+                        return [
+                            'user'  => $array,
+                            'error' => $error,
+                            'url'   => 'index.php?trigger=changePass',
+                        ];
+                    }
+                }
+
                 $loggingMethod = \SrcCore\models\CoreConfigModel::getLoggingMethod();
                 if ($array['change_pass'] == 'Y' && !in_array($loggingMethod['id'], ['sso', 'cas', 'ldap', 'ozwillo'])) {
                     return array(
                         'user' => $array,
                         'error' => $error,
-                        'url' => 'index.php?display=true&page=change_pass',
+                        'url' => 'index.php?trigger=changePass',
                     );
                 } elseif (isset($_SESSION['requestUri'])
                     && trim($_SESSION['requestUri']) != ''
diff --git a/sql/data_fr.sql b/sql/data_fr.sql
index edf9fb3b576..0ceabae4dcb 100755
--- a/sql/data_fr.sql
+++ b/sql/data_fr.sql
@@ -1756,7 +1756,7 @@ INSERT INTO password_rules (label, "value") VALUES ('complexityNumber', 0);
 INSERT INTO password_rules (label, "value") VALUES ('complexitySpecial', 0);
 INSERT INTO password_rules (label, "value") VALUES ('lockAttempts', 3);
 INSERT INTO password_rules (label, "value") VALUES ('lockTime', 5);
-INSERT INTO password_rules (label, "value") VALUES ('useNumber', 2);
+INSERT INTO password_rules (label, "value") VALUES ('historyLastUse', 2);
 INSERT INTO password_rules (label, "value") VALUES ('renewal', 90);
 
 
diff --git a/sql/develop.sql b/sql/develop.sql
index 995e320185f..41ce64997fe 100644
--- a/sql/develop.sql
+++ b/sql/develop.sql
@@ -98,10 +98,10 @@ INSERT INTO password_rules (label, "value") VALUES ('complexityNumber', 0);
 INSERT INTO password_rules (label, "value") VALUES ('complexitySpecial', 0);
 INSERT INTO password_rules (label, "value") VALUES ('lockAttempts', 3);
 INSERT INTO password_rules (label, "value") VALUES ('lockTime', 5);
-INSERT INTO password_rules (label, "value") VALUES ('useNumber', 2);
+INSERT INTO password_rules (label, "value") VALUES ('historyLastUse', 2);
 INSERT INTO password_rules (label, "value") VALUES ('renewal', 90);
 ALTER TABLE users DROP COLUMN IF EXISTS password_modification_date;
-ALTER TABLE users ADD COLUMN password_modification_date timestamp without time zone;
+ALTER TABLE users ADD COLUMN password_modification_date timestamp without time zone DEFAULT CURRENT_TIMESTAMP;
 ALTER TABLE users DROP COLUMN IF EXISTS failed_authentication;
 ALTER TABLE users ADD COLUMN failed_authentication INTEGER DEFAULT 0;
 ALTER TABLE users DROP COLUMN IF EXISTS locked_until;
diff --git a/sql/structure.sql b/sql/structure.sql
index c147c0a3330..644231b085b 100755
--- a/sql/structure.sql
+++ b/sql/structure.sql
@@ -227,7 +227,7 @@ CREATE TABLE users
   status character varying(10) NOT NULL DEFAULT 'OK'::character varying,
   enabled character(1) NOT NULL DEFAULT 'Y'::bpchar,
   change_password character(1) NOT NULL DEFAULT 'Y'::bpchar,
-  password_modification_date timestamp without time zone,
+  password_modification_date timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
   loginmode character varying(50) DEFAULT NULL::character varying,
   cookie_key character varying(255) DEFAULT NULL::character varying,
   cookie_date timestamp without time zone,
diff --git a/src/core/models/PasswordModel.php b/src/core/models/PasswordModel.php
index 21090c9bf27..8317b716538 100644
--- a/src/core/models/PasswordModel.php
+++ b/src/core/models/PasswordModel.php
@@ -94,14 +94,14 @@ class PasswordModel
 
         $passwordRules = PasswordModel::getEnabledRules();
 
-        if (!empty($passwordRules['useNumber'])) {
+        if (!empty($passwordRules['historyLastUse'])) {
             $passwordHistory = DatabaseModel::select([
                 'select'    => ['password'],
                 'table'     => ['password_history'],
                 'where'     => ['user_serial_id = ?'],
                 'data'      => [$aArgs['userSerialId']],
                 'order_by'  => ['id DESC'],
-                'limit'     => $passwordRules['useNumber']
+                'limit'     => $passwordRules['historyLastUse']
             ]);
 
             foreach ($passwordHistory as $value) {
-- 
GitLab