From c91765e8283352f819aad60defe853e4233589d5 Mon Sep 17 00:00:00 2001
From: mwalbeck <magn3200@gmail.com>
Date: Tue, 1 Nov 2016 16:38:38 +0100
Subject: [PATCH] Added reset password functionality, and added a random
 password generator function

---
 .../AdministrativeUserController.php          | 14 ++++++++++
 app/Policies/UserPolicy.php                   |  8 ++++++
 app/User.php                                  | 28 ++++++++++++++++---
 public/js/app.js                              | 10 +++++--
 resources/views/shared/delete-modal.blade.php |  4 +--
 .../shared/reset-password-modal.blade.php     | 16 +++++++++++
 resources/views/users/show.blade.php          |  3 ++
 routes/web.php                                |  2 ++
 8 files changed, 76 insertions(+), 9 deletions(-)
 create mode 100644 resources/views/shared/reset-password-modal.blade.php

diff --git a/app/Http/Controllers/AdministrativeUserController.php b/app/Http/Controllers/AdministrativeUserController.php
index 398a46a..2da6136 100644
--- a/app/Http/Controllers/AdministrativeUserController.php
+++ b/app/Http/Controllers/AdministrativeUserController.php
@@ -88,6 +88,20 @@ class AdministrativeUserController extends Controller
         return redirect("/" . Auth::user()->getAdminPath() . "/users/group/$user->group_id");
     }
 
+    /**
+     *
+     * Function for reset a users password
+     *
+     */
+    public function resetUserPassword(User $user, Request $request)
+    {
+        $this->authorize('resetPassword', $user);
+
+        $user->resetPassword();
+        $request->session()->flash('status', 'The password was successfully reset!');
+        return redirect("/" . Auth::user()->getAdminPath() . "/users/$user->id");
+    }
+
     public function deleteUser(User $user, Request $request)
     {
         $this->authorize('delete', $user);
diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php
index b632bc2..5499df6 100644
--- a/app/Policies/UserPolicy.php
+++ b/app/Policies/UserPolicy.php
@@ -43,6 +43,14 @@ class UserPolicy
         return false;
     }
 
