diff --git a/Dockerfile.build b/Dockerfile.build new file mode 100644 index 0000000000000000000000000000000000000000..cf3d5c1b5458556d110d756ab3ba6c2e3a5a65d2 --- /dev/null +++ b/Dockerfile.build @@ -0,0 +1,5 @@ +FROM php:8.2-apache +RUN apt-get update && apt-get install -y libpq-dev && docker-php-ext-install pdo pdo_pgsql +RUN a2enmod rewrite +COPY ./src /var/www/html +COPY ./src/php.ini /usr/local/etc/php/php.ini \ No newline at end of file diff --git a/build-image.sh b/build-image.sh new file mode 100644 index 0000000000000000000000000000000000000000..6e26f4c1619983fa152e10b59ee18c958ee9b93a --- /dev/null +++ b/build-image.sh @@ -0,0 +1 @@ +docker build -t tubes2-php -f "Dockerfile.build" . \ No newline at end of file diff --git a/scripts/build-image.sh b/scripts/build-image.sh deleted file mode 100644 index ce096bac1ad2e7c6eec731197a2b126c245fa237..0000000000000000000000000000000000000000 --- a/scripts/build-image.sh +++ /dev/null @@ -1 +0,0 @@ -docker build -t tubes-1:latest . \ No newline at end of file diff --git a/seed.py b/seed.py new file mode 100644 index 0000000000000000000000000000000000000000..d7d35c7d6845ce348468a4dea1bf874fb451bcf2 --- /dev/null +++ b/seed.py @@ -0,0 +1,56 @@ +import psycopg2 +from faker import Faker +from random import randint + +conn = psycopg2.connect( + host="localhost", + database="mykos", + user="postgres", + password="postgres", + port=5433) + +cur = conn.cursor() +fake = Faker("id_ID") + +owners = [] +for i in range(10): + owners.append(f"('{fake.name()}', '08{fake.msisdn()}')") +owners_str = ", ".join(owners) + +cur.execute("INSERT INTO owners(name, phone_number) VALUES " + owners_str) + +dorms = [] +for i in range(10000): + owner_id = randint(1, 10) + name = fake.text(max_nb_chars=50) + address = fake.address() + city = fake.city() + price = randint(10, 250) * 10000 + description = fake.paragraph(nb_sentences=2) + dorms.append( + f"({owner_id}, '{name}', '{address}', '{city}', {price}, '{description}')") +dorms_str = ", ".join(dorms) +cur.execute( + "INSERT INTO dorms(owner_id, name, address, city, price, description) VALUES " + dorms_str) + +medias = [] +for i in range(1, 10001): + for j in range(randint(1, 3)): + img_id = randint(1, 8) + endpoint = "/media/images/kos" + str(img_id) + ".jpeg" + alt_text = fake.text(max_nb_chars=25) + medias.append(f"({i}, 'photo', '{endpoint}', '{alt_text}')") + + if randint(0, 1): + medias.append( + f"({i}, 'video', '/media/videos/video.mp4', 'preview kos')") + +medias_str = ", ".join(medias) +cur.execute( + "INSERT INTO medias(dorm_id, type, endpoint, alt_text) VALUES " + medias_str) + + +conn.commit() +print("Success") +cur.close() +conn.close() diff --git a/src/Controllers/DormController.php b/src/Controllers/DormController.php index 10e8b9400aadfafaf4ae4c11dd384e5eecb47698..e17316cd7dd595b446c0066df1902b3cb9732985 100644 --- a/src/Controllers/DormController.php +++ b/src/Controllers/DormController.php @@ -17,11 +17,11 @@ use app\Utils\Toast; class DormController extends Controller { - - public function list() + public function getList() { $page = Request::getPage(); $cities = Dorm::getCities(); + $ids = Request::getQuery()["ids"] ?? null; $sort = Request::getQuery()["sort"] ?? "dorm_id DESC"; $city = Request::getQuery()["city"] ?? ""; $price = Request::getQuery()["price"] ?? ""; @@ -39,9 +39,27 @@ class DormController extends Controller if (!in_array($price, $priceValues)) { $price = ""; } - $data = Dorm::getAllFiltered($page, $sort, Request::getQuery()["q"] ?? "", $city, $price); + if ($ids !== null) { + $ids = explode(",", $ids); + $data = Dorm::getInIds($ids, $page, $sort, $city, $price); + $data["page"] = $page; + $data["cities"] = $cities; + return $data; + } else { + $data = Dorm::getAllFiltered($page, $sort, Request::getQuery()["q"] ?? "", $city, $price); + } $data["page"] = $page; $data["cities"] = $cities; + return $data; + } + + public function list() + { + $data = $this->getList(); + if (Request::isJSON()) { + Response::json($data); + return; + } if (isset(Request::getQuery()["list-only"])) { $this->render("dorm/list", $data); return; @@ -62,12 +80,19 @@ class DormController extends Controller return; } - $this->render("dorm/view", [ + $data = [ "dorm" => $dorm, "medias" => $medias, "owner" => $owner, - "reviews" => $reviews - ]); + ]; + + if (Request::isJSON()) { + Response::json($data); + return; + } + $data["reviews"] = $reviews; + + $this->render("dorm/view", $data); } diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index 5bffa27fcb4a0dcf72c383575c835d3495012082..874961404521f5ab3cbd9c21407225a6f69c2e49 100644 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -23,29 +23,29 @@ class UserController extends Controller Response::$title = "Akun | MyKos"; } -// public function me() -// { -// $form = new Validation([ -// [new Field('email', "Email"), [new Required(), new Email()]], -// [new Field('name', "Nama"), [new Required()]], -// [new Field('phone_number', "Nomor Telepon"), [new Required(), new Phone()]], -// // [new Field('password'), [new Required()]] -// ]); -// if (Request::getMethod() === "POST") { -// if ($form->validate(Request::getBody())) { -// $user = User::toModel($form->data); -// $user->save(); -// Toast::success("Penyewa berhasil ditambahkan", true); -// Response::redirect("/owners"); -// return; -// } -// } -// $user = Request::getUser(); -// $this->render("user/index", [ -// "user" => $user, -// ...$form->getFields(), -// ]); -// } + // public function me() + // { + // $form = new Validation([ + // [new Field('email', "Email"), [new Required(), new Email()]], + // [new Field('name', "Nama"), [new Required()]], + // [new Field('phone_number', "Nomor Telepon"), [new Required(), new Phone()]], + // // [new Field('password'), [new Required()]] + // ]); + // if (Request::getMethod() === "POST") { + // if ($form->validate(Request::getBody())) { + // $user = User::toModel($form->data); + // $user->save(); + // Toast::success("Penyewa berhasil ditambahkan", true); + // Response::redirect("/owners"); + // return; + // } + // } + // $user = Request::getUser(); + // $this->render("user/index", [ + // "user" => $user, + // ...$form->getFields(), + // ]); + // } public function edit() { @@ -65,7 +65,7 @@ class UserController extends Controller $user = User::findById($userId); $this->setUserFormData($formProfile, $user); } - + $user = Request::getUser(); $this->render("user/edit", [ "user" => $user, @@ -82,41 +82,41 @@ class UserController extends Controller $this->setUserFormData($formProfile, $user); if (Request::getMethod() === "POST") { - $valid = $formPassword->validate(Request::getBody()); - $data = $formPassword->data; - if (!password_verify($data['password'], $user->password)) { - $formPassword->addError('password', 'Password salah'); - $valid = false; - } - if ($data["password1"] !== $data["password2"]) { - $formPassword->addError('password2', 'Password tidak sama'); - $valid = false; - } - if (!$valid) { - $this->setUserFormData($formProfile, $user); - - $formPassword->data["password"] = $data["password"]; - $formPassword->data["password1"] = $data["password1"]; - $formPassword->data["password2"] = $data["password2"]; - - $this->render('user/edit', [ + $valid = $formPassword->validate(Request::getBody()); + $data = $formPassword->data; + if (!password_verify($data['password'], $user->password)) { + $formPassword->addError('password', 'Password salah'); + $valid = false; + } + if ($data["password1"] !== $data["password2"]) { + $formPassword->addError('password2', 'Password tidak sama'); + $valid = false; + } + if (!$valid) { + $this->setUserFormData($formProfile, $user); + + $formPassword->data["password"] = $data["password"]; + $formPassword->data["password1"] = $data["password1"]; + $formPassword->data["password2"] = $data["password2"]; + + $this->render('user/edit', [ "user" => $user, "fields" => $formProfile->data + $formPassword->data, "errors" => $formProfile->errors + $formPassword->errors - ]); + ]); return; - } + } - $userId = Request::getUser()->user_id; - $user = User::findById($userId); - $user->user_id = $userId; - $user->password = password_hash($data["password1"], PASSWORD_DEFAULT); + $userId = Request::getUser()->user_id; + $user = User::findById($userId); + $user->user_id = $userId; + $user->password = password_hash($data["password1"], PASSWORD_DEFAULT); - $user->save(); - Toast::success("Password berhasil diubah", true); - Response::redirect("/account/edit"); - return; - } + $user->save(); + Toast::success("Password berhasil diubah", true); + Response::redirect("/account/edit"); + return; + } } @@ -127,12 +127,12 @@ class UserController extends Controller $form->data["phone_number"] = $user->phone_number; } -// private function setPasswordFormData(Validation $form, User $user) -// { -// $form->data["password"] = $user->name; -// $form->data["password1"] = $user->email; -// $form->data["password2"] = $user->phone_number; -// } + // private function setPasswordFormData(Validation $form, User $user) + // { + // $form->data["password"] = $user->name; + // $form->data["password1"] = $user->email; + // $form->data["password2"] = $user->phone_number; + // } private function getProfileForm() @@ -147,9 +147,9 @@ class UserController extends Controller private function getPasswordForm() { return new Validation([ - [new Field('password', "Password Lama"), [new Required()]], - [new Field('password1', "Passwor Baru"), [new Required(), new Minimum(4)]], - [new Field('password2', "Konfirmasi Password"), [new Required()]] + [new Field('password', "Password Lama"), [new Required()]], + [new Field('password1', "Passwor Baru"), [new Required(), new Minimum(4)]], + [new Field('password2', "Konfirmasi Password"), [new Required()]] ]); } } diff --git a/src/Controllers/WishlistController.php b/src/Controllers/WishlistController.php index b057f9b3e8ac161e6c18a73338bcadee4ae0493a..1006580e73410c27ae0cc36fb7231fd5bd87cc17 100644 --- a/src/Controllers/WishlistController.php +++ b/src/Controllers/WishlistController.php @@ -70,7 +70,7 @@ class WishlistController extends Controller $dormId = $params["dormId"]; if (Request::getMethod() === "GET") { - if (empty(Wishlists::where(["dorm_id"=>$dormId, "user_id"=>$userId]))) { + if (empty(Wishlists::where(["dorm_id" => $dormId, "user_id" => $userId]))) { $wishlist = Wishlists::toModel(["dorm_id" => $dormId, "user_id" => $userId]); $wishlist->save(); } diff --git a/src/Core/Application.php b/src/Core/Application.php index 463ff2d6ef9f1cc11ebb9851ba956601158d426d..a4a65861847e3e9682e48074537a540b9db087d3 100644 --- a/src/Core/Application.php +++ b/src/Core/Application.php @@ -36,6 +36,7 @@ class Application { $this->router = new Router(); $this->router->get('/', [], DormController::class, 'list'); + $this->router->get('/dorms', [], DormController::class, 'list'); $this->router->methods(["GET", "POST"], '/login', [], AuthController::class, 'login'); $this->router->methods(["GET", "POST"], '/register', [], AuthController::class, 'register'); $this->router->get('/logout', [], AuthController::class, 'logout'); @@ -47,7 +48,7 @@ class Application $this->router->get("/me", [AuthRequired::class], AuthController::class, 'me'); $this->router->methods(["GET", "POST"], "/dorms/create", [AdminOnly::class], DormController::class, 'create'); - $this->router->methods(["GET", "POST"], "/dorms/{dormId}", [AuthRequired::class], DormController::class, 'view'); + $this->router->methods(["GET", "POST"], "/dorms/{dormId}", [], DormController::class, 'view'); $this->router->delete("/dorms/{dormId}", [AuthRequired::class], DormController::class, 'delete'); $this->router->methods(["GET", "POST"], "/dorms/{dormId}/media", [AdminOnly::class], DormController::class, 'media'); $this->router->delete("/dorms/{dormId}/media", [AdminOnly::class], DormController::class, 'deleteMedia'); diff --git a/src/Core/Request.php b/src/Core/Request.php index 51c314ba5ae02e310355b3ed971009272c7ffbdf..b2f2bdfb35e1cd717766406e596be083afba4efc 100644 --- a/src/Core/Request.php +++ b/src/Core/Request.php @@ -74,4 +74,9 @@ class Request { return $_GET; } + + public static function isJSON() + { + return isset($_SERVER["ACCEPT"]) && $_SERVER["ACCEPT"] === "application/json"; + } } diff --git a/src/Core/Response.php b/src/Core/Response.php index 59445f395f2383fbc123e0a0dd845d64186243c0..325933c4dfcff7cdb5061cd1c0fe967474bdaf4f 100644 --- a/src/Core/Response.php +++ b/src/Core/Response.php @@ -16,4 +16,10 @@ class Response header("Location: $url"); self::statusCode($permanent ? 301 : 302); } + + public static function json($data) + { + header('Content-Type: application/json'); + echo json_encode($data); + } } diff --git a/src/Models/Dorm.php b/src/Models/Dorm.php index 509ebfcfb7483f57f09dfbe8db78262add352d99..d459c5657713f5bf9c8d40b8b1bf9679e3f8c2a0 100644 --- a/src/Models/Dorm.php +++ b/src/Models/Dorm.php @@ -19,7 +19,7 @@ class Dorm extends BaseModel public static function getAllFiltered($page = 1, $orderBy = "dorm_id DESC", $search = "", $city = "", $price = "") { - $limit = 4; + $limit = 12; $offset = ($page - 1) * $limit; $cityQuery = $city ? "AND city = '$city'" : ""; $priceQuery = $price ? "AND $price" : ""; diff --git a/src/Models/schema.sql b/src/Models/schema.sql index 508f5c00cb5d5924e075d5c8ded87211f67b2683..578b27f0c30f9fc33ef71360dbb491bbbd9f5cf7 100644 --- a/src/Models/schema.sql +++ b/src/Models/schema.sql @@ -1,4 +1,4 @@ -CREATE TABLE users ( +CREATE TABLE IF NOT EXISTS users ( user_id SERIAL NOT NULL, email TEXT NOT NULL UNIQUE, name TEXT NOT NULL, @@ -9,7 +9,7 @@ CREATE TABLE users ( PRIMARY KEY (user_id) ); -CREATE TABLE owners ( +CREATE TABLE IF NOT EXISTS owners ( owner_id SERIAL NOT NULL, name TEXT NOT NULL, phone_number TEXT, @@ -17,7 +17,7 @@ CREATE TABLE owners ( PRIMARY KEY (owner_id) ); -CREATE TABLE dorms ( +CREATE TABLE IF NOT EXISTS dorms ( dorm_id SERIAL NOT NULL, owner_id INT NOT NULL, name TEXT NOT NULL, @@ -30,9 +30,15 @@ CREATE TABLE dorms ( FOREIGN KEY (owner_id) REFERENCES owners(owner_id) ); -CREATE TYPE media_type AS ENUM ('photo', 'video'); +--create types +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'media_type') THEN + CREATE TYPE media_type AS ENUM ('photo', 'video'); + END IF; +END$$; -CREATE TABLE medias ( +CREATE TABLE IF NOT EXISTS medias ( media_id SERIAL NOT NULL, dorm_id INT NOT NULL, type MEDIA_TYPE NOT NULL, @@ -43,7 +49,7 @@ CREATE TABLE medias ( FOREIGN KEY (dorm_id) REFERENCES dorms(dorm_id) ON DELETE CASCADE ); -CREATE TABLE reviews ( +CREATE TABLE IF NOT EXISTS reviews ( review_id SERIAL NOT NULL, dorm_id INT NOT NULL, user_id INT NOT NULL, @@ -55,7 +61,7 @@ CREATE TABLE reviews ( FOREIGN KEY (user_id) REFERENCES users(user_id) ); -CREATE TABLE wishlists ( +CREATE TABLE IF NOT EXISTS wishlists ( user_id INT NOT NULL, dorm_id INT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, diff --git a/src/Views/dorm/list.php b/src/Views/dorm/list.php index 17cfccba2567ce1d70bdd87ee0e9f6058837e8fa..1ef48c12844a32f380d1d55d3b3b9826b29ca8fd 100644 --- a/src/Views/dorm/list.php +++ b/src/Views/dorm/list.php @@ -21,18 +21,26 @@ <? endforeach; ?> </ul> <div class="pagination"> + <button data-page="1" class="pagination_item" <? if ($page===1) echo "disabled" ?>><span + aria-hidden="true">«</span> + <span class="sr-only">First</span> + </button> <button data-page="<?= $page - 1 ?>" class="pagination_item" <? if ($page===1) echo "disabled" ?>> - <span aria-hidden="true">«</span> + <span aria-hidden="true"><</span> <span class="sr-only">Previous</span> </button> - - <? for ($i = 1; $i <= $totalPage; $i++) : ?> + <? for ($i = $page - 2; $i <= $page + 2; $i++) : ?> + <? if ($i < 1 || $i > $totalPage) continue; ?> <button data-page="<?= $i ?>" class="pagination_item <?= $i == $page ? 'active' : '' ?>"><?= $i ?></button> <? endfor; ?> <button data-page="<?= $page + 1 ?>" class="pagination_item" <? if ($page==$totalPage) echo "disabled" ?>> - <span aria-hidden="true">»</span> + <span aria-hidden="true">></span> <span class="sr-only">Next</span> </button> + <button data-page="<?= $totalPage ?>" class="pagination_item" <? if ($page==$totalPage) echo "disabled" ?>> + <span aria-hidden="true">»</span> + <span class="sr-only">Last</span> + </button> </div> \ No newline at end of file diff --git a/src/Views/dorm/view.php b/src/Views/dorm/view.php index 6d12e5dfe972a38518a00d63b8fd75fd43741897..d975d9742999c1efcb3af28c468422f967ae6030 100644 --- a/src/Views/dorm/view.php +++ b/src/Views/dorm/view.php @@ -2,9 +2,9 @@ @@head <link rel="stylesheet" href="/static/styles/dorm-view.css?v=<?php -use app\Models\User; + use app\Models\User; - echo time(); ?>"> + echo time(); ?>"> @@endhead <div class="container"> <? if (count($medias) > 0) : ?> @@ -43,20 +43,20 @@ use app\Models\User; <div class="info-booking"> <p class="price">Rp<?= number_format($dorm->price, 0, ',', '.') ?> - <span> / bulan</span> + <span> / bulan</span> </p> <p class="info-owner">Info Pemilik</p> <p><span class="person-icon">👤</span>: <?= $owner->name ?></p> <p><span class="phone-icon"> ☎</span> : <?= $owner->phone_number ?></p> - <? if (!$user->is_admin ?? false) : ?> + <? if ($user && !$user->is_admin ?? false) : ?> <!-- <form id="wishlist-button" action="/WishlistController/add" method="POST"> <input type="hidden" name="dorm_id" id="likedInput" value="<?= $dormId ?>"> </form> <button id="wishlist-button" lass="btn btn-primary btn-edit-kos">Tambahkan kos ke wishlist</button> --> - <div class="wishlist"> - <a href="/dorms/<?= $dorm->dorm_id ?>/add-to-wishlist" id="wishlist-button" class="btn btn-primary btn-edit-kos">Tambahkan kos ke wishlist</a> - <!-- <script> + <div class="wishlist"> + <a href="/dorms/<?= $dorm->dorm_id ?>/add-to-wishlist" id="wishlist-button" class="btn btn-primary btn-edit-kos">Tambahkan kos ke wishlist</a> + <!-- <script> $(document).ready(function () { // Attach a click event listener to the like link $("#wishlist-button").click(function (event) { @@ -68,24 +68,21 @@ use app\Models\User; }); }); </script> --> - </div> + </div> <? endif; ?> - + </div> </div> <? if ($user->is_admin ?? false) : ?> - <div class="edit-admin"> - <a href="/dorms/<?= $dorm->dorm_id ?>/edit" class="btn btn-primary btn-edit-kos">Edit Kos</a> - </div> - <form method="POST"> - <button type="button" class="btn btn-danger dialog-btn action-btn delete-dorm" - data-dialog="delete-<?= $dorm->dorm_id ?>"><svg xmlns="http://www.w3.org/2000/svg" fill="none" - viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="14" height="14"> - <path stroke-linecap="round" stroke-linejoin="round" - d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> - </svg> - Delete kos + <div class="edit-admin"> + <a href="/dorms/<?= $dorm->dorm_id ?>/edit" class="btn btn-primary btn-edit-kos">Edit Kos</a> + </div> + <form method="POST"> + <button type="button" class="btn btn-danger dialog-btn action-btn delete-dorm" data-dialog="delete-<?= $dorm->dorm_id ?>"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="14" height="14"> + <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> + </svg> + Delete kos </button> <input type="hidden" name="dorm_id" value="<?= $dorm->dorm_id ?>" /> <input type="hidden" name="_method" value="DELETE" /> @@ -93,29 +90,27 @@ use app\Models\User; <div class="dialog-content"> <h4 class="confirm-title">Apakah Anda yakin ingin menghapus kos?</h4> <div class="confirm-action"> - <button type="button" class="btn btn-outlined dialog-btn" - data-dialog="delete-<?= $dorm->dorm_id ?>">Batal</button> + <button type="button" class="btn btn-outlined dialog-btn" data-dialog="delete-<?= $dorm->dorm_id ?>">Batal</button> <button type="submit" class="btn btn-danger">Hapus</button> </div> </div> </div> </form> <? endif; ?> - + <div class="reviews"> <h1> Review Kos Ini</h1> - <? if (!$user->is_admin ?? false) : ?> + <? if ($user && !$user->is_admin ?? false) : ?> <div class="add-review"> <a href="/dorms/<?= $dorm->dorm_id ?>/add-review" class="btn btn-primary btn-add-review"> - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" - width="12" height="12" aria-hidden="true"> - <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /> + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" width="12" height="12" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /> </svg> - Tambahkan Review + Tambahkan Review </a> </div> <? endif; ?> - + <ul class="review-list"> <? foreach ($reviews as $review) : ?> <? $reviewer = User::findById($review->user_id); ?> @@ -125,8 +120,8 @@ use app\Models\User; <p class="review-item-rate"> <? $rating = $review->rate; - $stars = str_repeat("★", $rating); - $emptyStars = str_repeat("☆", 5 - $rating); + $stars = str_repeat("★", $rating); + $emptyStars = str_repeat("☆", 5 - $rating); echo $stars . $emptyStars; ?> </p> @@ -135,20 +130,15 @@ use app\Models\User; <div class="review-actions"> <? if (($user->is_admin ?? false) || ($user->user_id == $reviewer->user_id ?? false)) : ?> <? if ($user->user_id == $reviewer->user_id ?? false) : ?> - <a href="/reviews/<?= $review->review_id ?>" class="btn btn-outlined edit-review" data-dialog="add-owner-dialog"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" - stroke-width="2" stroke="currentColor" width="20" height="20"> - <path stroke-linecap="round" stroke-linejoin="round" - d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /> + <a href="/reviews/<?= $review->review_id ?>" class="btn btn-outlined edit-review" data-dialog="add-owner-dialog"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20"> + <path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /> </svg> </a> <? endif ?> <form method="POST" action="/dorms/<?= $dorm->dorm_id ?>/delete-review"> - <button type="button" class="btn btn-danger dialog-btn action-btn" - data-dialog="delete-<?= $review->review_id ?>"><svg xmlns="http://www.w3.org/2000/svg" fill="none" - viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20"> - <path stroke-linecap="round" stroke-linejoin="round" - d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> - </svg> + <button type="button" class="btn btn-danger dialog-btn action-btn" data-dialog="delete-<?= $review->review_id ?>"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20"> + <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /> + </svg> </button> <input type="hidden" name="review_id" value="<?= $review->review_id ?>" /> <input type="hidden" name="_method" value="DELETE" /> @@ -156,8 +146,7 @@ use app\Models\User; <div class="dialog-content"> <h4 class="confirm-title">Apakah anda yakin ingin menghapus review?</h4> <div class="confirm-action"> - <button type="button" class="btn btn-outlined dialog-btn" - data-dialog="delete-<?= $review->review_id ?>">Batal</button> + <button type="button" class="btn btn-outlined dialog-btn" data-dialog="delete-<?= $review->review_id ?>">Batal</button> <button type="submit" class="btn btn-danger">Hapus</button> </div> </div> diff --git a/src/migrate.php b/src/migrate.php new file mode 100644 index 0000000000000000000000000000000000000000..e10d247c439ed606cb43ddf9ef729a0c062a2e4a --- /dev/null +++ b/src/migrate.php @@ -0,0 +1,11 @@ +<?php + +$dsn = sprintf("pgsql:host=%s;dbname=%s", getenv("POSTGRES_HOST"), getenv("POSTGRES_DB")); +$pdo = new PDO($dsn, getenv("POSTGRES_USER"), getenv("POSTGRES_PASSWORD"), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT => true]); + +try { + $sql = file_get_contents(__DIR__ . "/Models/schema.sql"); + $pdo->exec($sql); +} catch (PDOException $e) { + die($e->getMessage()); +}