diff --git a/.htaccess b/.htaccess index 04f821ff632042f2647322ef5aeb7eef79a0bb32..5d0c861f73a613eff7338dde91be1ec72dcd80fc 100644 --- a/.htaccess +++ b/.htaccess @@ -11,7 +11,6 @@ RewriteEngine On RewriteBase / -# Rewrite all requests to index.php except for existing files or directories RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index fccd3f4f67a4e14285262f1ee3f2d6978cb5b0c7..643dae5293f02e5eb93f8ea5daaf536af080d83e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,8 @@ RUN apt-get update RUN docker-php-ext-install pdo pdo_mysql -# Copy custom configuration files COPY ./php.ini /usr/local/etc/php/conf.d/php.ini -# Copy your application code COPY . /var/www/html/ RUN a2enmod rewrite && service apache2 restart diff --git a/docker-compose.yml b/docker-compose.yml index 0446cf6e3385fbd76503685f661655d303041e40..cfe29ac984bf37d409a50efb2cd601be001a2cfb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,5 +32,5 @@ services: - "3306:3306" -# run code below first +# run command below first # docker exec -i tubes-1-db /bin/mysql -u root -pBabybaby123 migrate < ./migrations/migrate.sql \ No newline at end of file diff --git a/index.php b/index.php index 38faa27ef90e99ae455f8dfd414ed49aebc2871b..ad772b154e24cab9685b35b655a13ff291aeb372 100644 --- a/index.php +++ b/index.php @@ -10,6 +10,7 @@ require_once PROJECT_ROOT_PATH . "/src/controllers/auth/LogoutController.php"; // require_once PROJECT_ROOT_PATH . "/src/controllers/auth/LoginFormController.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"; session_start(); @@ -23,5 +24,7 @@ $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']); diff --git a/migrations/migrate.sql b/migrations/migrate.sql index 78a4538bd64c3979e6613411801b2148859407c6..1658a3baf073b22149c82ecc7e77f7726e0e0d14 100644 --- a/migrations/migrate.sql +++ b/migrations/migrate.sql @@ -9,6 +9,9 @@ CREATE TABLE users ( isAdmin tinyint(1) NOT NULL DEFAULT '0', registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); +INSERT INTO users (user_id, nama, username, password, email, isAdmin) VALUES +(1,'ujang','unjanx','p','p',1); + drop table if exists cats; -- Cats Table @@ -38,12 +41,15 @@ CREATE TABLE sightings ( sighting_id INT PRIMARY KEY AUTO_INCREMENT, cat_id INT REFERENCES cats(cat_id), user_id INT REFERENCES users(user_id), - location VARCHAR(255) NOT NULL, + sighting_location VARCHAR(255) NOT NULL, date DATE, time TIME, - description TEXT, + sighting_description TEXT, image_url TEXT -- URL to image related to the sighting ); +INSERT INTO sightings (sighting_id,cat_id,user_id,sighting_location,date,time,sighting_description,image_url) VALUES +(1,1,1,'loc','2023-10-1','10:00:00','ppp','/images/whiskers.jpg'), +(2,2,1,'loc2','2023-10-1','10:00:00','ppp','/images/whiskers.jpg'); ## HOME PAGE diff --git a/public/css/styles.css b/public/css/styles.css index fc8644ec68401efa1fcb227e2de63e99a14a4d4c..259c1984a77037156ba0270a7f0cbd923a60bc7c 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 { +.cat-card, .sighting-card { border: 1px solid #ccc; padding: 16px; margin: 16px; @@ -80,7 +80,7 @@ nav ul li a:hover { /* styles.css */ /* Style for the container that holds the cat cards */ -.cat-cards-container { +.cat-cards-container, .sighting-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 { +.cat-card, .sighting-card { position: relative; /* Add relative positioning to the cat card */ border: 1px solid #ccc; padding: 16px; diff --git a/public/js/sighting.js b/public/js/sighting.js new file mode 100644 index 0000000000000000000000000000000000000000..58a6e88582fb4ed124eac6c66e916a46a534ce12 --- /dev/null +++ b/public/js/sighting.js @@ -0,0 +1,33 @@ +const addSightingModal = document.getElementById("add-sighting-modal"); + +function openAddSightingModal(){ + addSightingModal.style.display="block"; +} + +function closeAddSightingModal(){ + addSightingModal.style.display="none"; +} + +const addSightingForm = document.getElementById("add-sighting-form"); + +addSightingForm.addEventListener("submit", function (e){ + e.preventDefault(); + const formData = new FormData(addSightingForm); + fetch("/sighting",{ + method: "POST", + body: formData, + }) + .then((response) =>{ + if (response.ok){ + console.log(addSightingForm); + console.log("Sighting added"); + closeAddSightingModal(); + window.location.reload(); + } else { + console.log("failed"); + } + }) + .catch((error) =>{ + console.error(error); + }) +}) \ No newline at end of file diff --git a/public/view/sighting.php b/public/view/sighting.php new file mode 100644 index 0000000000000000000000000000000000000000..3d3e8c44dd703e5219e1390869883a38fce3dbc4 --- /dev/null +++ b/public/view/sighting.php @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>List of Sightings</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="sighting-cards-container"> + <?php foreach ($responseSightings as $sighting):?> + <div class="sighting-card" id="sighting-card<?=$sighting['sighting_id']?>"> +<!-- //if ($_SESSION['user_id']==$sighting['user_id']){--> +<!--echo ("<a class=\"delete-button\" href=\"/sighting/--><?php //=htmlspecialchars(" . $sighting['sighting_id']. "?><!--\">");}*/?>--> + <strong>Kucing:</strong> + <p class="cat-title"> + <?=htmlspecialchars($sighting['name'])?> + </p> + <strong>Sighted by:</strong> + <p class="sighting-username"> + <?=htmlspecialchars($sighting['username'])?> + </p> + <strong>Location:</strong> + <p class="sighting-location"> + <?=htmlspecialchars($sighting['sighting_location'])?> + </p> + <strong>Date:</strong> + <p class="sighting-date"> + <?=htmlspecialchars($sighting['date'])?> + </p> + <strong>Time:</strong> + <p class="sigting-time"> + <?=htmlspecialchars($sighting['time'])?> + </p> + <br> + <p class="sighting-description"> + <?=htmlspecialchars($sighting['sighting_description'])?> + </p> + <img class="cat-image" src="public/<?= htmlspecialchars($sighting['image_url'])?>" alt="cat_image"> + </div> + <!-- <p>--> + <!-- --><?php //= htmlspecialchars($sighting['nama'])?> + <!-- </p>--> + <!-- <img src="public/--><?php //=htmlspecialchars($sighting['image_url'])?><!--">--> + <?php endforeach;?> + </div> +<!-- foreach ($responseCats as $cat){--> +<!-- echo ('<option value="' . $cat['cat_id'] . '">' . $cat['name'] . '</option>');--> +<!-- }?>--> + + <div> + <div id="add-sighting-modal" class="modal" > + <div class="modal-content"> + <span class="close" onclick="closeAddSightingModal()">×</span> + <h2>Add New Sighting</h2> + <form id="add-sighting-form" enctype="multipart/form-data"> + <div class="form-group"> + <label for="cat-name">Cat name:</label> + <select id="cat-name-select" name="cat_id" class="form-control"> + <?php foreach ($responseCats as $cat){ + echo ('<option value="' . $cat['cat_id'] . '">' . $cat['name'] . '</option>'); + }?> + </select> + </div> + <div class="form-group"> + <label for="sighting_location">Location:</label> + <textarea id="sighting_location" name="sighting_location" class="form-control"></textarea> + </div> + <div class="form-group"> + <label for="date">Date:</label> + <input type="date" id="date" name="date" class="form-control"> + </div> + <div class="form-group"> + <label for="time">Time:</label> + <input type="time" value="00:00:00" id="time" name="time" class="form-control"> + </div> + <div class="form-group"> + <label for="sighting_description">Description:</label> + <textarea id="sighting_description" name="sighting_description" class="form-control"></textarea> + </div> + <div class="form-group"> + <label for="image_url">Image File (JPG, JPEG, PNG):</label> + <input type="file" id="image_url" name="image_url" class="file-input" + accept=".jpg, .jpeg, .png"> + </div> + <button type="submit" class="submit-button">Add Cat</button> + </form> + </div> + </div> + <button id="add-sighting-button" class="add-button" onclick="openAddSightingModal()">+</button> + </div> + <script src="public/js/sighting.js"></script> +</body> +</html> \ No newline at end of file diff --git a/src/controllers/sightings/SightingController.php b/src/controllers/sightings/SightingController.php new file mode 100644 index 0000000000000000000000000000000000000000..9a9b81011272a29bf41aef744a4d04a8f26c084b --- /dev/null +++ b/src/controllers/sightings/SightingController.php @@ -0,0 +1,94 @@ +<?php + +require_once PROJECT_ROOT_PATH . "/src/bases/BaseController.php"; +require_once PROJECT_ROOT_PATH . "/src/services/SightingSrv.php"; +require_once PROJECT_ROOT_PATH . "/src/utils/FileUploader.php"; +require_once PROJECT_ROOT_PATH . "/src/services/CatSrv.php"; + +class SightingController extends BaseController +{ + protected static $instance; + + private function __construct($srv) + { + parent::__construct($srv); + } + + public static function getInstance() + { + if (!isset(self::$instance)) { + self::$instance = new static( + SightingSrv::getInstance() + ); + } + return self::$instance; + } + + public function get($urlParams) + { + echo $_SESSION['user_id']; + echo ("<br>"); + if (!$urlParams) { + // need join + $sightings = $this->srv->getAll(); +// echo ($sightings); + $responseSightings = array_map(function($sighting) { + return $sighting->toResponse(); + }, $sightings); + + $catSrv = (CatSrv::getInstance()); + $cats = $catSrv->getAll([ + "search" => $_GET['search'] ?? null, + "gender" => $_GET['gender'] ?? null, + "spayed" => $_GET['spayed'] ?? null, + "order" => $_GET['order'] ?? null, + "pageNo" => $_GET['pageNo'] ?? null, + "pageSize" => $_GET['pageSize'] ?? null, + "isDesc" => $_GET['isDesc'] ?? null + ]); + $responseCats = array_map(function ($cat){ + return $cat->toResponse(); + },$cats["result"]); + // Include the HTML template + require_once PROJECT_ROOT_PATH . "/public/view/sighting.php"; + + } else { + // TODO GET CATS WITH ALL SIGHTINGS DO JOIN. + return (new BaseResponse(false, null, "NOT IMPLEMENTED", 404))->toJSON(); + } + } + + public function post($urlParams) + { +// $_POST+=['user_id'=>$_SESSION['user_id']]; +// foreach ($_POST) + $user_id=$_SESSION['user_id']; +// echo $_POST['user_id']; + $cat_id=$_POST['cat_id']; + echo $cat_id; + $sighting_location=$_POST['sighting_location']; + $date=$_POST['date']; + $time=$_POST['time']; + $sighting_description=$_POST['sighting_description']; + $image_url="images/" . handleFileUpload('image_file','public/images/'); + $sightingData = [ + 'user_id' => $user_id, + 'cat_id' => $cat_id, + 'sighting_location' => $sighting_location, + 'date' => $date, + 'time' => $time, + 'sighting_description' => $sighting_description, + 'image_url' => $image_url, + ]; + foreach ($sightingData as $key => $value){ + echo ($key.":" .$value."<br>"); + } + $sighting = $this->srv->createSighting($sightingData); + if ($sighting) { + $response = new BaseResponse(true, $sighting->toResponse(), "Sighting successfully updated", 200); + } else { + $response = new BaseResponse(false, null, "Failed to insert sighting", 400); + } + return $response->toJSON(); + } +} \ No newline at end of file diff --git a/src/models/SightingModel.php b/src/models/SightingModel.php new file mode 100644 index 0000000000000000000000000000000000000000..2f95b492e5b64997a70b4cc5a83a5953af99ef83 --- /dev/null +++ b/src/models/SightingModel.php @@ -0,0 +1,51 @@ +<?php + +require_once PROJECT_ROOT_PATH . "/src/bases/BaseModel.php"; +class SightingModel extends BaseModel { + public $sighting_id; + public $cat_id; + public $user_id; + public $sighting_location; + public $date; + public $time; + public $sighting_description; + public $image_url; + + public $name; + public $description; + public $location; + public $gender; + public $color; + public $spayed; + public $sound_path; + public $image_path; + public $cat_added; + public $email; + public $nama; + public $password; + public $isAdmin; + public $username; + + public $_primary_key = 'sighting_id'; + + public function __construct() { + return $this; + } + + public function constructFromArray($array) { + foreach ($array as $key => $value) { + if (property_exists($this, $key)) { + $this->$key = $value; + } + } + return $this; + } + + public function toArray() { + return get_object_vars($this); + } + + public function toResponse() { + return get_object_vars($this); + } +} diff --git a/src/repositories/SightingRepository.php b/src/repositories/SightingRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..43dc3ad0cd559266d0de6b3d549a46cb889b87c4 --- /dev/null +++ b/src/repositories/SightingRepository.php @@ -0,0 +1,54 @@ +<?php + +require_once PROJECT_ROOT_PATH . "/src/bases/BaseRepository.php"; + +class SightingRepository extends BaseRepository +{ + + protected static $instance; + protected $tableName = 'sightings'; + + private function __construct() + { + parent::__construct(); + } + + public static function getInstance() + { + if (!isset(self::$instance)) { + self::$instance = new static(); + } + return self::$instance; + } + + public function createSighting($sightingData){ +// foreach ($sightingData as $key => $value){ +// echo ($key.":" .$value."<br>"); +// } + return $this->insert($sightingData,array( + 'cat_id' => PDO::PARAM_INT, + 'user_id' => PDO::PARAM_INT, + 'sighting_location' => PDO::PARAM_STR, + 'date' => PDO::PARAM_STR, + 'time' => PDO::PARAM_STR, + 'sighting_description' => PDO::PARAM_STR, + 'image_url' => PDO::PARAM_STR + )); + } + + public function deleteSighting($sighting) + { + return $this->delete("sighting_id", $sighting); + } + + public function join(){ + $sql = "SELECT * FROM sightings s join (cats c, users u) on (c.cat_id=s.cat_id and u.user_id=s.user_id)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + public function getSightingById($sightingId){ + return $this->selectOne("*",["sighting_id = $sightingId"]); + } +} \ No newline at end of file diff --git a/src/services/SightingSrv.php b/src/services/SightingSrv.php new file mode 100644 index 0000000000000000000000000000000000000000..a7d31bf458373ed3ebe51cea0cc9550217063659 --- /dev/null +++ b/src/services/SightingSrv.php @@ -0,0 +1,52 @@ +<?php + +require_once PROJECT_ROOT_PATH . "/src/bases/BaseSrv.php"; +require_once PROJECT_ROOT_PATH . "/src/repositories/SightingRepository.php"; +require_once PROJECT_ROOT_PATH . "/src/models/SightingModel.php"; + +class SightingSrv extends BaseSrv +{ + protected static $instance; + protected function __construct($repository) + { + parent::__construct(); + $this->repository=$repository; + } + + public static function getInstance() + { + if (!isset(self::$instance)) { + self::$instance = new static( + SightingRepository::getInstance() + ); + } + return self::$instance; + } + + public function getAll() + { + // this should be join + $res=$this->repository->join(); + + foreach ($res as $re){ + foreach ($re as $r){ + echo ($r. ","); + } + echo ("<br>"); + } + $sightings=[]; + foreach ($res as $re){ + $sighting = new SightingModel(); + $sightings[]=$sighting->constructFromArray($re); + } + return $sightings; + } + + public function createSighting($sightingData){ + $sighting=(new SightingModel())->constructFromArray($sightingData); + $id=$this->repository->createSighting($sighting->toArray()); + $sqlRes = $this->repository->getSightingById($id); + $sighting = new SightingModel(); + return $sighting->constructFromArray($sqlRes); + } +} \ No newline at end of file