+    public function resetPassword(User $user, User $user2)
+    {
+        if ($user->isAdministrator() || ($user->isModerator() AND $user->group_id === $user2->group_id AND !$user2->isAdministrator())) {
+            return true;
+        }
+        return false;
+    }
+
     public function delete(User $user, User $user2)
     {
         if ($user->isAdministrator() || ($user->isModerator() AND $user->group_id === $user2->group_id AND !$user2->isAdministrator()) || $user === $user2) {
diff --git a/app/User.php b/app/User.php
index 6c540ec..0274df5 100644
--- a/app/User.php
+++ b/app/User.php
@@ -47,7 +47,7 @@ class User extends Authenticatable
 
     public function passwordHash($password)
     {
-        $this->password = password_hash($password, PASSWORD_DEFAULT);
+        return password_hash($password, PASSWORD_DEFAULT);
     }
 
     public function passwordVerify($password)
@@ -55,6 +55,26 @@ class User extends Authenticatable
         return password_verify($password, $this->password);
     }
 
+    public function generatePassword(Int $length)
+    {
+        $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyz";
+        $password = "";
+        $char_max = strlen($chars) - 1;
+
+        for ($i = 0; $i < $length; ++$i) {
+            $password .= $chars[random_int(0, $char_max)];
+        }
+
+        return $password;
+    }
+
+    public function resetPassword()
+    {
+        $this->password = $this->passwordHash($this->generatePassword(10));
+        $this->update();
+        return true;
+    }
+
     public function isModerator()
     {
         if ($this->access_level === 2) {
@@ -80,7 +100,7 @@ class User extends Authenticatable
     {
         $this->name = $request["name"];
         $this->email = trim($request["email"]);
-        $this->passwordHash($request["password"]);
+        $this->password = $this->passwordHash($request["password"]);
         $this->enabled = $request["enabled"];
         $this->access_level = $request["access_level"];
 
@@ -108,7 +128,7 @@ class User extends Authenticatable
         $this->enabled = $request["enabled"];
 
         if ($request["password"]) {
-            $this->passwordHash($request["password"]);
+            $this->password = $this->passwordHash($request["password"]);
         }
 
         if (Auth::user()->isAdministrator()) {
@@ -143,7 +163,7 @@ class User extends Authenticatable
 
     public function updatePassword($password)
     {
-        $this->passwordHash($password);
+        $this->password = $this->passwordHash($password);
         $this->update();
     }
 
diff --git a/public/js/app.js b/public/js/app.js
index 2f35381..b7b020d 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -23,9 +23,15 @@ $('.delete-modal').on('show.bs.modal', function (event) {
       var button = $(event.relatedTarget); // Button that triggered the modal
       var delete_url = button.data('url'); // Extract info from data-* attributes
       var delete_id = button.data('id'); // Extract info from data-* attributes
-      // If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
-      // Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead.
       var modal = $(this);
       var admin_path = modal.find('#modal-button-delete').attr("formaction");
       modal.find('#modal-button-delete').attr("formaction", admin_path + delete_url + "/" + delete_id + "/delete");
+})
+
+$('.reset-password-modal').on('show.bs.modal', function (event) {
+      var button = $(event.relatedTarget); // Button that triggered the modal
+      var reset_password_id = button.data('id'); // Extract info from data-* attributes
+      var modal = $(this);
+      var admin_path = modal.find('#modal-button-reset-password').attr("formaction");
+      modal.find('#modal-button-reset-password').attr("formaction", admin_path + "users/" + reset_password_id + "/reset-password");
 })
\ No newline at end of file
diff --git a/resources/views/shared/delete-modal.blade.php b/resources/views/shared/delete-modal.blade.php
index 921e5c7..c76a274 100644
--- a/resources/views/shared/delete-modal.blade.php
+++ b/resources/views/shared/delete-modal.blade.php
@@ -6,9 +6,7 @@
                 <h4 class="modal-title" id="myModalLabel">Are You Sure!</h4>
             </div>
             <div class="modal-body">
-                <form method="POST" class="">
-                    {{ csrf_field() }}
-                    {{ method_field('DELETE') }}
+                <form method="GET">
                     <button id="modal-button-delete" class="btn btn-danger" formaction="/{{ Auth::user()->getAdminPath() }}/">Yes</button>
                     <button type="button" class="btn btn-default" data-dismiss="modal">No</button>
                 </form>
diff --git a/resources/views/shared/reset-password-modal.blade.php b/resources/views/shared/reset-password-modal.blade.php
new file mode 100644
index 0000000..80ac40c
--- /dev/null
+++ b/resources/views/shared/reset-password-modal.blade.php
@@ -0,0 +1,16 @@
+<div class="modal fade reset-password-modal" tabindex="-1" role="dialog" aria-labelledby="reset-password-modal">
+    <div class="modal-dialog modal-sm" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="myModalLabel">Are You Sure!</h4>
+            </div>
+            <div class="modal-body">
+                <form method="GET">
+                    <button id="modal-button-reset-password" class="btn btn-danger" formaction="/{{ Auth::user()->getAdminPath() }}/">Yes</button>
+                    <button type="button" class="btn btn-default" data-dismiss="modal">No</button>
+                </form>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/resources/views/users/show.blade.php b/resources/views/users/show.blade.php
index 2b1fd3b..9be479c 100644
--- a/resources/views/users/show.blade.php
+++ b/resources/views/users/show.blade.php
@@ -4,6 +4,8 @@
 
 @include('shared.delete-modal')
 
+@include('shared.reset-password-modal')
+
 <div class="container-fluid">
     <div class="row">
         <div class="col-md-6 col-md-offset-3">
@@ -17,6 +19,7 @@
                             <form method="get">
                                 <button type="button" class="btn btn-sm btn-danger pull-right" data-toggle="modal" data-target=".delete-modal" data-url="users" data-id="{{ $user->id }}">Delete</button>
                                 <button class="btn btn-sm btn-default pull-right" formaction="/{{ Auth::user()->getAdminPath() }}/users/{{ $user->id }}/edit">Edit</button>
+                                <button type="button" class="btn btn-sm btn-default pull-right" data-toggle="modal" data-target=".reset-password-modal" data-id="{{ $user->id }}">Reset Password</button>
                             </form>
                         @endif
                         <strong>Name:</strong><br>
diff --git a/routes/web.php b/routes/web.php
index 03ed71a..49ea675 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -67,6 +67,7 @@ Route::group(['prefix' => 'mod', 'middleware' => 'is.mod'], function () {
     Route::get('/users/{user}', 'AdministrativeUserController@showUser');
     Route::get('/users/{user}/edit', 'AdministrativeUserController@editUser');
     Route::post('/users/{user}/edit', 'AdministrativeUserController@updateUser');
+    Route::get('/users/{user}/reset-password', 'AdministrativeUserController@resetUserPassword');
     Route::delete('/users/{user}/delete', 'AdministrativeUserController@deleteUser');
 
     Route::get('/groups/{group}', 'GroupController@showGroup');
@@ -103,6 +104,7 @@ Route::group(['prefix' => 'admin', 'middleware' => 'is.admin'], function () {
     Route::get('/users/{user}', 'AdministrativeUserController@showUser');
     Route::get('/users/{user}/edit', 'AdministrativeUserController@editUser');
     Route::post('/users/{user}/edit', 'AdministrativeUserController@updateUser');
+    Route::get('/users/{user}/reset-password', 'AdministrativeUserController@resetUserPassword');
     Route::delete('/users/{user}/delete', 'AdministrativeUserController@deleteUser');
 
     Route::get('/groups', 'GroupController@showGroups');