diff --git a/public/css/styles.css b/public/css/styles.css index 4259dfe96c46c1adc272a44aac7b596191dc64ba..7f44689ac04710bfd68c91096225d08c97c6664d 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -197,6 +197,97 @@ textarea { text-decoration: none; } +.overlay { + /* Position the overlay to cover the entire viewport */ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + /* Add background image or color for the overlay */ + background: rgba(0, 0, 0, 0.5); /* Semi-transparent black overlay */ + backdrop-filter: blur(5px); /* Apply a blur effect to the background */ + display: flex; + justify-content: center; /* Center content horizontally */ + align-items: center; /* Center content vertically */ +} + +.overlay .form { + position: fixed; + top: 0; + left: 0; +} + +.popup { + display: flex; + flex-direction: column; + background: white; + padding: 30px 40px 30px 40px; + width: 30%; + border-radius: 8px; + background: var(--neutral-grey-dark, #21252C); + margin-top: 5%; + margin-bottom: 5%; +} + +.popup p { + color: var(--neutral-grey-light, #BABDC3); + font-style: normal; + font-weight: 400; + text-align: center; +} + +.popup div { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 30px; +} + +.button-delete { + border:none; + border-radius: 8px; + background: #eb5050; + color: white; + width: 100%; + padding-top: 10px; + padding-bottom: 10px; + transition: all 0.5s; + cursor: pointer; + font-weight: bold; + margin-top: 20px; + margin-bottom: 20px; + align-self: stretch; +} + +.button-delete:hover {background-color: #ff9898} + +.button-delete:active { + background-color: #b63131; +} + +.button-cancel { + border:none; + border-radius: 8px; + background: var(--primary-base, #5360DC); + color: white; + width: 100%; + padding-top: 10px; + padding-bottom: 10px; + transition: all 0.5s; + cursor: pointer; + font-weight: bold; + margin-top: 20px; + margin-bottom: 20px; + align-self: stretch; +} + +.button-cancel:hover {background-color: #7580e3} + +.button-cancel:active { + background-color: #313c9f; +} + @media only screen and (max-width: 800px) { .form-container { width: 100%; diff --git a/src/App.php b/src/App.php index 4967f24232620d06799e260999f890b7fd9d87e8..dc25c013d8dcfd306eb7b1f60a8491608ba1367a 100644 --- a/src/App.php +++ b/src/App.php @@ -12,6 +12,7 @@ use app\controllers\ProfileController; use app\controllers\ReviewController; use app\controllers\RegisterController; use app\controllers\UpdateFilmController; +use app\controllers\UserDashboardController; use app\repositories\UserRepository; use app\repositories\ReviewRepository; use app\services\UserService; @@ -41,5 +42,6 @@ class App $this->router->addRoute('/add-film', CreateFilmController::class); $this->router->addRoute('/update-film', UpdateFilmController::class); $this->router->addRoute('/profile', ProfileController::class); + $this->router->addRoute('/user-dashboard', UserDashboardController::class); } } diff --git a/src/base/BaseRepository.php b/src/base/BaseRepository.php index 9b38df918b0939e2f420d31139d5d874f0200bfb..88b5930e65a2bf08099207e1d1760aa41717ff95 100644 --- a/src/base/BaseRepository.php +++ b/src/base/BaseRepository.php @@ -242,7 +242,8 @@ abstract class BaseRepository $sql .= "$primaryKey = :primaryKey"; $stmt = $this->pdo->prepare($sql); - $stmt->bindValue(":primaryKey", $model->get('$primaryKey'), PDO::PARAM_INT); + $stmt->bindValue(":primaryKey", $model->get($primaryKey), PDO::PARAM_INT); + $stmt->execute(); return $stmt->rowCount(); diff --git a/src/controllers/ProfileController.php b/src/controllers/ProfileController.php index fc9f2daff2c8a7fc1e2ac74d5372934161fc1a55..aa4e92abb1c41d38944267e24f47a408e6a06ded 100644 --- a/src/controllers/ProfileController.php +++ b/src/controllers/ProfileController.php @@ -57,11 +57,12 @@ class ProfileController extends BaseController // Call service $response = $this->service->update($user); - echo $response; $msg = ""; - $_SESSION['username'] = $username; - $msg = "Successfully updated profile!"; + if ($response != null) { + $_SESSION['username'] = $username; + $msg = "Successfully updated profile!"; + } // Render response parent::redirect("/", ["Msg" => $msg]); diff --git a/src/controllers/UserDashboardController.php b/src/controllers/UserDashboardController.php new file mode 100644 index 0000000000000000000000000000000000000000..0e15cea28304fbc1369be961d94a637629481d05 --- /dev/null +++ b/src/controllers/UserDashboardController.php @@ -0,0 +1,142 @@ +<?php + +namespace app\controllers; + +use app\base\BaseController; +use app\exceptions\BadRequestException; +use app\services\UserService; +use Exception; + +class UserDashboardController extends BaseController +{ + public function __construct() + { + parent::__construct(UserService::getInstance()); + } + + protected function get($urlParams) + { + if (!isset($_SESSION['role']) or $_SESSION['role'] != 'admin') { + // TODO: make error controller + parent::redirect("/error", [], 401); + return; + } + $urlParams['users'] = $this->service->getAllUser(); + if (isset($urlParams['context']) and $urlParams['context'] == 'update') { + $user = $this->service->getById($urlParams['user_id']); + if ($urlParams['action'] == 'edit') { + $urlParams['email'] = $user->email; + $urlParams['username'] = $user->username; + parent::render($urlParams, "update-user", "layouts/base"); + } + if ($urlParams['action'] == 'delete') { + $urlParams['username'] = $user->username; + parent::render($urlParams, "delete-user", "layouts/base"); + } + unset($urlParams['context']); + } else { + + parent::render($urlParams, "user-dashboard", "layouts/base"); + } + } + + protected function post($urlParams) + { + if (!isset($_SESSION['role']) or $_SESSION['role'] != 'admin') { + parent::redirect("/error", [], 401); + return; + } + if (isset($urlParams['context']) and $urlParams['context'] == 'update') { + if ($urlParams['action'] == 'edit') { + try { + $user = $this->service->getById($urlParams['user_id']); + $old_pass = $user->password; + + // Get data + $email = $_POST['email']; + $username = $_POST['username']; + $password = $_POST['password'] ? $_POST['password'] : $old_pass; + $confirm_password = $_POST['confirm-password'] ? $_POST['confirm-password'] : $old_pass; + + if ($this->service->isEmailExist($email) and $user->email != $email) { + throw new BadRequestException("Email Already Exists!"); + } + + if ($this->service->isUsernameExist($username) and $user->username != $username) { + throw new BadRequestException("Username Already Exists!"); + } + + if ($password != $confirm_password) { + throw new BadRequestException("Password does not match!"); + } + + $user + ->set('email', $email) + ->set('username', $username) + ->set('password', $_POST['password'] ? password_hash($password, PASSWORD_DEFAULT) : $password); + + // Call service + $response = $this->service->update($user); + + if ($response == 1) { + $msg = "User updated successfully!"; + $urlParams['msg'] = $msg; + } + + // Unset the parameters + unset($urlParams['context']); + unset($urlParams['action']); + unset($urlParams['user_id']); + // Redirect to own link, but with no params + parent::redirect("/user-dashboard", $urlParams); + } catch (Exception $e) { + $msg = $e->getMessage(); + $urlParams['errorMsg'] = $msg; + parent::redirect("/user-dashboard", $urlParams); + } + } + if ($urlParams['action'] == 'delete') { + try { + $user = $this->service->getById($urlParams['user_id']); + $confirm_delete = $_POST['delete_confirm']; + + if ($confirm_delete == 'yes') { + $response = $this->service->deleteById($user->user_id); + if ($response == 1) { + $msg = "User $user->username deleted successfully"; + $urlParams['msg'] = $msg; + } + // Unset the parameters + unset($urlParams['context']); + unset($urlParams['action']); + unset($urlParams['user_id']); + unset($urlParams['delete_confirm']); + // Redirect to own link, but with no params + parent::redirect("/user-dashboard", $urlParams); + } else { + // Unset the parameters + unset($urlParams['context']); + unset($urlParams['action']); + unset($urlParams['user_id']); + unset($urlParams['delete_confirm']); + // Redirect to own link, but with no params + parent::redirect("/user-dashboard", $urlParams); + } + } catch (Exception $e) { + $msg = $e->getMessage(); + $urlParams['errorMsg'] = $msg; + parent::redirect("/user-dashboard", $urlParams); + } + } + } else { + $action = $_POST['action']; + $user_id = $_POST['user_id']; + + $urlParams = ['context' => 'update']; + $urlParams['action'] = $action; + $urlParams['user_id'] = $user_id; + + parent::redirect("/user-dashboard", $urlParams); + } + } +} diff --git a/src/repositories/UserRepository.php b/src/repositories/UserRepository.php index b72034e63f37bb7d05d32be09de6dd0fd381e4ed..ac11ac52baa060f15f90cadd4932f0bd9ec510e2 100644 --- a/src/repositories/UserRepository.php +++ b/src/repositories/UserRepository.php @@ -3,6 +3,7 @@ namespace app\repositories; use app\base\BaseRepository; +use app\models\UserModel; use PDO; class UserRepository extends BaseRepository @@ -36,4 +37,12 @@ class UserRepository extends BaseRepository { return $this->findOne(['username' => [$username, PDO::PARAM_STR]]); } + + public function deleteById($user_id) + { + $user = $this->getById($user_id); + $userModel = new UserModel(); + $userModel->constructFromArray($user); + return $this->delete($userModel); + } } diff --git a/src/services/UserService.php b/src/services/UserService.php index f3dccab139ba0b3adac590fee428c3b641dbba8f..d92c14fbe0b4e9834d92318425f6fb67b2ec1c06 100644 --- a/src/services/UserService.php +++ b/src/services/UserService.php @@ -202,4 +202,9 @@ class UserService extends BaseService $arrParams['role'] = PDO::PARAM_STR; $this->repository->update($user, $arrParams); } + + public function deleteById($user_id) + { + $this->repository->deleteById($user_id); + } } diff --git a/views/delete-user.php b/views/delete-user.php new file mode 100644 index 0000000000000000000000000000000000000000..41a47cfebcbc7a39d53122a781fb6ca4c08f6249 --- /dev/null +++ b/views/delete-user.php @@ -0,0 +1,63 @@ +<div> + <table class='user-list'> + <tr> + <th>User Id</th> + <th>Username</th> + <th>Email</th> + <th>Role</th> + <th>Actions</th> + </tr> + <? + foreach ($users as $user) { + echo + "<tr class='user-card'> + <td> + $user->user_id + </td> + <td> + $user->username + </td> + <td> + $user->email + </td> + <td> + $user->role + </td> + <td> + <form method='post'> + <input type='hidden' name='action' value='edit'> + <input type='hidden' name='user_id' value='$user->user_id'> + <button type='submit'>edit</button> + </form> + </td> + <td> + <form method='post'> + <input type='hidden' name='action' value='delete'> + <input type='hidden' name='user_id' value='$user->user_id'> + <button type='submit'>delete</button> + </form> + </td> + </tr>"; + } + ?> + +</div> +<div class="overlay"> + <div class="popup"> + <h1 class="header-title">Are you sure?</h1> + <p class="error-msg"><?php if (isset($errorMsg)) { + echo "$errorMsg"; + } ?></p> + <p>User <?= $username ?> will be deleted forever!</p> + <div> + <form method='post' enctype="multipart/form-data"> + <input type='hidden' name='delete_confirm' value='yes'> + <button type="submit" class="button-delete">Delete</button> + </form> + <form method='post' enctype="multipart/form-data"> + <input type='hidden' name='delete_confirm' value='no'> + <button type="submit" class="button-cancel">Cancel</button> + </form> + </div> + </div> +</div> \ No newline at end of file diff --git a/views/update-film.php b/views/update-film.php index 19bf090b2e3da8ff61bf2d29462bfbfbbd03ffcb..5d08719393416882f738073956e447b54df2ac09 100644 --- a/views/update-film.php +++ b/views/update-film.php @@ -1,5 +1,5 @@ <div class="form-container"> - <h2 class="header-title">Add Film</h2> + <h2 class="header-title">Update Film</h2> <p class="error-msg"><?php if (isset($errorMsg)) { echo "$errorMsg"; } ?></p> diff --git a/views/update-user.php b/views/update-user.php new file mode 100644 index 0000000000000000000000000000000000000000..40e482c75338f1b0d2f6dd9ac15bf9409ac42373 --- /dev/null +++ b/views/update-user.php @@ -0,0 +1,31 @@ +<div class="form-container"> + <h2 class="header-title">Update User</h2> + <p class="error-msg"><?php if (isset($errorMsg)) { + echo "$errorMsg"; + } ?></p> + <form class="form" method="post" enctype="multipart/form-data"> + <div class="form-group"> + <label for="email">Email</label> + <br> + <input class="input" type="text" id="email" name="email" value="<?= $email ?>" required> + </div> + <div class="form-group"> + <label for="username">Username</label> + <br> + <input class="input" type="text" id="username" name="username" value="<?= $username ?>" required> + </div> + <div class="form-group"> + <label for="password">Password</label> + <br> + <input class="input" type="password" id="password" name="password"> + </div> + <div class="form-group"> + <label for="confirm-password">Confirm Password</label> + <br> + <input class="input" type="password" id="confirm-password" name="confirm-password"> + </div> + <div class="form-group"> + <button class="button" ctype="submit">Update</button> + </div> + </form> +</div> \ No newline at end of file diff --git a/views/user-dashboard.php b/views/user-dashboard.php new file mode 100644 index 0000000000000000000000000000000000000000..1f56ad88939d03af741308e21c6919172920a7a4 --- /dev/null +++ b/views/user-dashboard.php @@ -0,0 +1,46 @@ +<div> + <p class="error-msg"><?php if (isset($errorMsg)) { + echo "$errorMsg"; + } ?></p> + <table class='user-list'> + <tr> + <th>User Id</th> + <th>Username</th> + <th>Email</th> + <th>Role</th> + <th>Actions</th> + </tr> + <? + foreach ($users as $user) { + echo + "<tr class='user-card'> + <td> + $user->user_id + </td> + <td> + $user->username + </td> + <td> + $user->email + </td> + <td> + $user->role + </td> + <td> + <form method='post'> + <input type='hidden' name='action' value='edit'> + <input type='hidden' name='user_id' value='$user->user_id'> + <button type='submit'>edit</button> + </form> + </td> + <td> + <form method='post'> + <input type='hidden' name='action' value='delete'> + <input type='hidden' name='user_id' value='$user->user_id'> + <button type='submit'>delete</button> + </form> + </td> + </tr>"; + } + ?> +</div> \ No newline at end of file