diff --git a/index.php b/index.php index ad772b154e24cab9685b35b655a13ff291aeb372..02c05a2f8ee43d34de01ea89cbb312cc95b209a8 100644 --- a/index.php +++ b/index.php @@ -11,12 +11,12 @@ require_once PROJECT_ROOT_PATH . "/src/controllers/auth/LogoutController.php"; require_once PROJECT_ROOT_PATH . "/src/controllers/auth/RegisterController.php"; require_once PROJECT_ROOT_PATH . "/src/controllers/cat/CatController.php"; require_once PROJECT_ROOT_PATH . "/src/controllers/sightings/SightingController.php"; - +require_once PROJECT_ROOT_PATH . "/src/controllers/user/UserController.php"; session_start(); $router = new Router(); -$router->route("/", HomeController::getInstance(), ["POST"=>"admin", "PUT"=>"auth"]); +$router->route("/", HomeController::getInstance(), ["POST" => "admin", "PUT" => "auth"]); $router->route("/login", LoginController::getInstance(), []); $router->route("/register", RegisterController::getInstance(), []); $router->route("/logout", LogoutController::getInstance(), []); @@ -24,7 +24,8 @@ $router->route("/logout", LogoutController::getInstance(), []); $router->route("/cat", CatController::getInstance(), []); $router->route("/cat/*", CatController::getInstance(), []); -$router->route("/sighting",SightingController::getInstance(),[]); - -$router->run($_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD']); +$router->route("/sighting", SightingController::getInstance(), []); +$router->route("/user", UserController::getInstance(), ["GET" => "admin"]); +$router->route("/user/*", UserController::getInstance(), ["POST" => "admin", "PUT" => "admin", "DELETE" => "admin"]); +$router->run($_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD']); \ No newline at end of file diff --git a/public/components/Navbar.php b/public/components/Navbar.php index 62d17756b1168e61da1b2ac3e86d6a58f6db4a5b..e09ed430ff67e8aef7087e74997ee52bd7a87f16 100644 --- a/public/components/Navbar.php +++ b/public/components/Navbar.php @@ -6,9 +6,9 @@ <?php // Check if the user is logged in (You will need to implement this logic) $loggedIn = isset($_SESSION['user_id']); - $isAdmin = isset($_SESSION['isAdmin']); + $isAdmin = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === 1; if ($isAdmin) { - echo '<li><a href="admin">Manage Users</a></li>'; + echo '<li><a href="user">Manage Users</a></li>'; } if ($loggedIn) { echo '<li><a href="logout">Logout</a></li>'; diff --git a/public/components/Pagination.php b/public/components/Pagination.php index cdbe6c40a969b7c03ac47b174737bbac07be3437..c986446d880568c0df8c3b1271889ff65b695817 100644 --- a/public/components/Pagination.php +++ b/public/components/Pagination.php @@ -4,26 +4,30 @@ // 2. Di controller sebelum render page, query total count dari database simpan di variabel $_count. // 3. Pastiin di service/repo ada fungsi buat ngurusin order by, limit, dst. // For more information, refer to GET /cats di cats controller. -function generatePaginationLinks($currentPage, $totalPages) + +function generatePaginationLinks($currentPage, $totalPages, $queryParams) { $html = '<div class="pagination">'; + // Build the query string with the existing parameters + $queryString = http_build_query($queryParams); + // Previous button if ($currentPage > 1) { - $html .= '<a href="?pageNo=' . ($currentPage - 1) . '&pageSize=10" class="prev-page">Previous</a>'; + $html .= '<a href="?pageNo=' . ($currentPage - 1) . '&' . $queryString . '" class="prev-page">Previous</a>'; } for ($i = 1; $i <= $totalPages; $i++) { if ($i === $currentPage) { $html .= '<span class="current-page">' . $i . '</span>'; } else { - $html .= '<a href="?pageNo=' . $i . '&pageSize=10">' . $i . '</a>'; + $html .= '<a href="?pageNo=' . $i . '&' . $queryString . '">' . $i . '</a>'; } } // Next button if ($currentPage < $totalPages) { - $html .= '<a href="?pageNo=' . ($currentPage + 1) . '&pageSize=10" class="next-page">Next</a>'; + $html .= '<a href="?pageNo=' . ($currentPage + 1) . '&&' . $queryString . '" class="next-page">Next</a>'; } $html .= '</div>'; @@ -35,7 +39,73 @@ $pageSize = isset($_GET['pageSize']) ? intval($_GET['pageSize']) : 10; // Number $totalPages = ceil($totalCount / $pageSize); $currentPage = isset($_GET['pageNo']) ? intval($_GET['pageNo']) : 1; -$paginationHtml = generatePaginationLinks($currentPage, $totalPages); +// Check if the current URL is /cats +$currentUrl = $_SERVER['REQUEST_URI']; +$isCatsPage = strpos($currentUrl, '/cats') !== false; + +if ($isCatsPage) { + // Extract and preserve query parameters + $queryParams = [ + 'search' => $_GET['search'] ?? '', + 'gender' => $_GET['gender'] ?? '', + 'spayed' => $_GET['spayed'] ?? '', + 'isDesc' => $_GET['isDesc'] ?? '', + 'order' => $_GET['order'] ?? '', + 'pageSize' => $_GET['pageSize'] ?? '' + ]; + + $paginationHtml = generatePaginationLinks($currentPage, $totalPages, $queryParams); +} else { + // No query parameters + $paginationHtml = generatePaginationLinks($currentPage, $totalPages, ['pageSize' => $_GET['pageSize'] ?? '']); +} + +// // Extract and preserve query parameters +// $queryParams = [ +// 'search' => $_GET['search'] ?? '', +// 'gender' => $_GET['gender'] ?? '', +// 'spayed' => $_GET['spayed'] ?? '', +// 'isDesc' => $_GET['isDesc'] ?? '', +// 'order' => $_GET['order'] ?? '', +// 'pageSize' => $_GET['pageSize'] ?? '' +// ]; + +// $paginationHtml = generatePaginationLinks($currentPage, $totalPages, $queryParams); + + + +// function generatePaginationLinks($currentPage, $totalPages) +// { +// $html = '<div class="pagination">'; + +// // Previous button +// if ($currentPage > 1) { +// $html .= '<a href="?pageNo=' . ($currentPage - 1) . '&pageSize=10" class="prev-page">Previous</a>'; +// } + +// for ($i = 1; $i <= $totalPages; $i++) { +// if ($i === $currentPage) { +// $html .= '<span class="current-page">' . $i . '</span>'; +// } else { +// $html .= '<a href="?pageNo=' . $i . '&pageSize=10">' . $i . '</a>'; +// } +// } + +// // Next button +// if ($currentPage < $totalPages) { +// $html .= '<a href="?pageNo=' . ($currentPage + 1) . '&pageSize=10" class="next-page">Next</a>'; +// } + +// $html .= '</div>'; +// return $html; +// } + +// $totalCount = $_count; // Total number of cats +// $pageSize = (isset($_GET['pageSize']) && intval($_GET['pageSize']) != 0) ? intval($_GET['pageSize']) : 10; // Number of cats per page +// $totalPages = ceil($totalCount / $pageSize); +// $currentPage = isset($_GET['pageNo']) && $_GET['pageNo'] != 0 ? intval($_GET['pageNo']) : 1; + +// $paginationHtml = generatePaginationLinks($currentPage, $totalPages); ?> diff --git a/public/css/styles.css b/public/css/styles.css index 259c1984a77037156ba0270a7f0cbd923a60bc7c..f39b28da09a37e318209b6f9358104f5d46195ff 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -45,7 +45,7 @@ nav ul li a:hover { /* styles.css */ /* Style for the cat card container */ -.cat-card, .sighting-card { +.cat-card, .sighting-card, .user-card { border: 1px solid #ccc; padding: 16px; margin: 16px; @@ -66,13 +66,13 @@ nav ul li a:hover { } /* Style for the cat card title */ -.cat-title { +.cat-title, .user-card { font-size: 24px; margin: 8px 0; } /* Style for the cat card details */ -.cat-details { +.cat-details, .user-card { font-size: 16px; margin: 8px 0; } @@ -80,7 +80,7 @@ nav ul li a:hover { /* styles.css */ /* Style for the container that holds the cat cards */ -.cat-cards-container, .sighting-cards-container { +.cat-cards-container, .sighting-cards-container, .user-cards-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); /* Responsive grid with minimum 300px width */ grid-gap: 16px; /* Spacing between cat cards */ @@ -168,7 +168,7 @@ nav ul li a:hover { } */ /* Style for each cat card */ -.cat-card, .sighting-card { +.cat-card, .sighting-card, .user-card { position: relative; /* Add relative positioning to the cat card */ border: 1px solid #ccc; padding: 16px; diff --git a/public/js/users.js b/public/js/users.js new file mode 100644 index 0000000000000000000000000000000000000000..c0933b002695e10b95fe67a568ab74e8f144f2ec --- /dev/null +++ b/public/js/users.js @@ -0,0 +1,100 @@ +const editUserModal = document.getElementById("edit-user-modal"); + +function openEditUserModal() { + editUserModal.style.display = "block"; +} + +function closeEditUserModal() { + editUserModal.style.display = "none"; +} + +window.onclick = function (event) { + if (event.target === editUserModal) { + closeEditUserModal(); + } +} + +const editUserForm = document.getElementById("edit-user-form"); +editUserForm.addEventListener("submit", function (event) { + event.preventDefault(); + + const userId = document.getElementById("edit-user-id").value; + + const formData = new FormData(); + formData.append("nama", document.getElementById("edit-nama").value); + formData.append("email", document.getElementById("edit-email").value); + formData.append("username", document.getElementById("edit-username").value); + formData.append("isAdmin", document.getElementById("edit-isadmin").value); + + // Send a POST request to /user/{user_id} + fetch(`/user/${userId}`, { + method: "POST", + body: formData, + }) + .then((response) => { + if (response.ok) { + closeEditUserModal(); + location.reload(); + } else { + console.error("Error editing user:", response.statusText); + } + }) + .catch((error) => { + console.error("Error editing user:", error); + }); +}); + +// JavaScript to handle delete button click +document.addEventListener("DOMContentLoaded", function () { + const deleteButtons = document.querySelectorAll(".delete-button"); + + deleteButtons.forEach(function (button) { + button.addEventListener("click", function (event) { + let conf = confirm('Are you sure you want to delete this user?'); + if (!conf) { + event.preventDefault(); + return; + } + + const deleteUrl = button.getAttribute("href"); + + fetch(deleteUrl, { + method: "DELETE", + }) + .then(function (response) { + if (response.ok) { + location.reload(); + } else { + console.error("DELETE request failed."); + } + }) + .catch(function (error) { + console.error("Network error:", error); + }); + }); + }); +}); + +function editUser(userId) { + const userCard = document.getElementById(`user-card-${userId}`); + + if (userCard) { + populateEditForm(userCard, userId); + openEditUserModal(); + } else { + console.error("User card not found for userId:", userId); + } +} + +function populateEditForm(userCard, userId) { + const userName = userCard.querySelector(".user-title").textContent.trim(); + const userEmail = userCard.querySelector(".user-email").textContent.trim(); + const userUsername = userCard.querySelector(".user-username").textContent.trim(); + const userIsAdmin = userCard.querySelector(".user-isadmin").textContent.trim(); + + document.getElementById("edit-nama").value = userName; + document.getElementById("edit-email").value = userEmail; + document.getElementById("edit-username").value = userUsername; + document.getElementById("edit-isadmin").value = userIsAdmin; + document.getElementById("edit-user-id").value = userId; +} diff --git a/public/view/cats.php b/public/view/cats.php index 677e749f5ac774262f623b31b41a93dc7075ae29..198d530ae67e7b2512fab15220b37005aae76121 100644 --- a/public/view/cats.php +++ b/public/view/cats.php @@ -66,7 +66,11 @@ <div class="cat-cards-container"> <?php foreach ($responseCats as $cat): ?> <div class="cat-card" id="cat-card-<?= $cat['cat_id'] ?>"> - <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>">X</a> + <?php if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === 1): ?> + <!-- Edit and delete buttons for admin users --> + <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>">X</a> + <?php endif; ?> + <!-- <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>">X</a> --> <h2 class="cat-title"> <?= htmlspecialchars($cat['name']) ?> </h2> @@ -102,137 +106,143 @@ <source src="public/<?= htmlspecialchars($cat['sound_path']) ?>" type="audio/mp4"> <source src="public/<?= htmlspecialchars($cat['sound_path']) ?>" type="audio/mp3"> </audio> - <button class="edit-button" onclick="editCat(<?= $cat['cat_id'] ?>)">Edit</button> + <?php if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === 1): ?> + <!-- Edit and delete buttons for admin users --> + <button class="edit-button" onclick="editCat(<?= $cat['cat_id'] ?>)">Edit</button> + + <?php endif; ?> </div> <?php endforeach; ?> </div> <?php require_once(PROJECT_ROOT_PATH . '/public/components/Pagination.php'); ?> - <div> - <div id="edit-cat-modal" class="modal"> - <div class="modal-content"> - <span class="close" onclick="closeEditCatModal()">×</span> - <h2>Edit Cat</h2> - <form id="edit-cat-form" enctype="multipart/form-data"> - <input type="hidden" id="edit-cat-id" name="cat_id" class="form-control"> - <div class="form-group"> - <label for="name">Name:</label> - <input type="text" id="edit-name" name="name" class="form-control"> - </div> + <?php if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === 1): ?> + <div> + <div id="edit-cat-modal" class="modal"> + <div class="modal-content"> + <span class="close" onclick="closeEditCatModal()">×</span> + <h2>Edit Cat</h2> + <form id="edit-cat-form" enctype="multipart/form-data"> + <input type="hidden" id="edit-cat-id" name="cat_id" class="form-control"> + <div class="form-group"> + <label for="name">Name:</label> + <input type="text" id="edit-name" name="name" class="form-control"> + </div> - <div class="form-group"> - <label for="description">Description:</label> - <textarea id="edit-description" name="description" class="form-control"></textarea> - </div> + <div class="form-group"> + <label for="description">Description:</label> + <textarea id="edit-description" name="description" class="form-control"></textarea> + </div> - <div class="form-group"> - <label for="location">Location:</label> - <input type="text" id="edit-location" name="location" class="form-control"> - </div> + <div class="form-group"> + <label for="location">Location:</label> + <input type="text" id="edit-location" name="location" class="form-control"> + </div> - <div class="form-group"> - <label for="gender">Gender:</label> - <select id="edit-gender" name="gender" class="form-control"> - <option value="Male">Male</option> - <option value="Female">Female</option> - </select> - </div> + <div class="form-group"> + <label for="gender">Gender:</label> + <select id="edit-gender" name="gender" class="form-control"> + <option value="Male">Male</option> + <option value="Female">Female</option> + </select> + </div> - <div class="form-group"> - <label for="color">Color:</label> - <input type="text" id="edit-color" name="color" class="form-control"> - </div> + <div class="form-group"> + <label for="color">Color:</label> + <input type="text" id="edit-color" name="color" class="form-control"> + </div> - <div class="form-group"> - <label for="spayed">Spayed:</label> - <select id="edit-spayed" name="spayed" class="form-control"> - <option value="Yes">Yes</option> - <option value="No">No</option> - </select> - </div> + <div class="form-group"> + <label for="spayed">Spayed:</label> + <select id="edit-spayed" name="spayed" class="form-control"> + <option value="Yes">Yes</option> + <option value="No">No</option> + </select> + </div> - <!-- File Upload for Sound --> - <div class="form-group"> - <label for="sound_file">Sound File (MP3):</label> - <input type="file" id="edit-sound_file" name="sound_file" class="file-input" accept=".mp3"> - </div> + <!-- File Upload for Sound --> + <div class="form-group"> + <label for="sound_file">Sound File (MP3):</label> + <input type="file" id="edit-sound_file" name="sound_file" class="file-input" accept=".mp3"> + </div> - <!-- File Upload for Image --> - <div class="form-group"> - <label for="image_file">Image File (JPG, JPEG, PNG):</label> - <input type="file" id="edit-image_file" name="image_file" class="file-input" - accept=".jpg, .jpeg, .png"> - </div> + <!-- File Upload for Image --> + <div class="form-group"> + <label for="image_file">Image File (JPG, JPEG, PNG):</label> + <input type="file" id="edit-image_file" name="image_file" class="file-input" + accept=".jpg, .jpeg, .png"> + </div> - <button type="submit" class="submit-button">Edit Cat</button> - </form> + <button type="submit" class="submit-button">Edit Cat</button> + </form> + </div> </div> - </div> - </div> - <div> - <!-- Add Cat Modal --> - <div id="add-cat-modal" class="modal"> - <div class="modal-content"> - <span class="close" onclick="closeAddCatModal()">×</span> - <h2>Add New Cat</h2> - <form id="add-cat-form" enctype="multipart/form-data"> - <div class="form-group"> - <label for="name">Name:</label> - <input type="text" id="name" name="name" class="form-control"> - </div> + </div> + <div> + <!-- Add Cat Modal --> + <div id="add-cat-modal" class="modal"> + <div class="modal-content"> + <span class="close" onclick="closeAddCatModal()">×</span> + <h2>Add New Cat</h2> + <form id="add-cat-form" enctype="multipart/form-data"> + <div class="form-group"> + <label for="name">Name:</label> + <input type="text" id="name" name="name" class="form-control"> + </div> - <div class="form-group"> - <label for="description">Description:</label> - <textarea id="description" name="description" class="form-control"></textarea> - </div> + <div class="form-group"> + <label for="description">Description:</label> + <textarea id="description" name="description" class="form-control"></textarea> + </div> - <div class="form-group"> - <label for="location">Location:</label> - <input type="text" id="location" name="location" class="form-control"> - </div> + <div class="form-group"> + <label for="location">Location:</label> + <input type="text" id="location" name="location" class="form-control"> + </div> - <div class="form-group"> - <label for="gender">Gender:</label> - <select id="gender" name="gender" class="form-control"> - <option value="Male">Male</option> - <option value="Female">Female</option> - </select> - </div> + <div class="form-group"> + <label for="gender">Gender:</label> + <select id="gender" name="gender" class="form-control"> + <option value="Male">Male</option> + <option value="Female">Female</option> + </select> + </div> - <div class="form-group"> - <label for="color">Color:</label> - <input type="text" id="color" name="color" class="form-control"> - </div> - <div class="form-group"> - <label for="spayed">Spayed:</label> - <select id="spayed" name="spayed" class="form-control"> - <option value="Yes">Yes</option> - <option value="No">No</option> - </select> - </div> + <div class="form-group"> + <label for="color">Color:</label> + <input type="text" id="color" name="color" class="form-control"> + </div> + <div class="form-group"> + <label for="spayed">Spayed:</label> + <select id="spayed" name="spayed" class="form-control"> + <option value="Yes">Yes</option> + <option value="No">No</option> + </select> + </div> - <!-- File Upload for Sound --> - <div class="form-group"> - <label for="sound_file">Sound File (MP3):</label> - <input type="file" id="sound_file" name="sound_file" class="file-input" accept=".mp3"> - </div> + <!-- File Upload for Sound --> + <div class="form-group"> + <label for="sound_file">Sound File (MP3):</label> + <input type="file" id="sound_file" name="sound_file" class="file-input" accept=".mp3"> + </div> - <!-- File Upload for Image --> - <div class="form-group"> - <label for="image_file">Image File (JPG, JPEG, PNG):</label> - <input type="file" id="image_file" name="image_file" class="file-input" - accept=".jpg, .jpeg, .png"> - </div> + <!-- File Upload for Image --> + <div class="form-group"> + <label for="image_file">Image File (JPG, JPEG, PNG):</label> + <input type="file" id="image_file" name="image_file" class="file-input" + accept=".jpg, .jpeg, .png"> + </div> - <button type="submit" class="submit-button">Add Cat</button> - </form> + <button type="submit" class="submit-button">Add Cat</button> + </form> + </div> </div> - </div> - <!-- Add Cat Button --> - <button id="add-cat-button" class="add-button" onclick="openAddCatModal()">+</button> - </div> + <!-- Add Cat Button --> + <button id="add-cat-button" class="add-button" onclick="openAddCatModal()">+</button> + </div> + <?php endif; ?> <script src="public/js/cats.js"></script> </body> diff --git a/public/view/home.php b/public/view/home.php index dd059e5aed3a34642dfc50a4494cb2ec4a9118a4..214a530a106aa04dc004167e1b004e83cd7af6c0 100644 --- a/public/view/home.php +++ b/public/view/home.php @@ -1,18 +1,137 @@ <!DOCTYPE html> <html lang="en"> + <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="public/css/styles.css"> - <title>Document</title> + <style> + /* Add your CSS styles here */ + body { + font-family: Arial, sans-serif; + background-color: #f5f5f5; + margin: 0; + padding: 0; + } + + header { + background-color: #333; + color: #fff; + padding: 20px 0; + text-align: center; + } + + h1 { + font-size: 36px; + margin: 0; + } + + .container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + } + + .intro { + text-align: center; + margin-bottom: 40px; + } + + .cta-button { + display: inline-block; + padding: 15px 30px; + background-color: #007BFF; + color: #fff; + text-decoration: none; + border-radius: 5px; + font-weight: bold; + } + + .cta-button:hover { + background-color: #0056b3; + } + + .features { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 20px; + } + + .feature { + flex: 1; + background-color: #fff; + box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); + border-radius: 5px; + text-align: center; + padding: 20px; + transition: transform 0.2s ease-in-out; + } + + .feature h2 { + font-size: 24px; + margin-bottom: 10px; + } + + .feature p { + font-size: 16px; + color: #555; + } + + .feature:hover { + transform: translateY(-5px); + } + + footer { + background-color: #333; + color: #fff; + text-align: center; + padding: 20px 0; + } + </style> + <title>Wild Cats Guide</title> </head> + <body> - <?php require_once(PROJECT_ROOT_PATH.'/public/components/Navbar.php'); ?> + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Navbar.php'); ?> + + <header> + <h1>Welcome to the Wild Cats Guide</h1> + <p>Explore the fascinating world of wild cats at your university</p> + <a href="#features" class="cta-button">Learn More</a> + </header> - <div> - HIIIIIIIIIIIIII + <div class="container"> + <div class="intro"> + <h2>Discover Wild Cats on Campus</h2> + <p>Get to know the wild cats that roam your university campus. Explore their preferred locations, view sightings, + and share your own.</p> </div> + + <section id="features" class="features"> + <div class="feature"> + <h2>Wild Cat List</h2> + <p>View a list of wild cats and their preferred locations on campus.</p> + </div> + + <div class="feature"> + <h2>Sightings</h2> + <p>Share your wild cat sightings with photos and descriptions.</p> + </div> + + <div class="feature"> + <h2>Add a Sighting</h2> + <p>Contribute to our guide by adding your own wild cat sightings.</p> + </div> + </section> + </div> + + <footer> + <p>© + <?= date('Y') ?> Wild Cats Guide + </p> + </footer> </body> </html> \ No newline at end of file diff --git a/public/view/users.php b/public/view/users.php new file mode 100644 index 0000000000000000000000000000000000000000..a5e99dc91bbf6b281441d724e81f2783dc96a53d --- /dev/null +++ b/public/view/users.php @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>List of Users</title> + <link rel="stylesheet" type="text/css" href="public/css/styles.css"> +</head> + +<body> + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Navbar.php'); ?> + <div class="user-cards-container"> + <?php foreach ($responseUsers as $user): ?> + <div class="user-card" id="user-card-<?= $user['user_id'] ?>"> + <a class="delete-button" href="/user/<?= htmlspecialchars($user['user_id']) ?>">Delete</a> + <h2 class="user-title"> + <?= htmlspecialchars($user['nama']) ?> + </h2> + <strong>Email:</strong> + <p class="user-email"> + <?= htmlspecialchars($user['email']) ?> + </p> + <strong>Username:</strong> + <p class="user-username"> + <?= htmlspecialchars($user['username']) ?> + </p> + <strong>isAdmin:</strong> + <p class="user-isadmin"> + <?= htmlspecialchars($user['isAdmin']) ?> + </p> + <button class="edit-button" onclick="editUser(<?= $user['user_id'] ?>)">Edit</button> + </div> + <?php endforeach; ?> + </div> + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Pagination.php'); ?> + <div> + <div id="edit-user-modal" class="modal"> + <div class="modal-content"> + <span class="close" onclick="closeEditUserModal()">×</span> + <h2>Edit User</h2> + <form id="edit-user-form" enctype="multipart/form-data"> + <input type="hidden" id="edit-user-id" name="user_id" class="form-control"> + <div class="form-group"> + <label for="nama">Nama:</label> + <input type="text" id="edit-nama" name="nama" class="form-control"> + </div> + + <div class="form-group"> + <label for="email">Email:</label> + <input type="email" id="edit-email" name="email" class="form-control" readonly> + </div> + + <div class="form-group"> + <label for="username">Username:</label> + <input type="text" id="edit-username" name="username" class="form-control"> + </div> + + <div class="form-group"> + <label for="isAdmin">isAdmin:</label> + <select id="edit-isadmin" name="isAdmin" class="form-control"> + <option value="1">Yes</option> + <option value="0">No</option> + </select> + </div> + + <button type="submit" class="submit-button">Edit User</button> + </form> + </div> + </div> + </div> + <script src="public/js/users.js"></script> +</body> + +</html> \ No newline at end of file diff --git a/src/controllers/user/UserController.php b/src/controllers/user/UserController.php new file mode 100644 index 0000000000000000000000000000000000000000..f1179faffa5c4e6ec54ae2e0126320b7787a0c16 --- /dev/null +++ b/src/controllers/user/UserController.php @@ -0,0 +1,108 @@ +<?php + +require_once PROJECT_ROOT_PATH . "/src/bases/BaseController.php"; +require_once PROJECT_ROOT_PATH . "/src/services/UserSrv.php"; + +class UserController extends BaseController +{ + protected static $instance; + + private function __construct($srv) + { + parent::__construct($srv); + } + + public static function getInstance() + { + if (!isset(self::$instance)) { + self::$instance = new static( + UserSrv::getInstance() + ); + } + return self::$instance; + } + + public function get($urlParams) + { + if (!$urlParams) { + if (!$_GET["pageNo"] || !$_GET["pageSize"]) { + header("Location: /user?pageNo=1&pageSize=10"); + } + $users = $this->srv->getAll([ + "order" => "registration_date", + "pageNo" => $_GET['pageNo'] ?? 1, + "pageSize" => $_GET['pageSize'] ?? 10 + ]); + + $responseUsers = array_map(function ($user) { + return $user->toResponse(); + }, $users["result"]); + + $_count = $users["count"]; + + // Include the HTML template + require_once PROJECT_ROOT_PATH . "/public/view/users.php"; + + } else { + // TODO: Implement getting a specific user's data by user ID + return (new BaseResponse(false, null, "NOT IMPLEMENTED", 404))->toJSON(); + } + } + + public function post($urlParams) + { + if ($urlParams) { + $userIdFromUrl = $urlParams[0]; + $authenticatedUserId = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null; + + // Check if the authenticated user is authorized to edit the user's data + if (!$_SESSION['isAdmin'] && ($authenticatedUserId !== $userIdFromUrl)) { + return (new BaseResponse(false, null, "You are not authorized to edit this user's data", 403))->toJSON(); + } + $name = $_POST["nama"]; + $username = $_POST['username']; + $isAdmin = $_POST['isAdmin']; + + $updatedUserData = [ + "nama" => $name, + "username" => $username, + "isAdmin" => $isAdmin + ]; + + $user = $this->srv->updateUser($userIdFromUrl, $updatedUserData); + + if ($user) { + $response = new BaseResponse(true, $user->toResponse(), "User data updated successfully", 200); + } else { + $response = new BaseResponse(false, null, "Failed to update user data", 400); + } + + return $response->toJSON(); + } + return (new BaseResponse(false, null, "NOT IMPLEMENTED", 404))->toJSON(); + } + + public function delete($urlParams) + { + echo "HI ITMS ME"; + if ($urlParams) { + $userIdToDelete = $urlParams[0]; + $authenticatedUserId = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null; + + if (!$_SESSION['isAdmin'] && $authenticatedUserId !== $userIdToDelete) { + return (new BaseResponse(false, null, "You are not authorized to delete this user", 403))->toJSON(); + } + + $user = $this->srv->deleteUser($userIdToDelete); + + if ($user) { + $response = new BaseResponse(true, $user->toResponse(), "User deleted successfully", 200); + } else { + $response = new BaseResponse(false, null, "Failed to delete user", 400); + } + + return $response->toJSON(); + } + return (new BaseResponse(false, null, "NOT IMPLEMENTED", 404))->toJSON(); + } +} \ No newline at end of file diff --git a/src/models/UserModel.php b/src/models/UserModel.php index 0afc225b4df83f34d8da888d29a2f07431c745f5..134844f5426245bc2c41b166b28beaabcf5828a8 100644 --- a/src/models/UserModel.php +++ b/src/models/UserModel.php @@ -2,47 +2,53 @@ require_once PROJECT_ROOT_PATH . "/src/bases/BaseModel.php"; -class UserModel extends BaseModel { +class UserModel extends BaseModel +{ public $user_id; public $email; public $nama; public $password; public $isAdmin; public $username; + public $registration_date; - public function __construct() { + public function __construct() + { $this->_primary_key = 'user_id'; return $this; } - public function constructFromArray($array) { - $this->user_id = $array['user_id']; - $this->nama = $array['nama']; - $this->email = $array['email']; - $this->password = $array['password']; - $this->isAdmin = $array['isAdmin']; - $this->username = $array['username']; + public function constructFromArray($array) + { + foreach ($array as $key => $value) { + if (property_exists($this, $key)) { + $this->$key = $value; + } + } return $this; } - public function toResponse() { + public function toResponse() + { return array( 'user_id' => $this->user_id, 'nama' => $this->nama, 'email' => $this->email, 'username' => $this->username, 'isAdmin' => $this->isAdmin, + 'registration_date' => $this->registration_date, ); } - public function toArray() { + public function toArray() + { return array( - 'user_id' => $this->user_id, - 'nama' => $this->nama, - 'email' => $this->email, - 'password' => $this->password, - 'isAdmin' => $this->isAdmin, - 'username' => $this->username, + 'user_id' => $this->user_id, + 'nama' => $this->nama, + 'email' => $this->email, + 'password' => $this->password, + 'isAdmin' => $this->isAdmin, + 'username' => $this->username, ); } -} +} \ No newline at end of file diff --git a/src/repositories/UserRepository.php b/src/repositories/UserRepository.php index b0286271baec838fa4a1a92feb84a96749e00409..9b36c45d7e60f48adfb05a37844d68dc236912b1 100644 --- a/src/repositories/UserRepository.php +++ b/src/repositories/UserRepository.php @@ -2,7 +2,8 @@ require_once PROJECT_ROOT_PATH . "/src/bases/BaseRepository.php"; -class UserRepository extends BaseRepository { +class UserRepository extends BaseRepository +{ protected static $instance; protected $tableName = 'users'; @@ -11,6 +12,25 @@ class UserRepository extends BaseRepository { parent::__construct(); } + public function getUserById($userId) + { + return $this->selectOne("*", ["user_id = $userId"]); + } + + public function updateUser($userId, $userData) + { + return $this->update( + "user_id", + $userId, + $userData, + array( + 'nama' => PDO::PARAM_STR, + 'username' => PDO::PARAM_STR, + 'isAdmin' => PDO::PARAM_STR, + ) + ); + } + public static function getInstance() { if (!isset(self::$instance)) { @@ -19,16 +39,20 @@ class UserRepository extends BaseRepository { return self::$instance; } - public function getById($user_id) { + public function getById($user_id) + { return $this->selectOne('*', ["USER_ID = '$user_id'"]); } - public function getByEmail($email) { + public function getByEmail($email) + { return $this->selectOne('*', ["email = '$email'"]); } - public function getByUsername($username) { + public function getByUsername($username) + { return $this->selectOne('*', ["username = '$username'"]); } - public function getByPassword($password){ - return $this->selectOne('*', ["password = '$password'"]); + public function getByPassword($password) + { + return $this->selectOne('*', ["password = '$password'"]); } -} +} \ No newline at end of file diff --git a/src/services/UserSrv.php b/src/services/UserSrv.php index f50c6b016ad6eb91c9bdabdc05acdb8ade09489e..6d50c4c59439432b664f969869d2617058fd56c4 100644 --- a/src/services/UserSrv.php +++ b/src/services/UserSrv.php @@ -43,18 +43,38 @@ class UserSrv extends BaseSrv $user = (new UserModel())->set('nama', $nama)->set('username', $username)->set('email', $email)->set('password', password_hash($password, PASSWORD_DEFAULT)); - $id = $this->repository->insert($user->toArray(), array( - 'nama' => PDO::PARAM_STR, - 'username' => PDO::PARAM_STR, - 'email' => PDO::PARAM_STR, - 'password' => PDO::PARAM_STR, - )); + $id = $this->repository->insert( + $user->toArray(), + array( + 'nama' => PDO::PARAM_STR, + 'username' => PDO::PARAM_STR, + 'email' => PDO::PARAM_STR, + 'password' => PDO::PARAM_STR, + ) + ); $sqlRes = $this->repository->getById($id); $user = new UserModel(); return $user->constructFromArray($sqlRes); } + public function getAll($config) + { + $order = ["registration_date"]; + // if ($config["order"]) { + // $order = explode(",", $config["order"]); + // } + + $usersResult = $this->repository->select('*', [], $order, $config["pageNo"], $config['pageSize'], null); + $users = []; + foreach ($usersResult["result"] as $userResult) { + $user = new UserModel(); + $users[] = $user->constructFromArray($userResult); + } + return ["result" => $users, "count" => $usersResult["count"]]; + } + + public function login($email_uname, $password) { $user = null; @@ -85,6 +105,23 @@ class UserSrv extends BaseSrv return $user; } + public function getUserById($userId) + { + $userData = $this->repository->getUserById($userId); + if (!$userData) { + throw new Exception("User not found"); + } + + $user = new UserModel(); + return $user->constructFromArray($userData); + } + + public function deleteUser($userId) + { + $cat = $this->getUserById($userId); + $this->repository->delete("user_id", $userId); + return $cat; + } public function getByEmail($email) { @@ -108,6 +145,23 @@ class UserSrv extends BaseSrv return $user; } + public function updateUser($userId, $userData) + { + $existingUser = $this->getUserById($userId); + $updatedUser = (new UserModel())->constructFromArray($userData); + + // Merge updated data into the existing cat model + foreach (get_object_vars($updatedUser) as $property => $value) { + if ($value !== null) { + $existingUser->$property = $value; + } + } + + $this->repository->updateUser($userId, $existingUser->toArray()); + + return $existingUser; + } + public function isUsernameExist($username) { $user = $this->getByUsername($username); @@ -120,7 +174,8 @@ class UserSrv extends BaseSrv return !is_null($user->get('user_id')); } - public function getById($id) { + public function getById($id) + { $user = $this->repository->getById($id); if (!$user) { return null; @@ -131,4 +186,4 @@ class UserSrv extends BaseSrv return $userModel; } -} +} \ No newline at end of file