From 0c845d208d70e621958073aa516658c07e741442 Mon Sep 17 00:00:00 2001 From: SulthanDA28 <13521159@std.stei.itb.ac.id> Date: Mon, 13 Nov 2023 20:27:01 +0700 Subject: [PATCH] add follow and profile --- src/app/controllers/Home/FollowController.php | 32 +++++ .../controllers/Home/ProfileController.php | 30 +++++ .../Home/ProfileUserController.php | 51 ++++++++ .../controllers/Home/ReplyPostController.php | 2 +- .../controllers/Home/UnfollowController.php | 33 +++++ src/app/controllers/Page/ProfilePage.php | 20 +++ src/app/models/HomeModel.php | 83 +++++++++++- src/app/view/post.php | 2 +- src/app/view/profile.php | 33 +++++ src/app/view/templates/navbar.php | 29 ++++- src/index.php | 16 ++- src/public/css/profile.css | 66 ++++++++++ src/public/css/shared.css | 14 ++ src/public/js/home.js | 2 + src/public/js/post.js | 6 +- src/public/js/profile.js | 121 ++++++++++++++++++ 16 files changed, 532 insertions(+), 8 deletions(-) create mode 100644 src/app/controllers/Home/FollowController.php create mode 100644 src/app/controllers/Home/ProfileController.php create mode 100644 src/app/controllers/Home/ProfileUserController.php create mode 100644 src/app/controllers/Home/UnfollowController.php create mode 100644 src/app/controllers/Page/ProfilePage.php create mode 100644 src/app/view/profile.php create mode 100644 src/public/css/profile.css create mode 100644 src/public/js/profile.js diff --git a/src/app/controllers/Home/FollowController.php b/src/app/controllers/Home/FollowController.php new file mode 100644 index 0000000..c4e16a0 --- /dev/null +++ b/src/app/controllers/Home/FollowController.php @@ -0,0 +1,32 @@ +<?php + +require_once SRC_ROOT_PATH . "/app/baseclasses/BaseController.php"; +require_once SRC_ROOT_PATH . "/app/models/HomeModel.php"; +class FollowController extends BaseController{ + protected static $instance; + public static function getInstance(){ + if(!isset(self::$instance)){ + self::$instance = new static(HomeModel::getInstance()); + } + return self::$instance; + } + public function post($urlParams){ + $userid = $_POST['userid']; + $data = $this->srv->follow($userid); + if($data){ + return json_encode(array( + 'status' => 'success', + 'message' => 'Success to follow user', + )); + } + else{ + return json_encode(array( + 'status' => 'failed', + 'message' => 'Failed to follow user', + )); + } + + } +} + +?> \ No newline at end of file diff --git a/src/app/controllers/Home/ProfileController.php b/src/app/controllers/Home/ProfileController.php new file mode 100644 index 0000000..44bb1d9 --- /dev/null +++ b/src/app/controllers/Home/ProfileController.php @@ -0,0 +1,30 @@ +<?php + +require_once SRC_ROOT_PATH . "/app/baseclasses/BaseController.php"; +require_once SRC_ROOT_PATH . "/app/models/HomeModel.php"; +class ProfileController extends BaseController{ + protected static $instance; + public static function getInstance(){ + if(!isset(self::$instance)){ + self::$instance = new static(HomeModel::getInstance()); + } + return self::$instance; + } + public function get($urlParams){ + $data = $this->srv->getProfile(); + if($data){ + return json_encode(array( + 'status' => 'success', + 'data' => $data + )); + } + else{ + return json_encode(array( + 'status' => 'failed', + 'message' => 'Failed to get profile', + )); + } + } +} + +?> \ No newline at end of file diff --git a/src/app/controllers/Home/ProfileUserController.php b/src/app/controllers/Home/ProfileUserController.php new file mode 100644 index 0000000..4a49753 --- /dev/null +++ b/src/app/controllers/Home/ProfileUserController.php @@ -0,0 +1,51 @@ +<?php + +require_once SRC_ROOT_PATH . "/app/baseclasses/BaseController.php"; +require_once SRC_ROOT_PATH . "/app/models/HomeModel.php"; +class ProfileUserController extends BaseController{ + protected static $instance; + public static function getInstance(){ + if(!isset(self::$instance)){ + self::$instance = new static(HomeModel::getInstance()); + } + return self::$instance; + } + public function get($urlParams){ + $userid = $urlParams[0]; + $data = $this->srv->getProfileUser($userid); + if($data){ + return json_encode(array( + 'status' => 'success', + 'data' => $data + )); + } + else{ + $data2 = $this->srv->getProfileID($userid); + if($data2){ + if($data2['id']==$_SESSION['user_id']){ + $hasil =json_encode(array( + 'status' => 'success3', + 'data' => $data2 + )); + return $hasil; + } + else{ + $hasil =json_encode(array( + 'status' => 'success2', + 'data' => $data2 + )); + return $hasil; + } + } + else{ + return json_encode(array( + 'status' => 'failed', + 'data' => null + )); + } + } + + } +} + +?> \ No newline at end of file diff --git a/src/app/controllers/Home/ReplyPostController.php b/src/app/controllers/Home/ReplyPostController.php index 37b5a4f..0cb69d1 100644 --- a/src/app/controllers/Home/ReplyPostController.php +++ b/src/app/controllers/Home/ReplyPostController.php @@ -24,7 +24,7 @@ class ReplyPostController extends BaseController{ else{ return json_encode(array( 'status' => 'failed', - 'message' => 'Cannot reply own post' + 'message' => 'Cannot reply post. You must post something or there is something wrong' )); } } diff --git a/src/app/controllers/Home/UnfollowController.php b/src/app/controllers/Home/UnfollowController.php new file mode 100644 index 0000000..7432890 --- /dev/null +++ b/src/app/controllers/Home/UnfollowController.php @@ -0,0 +1,33 @@ +<?php + +require_once SRC_ROOT_PATH . "/app/baseclasses/BaseController.php"; +require_once SRC_ROOT_PATH . "/app/models/HomeModel.php"; +class UnfollowController extends BaseController{ + protected static $instance; + public static function getInstance(){ + if(!isset(self::$instance)){ + self::$instance = new static(HomeModel::getInstance()); + } + return self::$instance; + } + public function delete($urlParams){ + parse_str(file_get_contents('php://input'), $_DELETE); + $userid = $_DELETE['userid']; + $data = $this->srv->unfollow($userid); + if($data){ + return json_encode(array( + 'status' => 'success', + 'message' => 'Success to unfollow user', + )); + } + else{ + return json_encode(array( + 'status' => 'failed', + 'message' => 'Failed to unfollow user', + )); + } + + } +} + +?> \ No newline at end of file diff --git a/src/app/controllers/Page/ProfilePage.php b/src/app/controllers/Page/ProfilePage.php new file mode 100644 index 0000000..8ce3ca7 --- /dev/null +++ b/src/app/controllers/Page/ProfilePage.php @@ -0,0 +1,20 @@ +<?php +require_once SRC_ROOT_PATH . "/app/baseclasses/BaseController.php"; +class ProfilePage extends BaseController{ + protected static $instance; + + public function __construct(){ + parent::__construct(null); + } + public static function getInstance(){ + if(!isset(self::$instance)){ + self::$instance = new static(); + } + return self::$instance; + } + public function get($urlParams){ + require PAGE_PATH . "/profile.php"; + exit(); + } +} +?> \ No newline at end of file diff --git a/src/app/models/HomeModel.php b/src/app/models/HomeModel.php index 12e499c..2ba3ec7 100644 --- a/src/app/models/HomeModel.php +++ b/src/app/models/HomeModel.php @@ -19,7 +19,7 @@ class HomeModel try{ $db = PDOHandler::getInstance()->getPDO(); $page = $page * 10; - $sql = "SELECT p.post_id,u.id,u.username,u.profile_name,u.profile_picture_path,p.body,pr.path FROM posts as p LEFT JOIN post_resources as pr ON p.post_id=pr.post_id AND p.owner_id=pr.post_owner_id JOIN users as u ON p.owner_id=u.id WHERE p.refer_type IS NULL ORDER BY p.post_id DESC LIMIT 10 OFFSET $page"; + $sql = "SELECT p.post_id,u.id,u.username,u.profile_name,u.profile_picture_path,p.body,pr.path FROM posts as p LEFT JOIN post_resources as pr ON p.post_id=pr.post_id AND p.owner_id=pr.post_owner_id JOIN users as u ON p.owner_id=u.id WHERE p.refer_type IS NULL ORDER BY p.created_at DESC LIMIT 10 OFFSET $page"; $count = "SELECT COUNT(*) as count FROM posts as p LEFT JOIN post_resources as pr ON p.post_id=pr.post_id AND p.owner_id=pr.post_owner_id JOIN users as u ON p.owner_id=u.id WHERE p.refer_type IS NULL"; $result = $db->query($sql); $result2 = $db->query($count); @@ -140,6 +140,87 @@ class HomeModel return false; } } + public function getProfile(){ + try{ + $user_id = $_SESSION['user_id']; + $db = PDOHandler::getInstance()->getPDO(); + $sql = "SELECT * FROM users WHERE id=$user_id"; + $result = $db->query($sql); + if($result){ + return $result->fetch(PDO::FETCH_ASSOC); + } + else{ + return false; + } + }catch(Exception $e){ + return false; + } + } + public function getProfileUser($userid){ + try{ + $current = $_SESSION['user_id']; + $db = PDOHandler::getInstance()->getPDO(); + $sql = "SELECT * FROM users as u LEFT JOIN follows as f ON u.id = f.followed_user_id WHERE u.id=$userid AND f.following_user_id=$current"; + $result = $db->query($sql); + if($result){ + $data = $result->fetch(PDO::FETCH_ASSOC); + return $data; + } + else{ + return false; + } + + }catch(Exception $e){ + return false; + } + } + public function getProfileID($user_id){ + try{ + $db = PDOHandler::getInstance()->getPDO(); + $sql = "SELECT * FROM users WHERE id=$user_id"; + $result = $db->query($sql); + if($result){ + return $result->fetch(PDO::FETCH_ASSOC); + } + else{ + return false; + } + }catch(Exception $e){ + return false; + } + } + public function follow($userid){ + try{ + $current = $_SESSION['user_id']; + $db = PDOHandler::getInstance()->getPDO(); + $sql = "INSERT INTO follows (following_user_id,followed_user_id) VALUES ($current,$userid),($userid,$current)"; + $result = $db->query($sql); + if($result){ + return true; + } + else{ + return false; + } + }catch(Exception $e){ + return false; + } + } + public function unfollow($userid){ + try{ + $current = $_SESSION['user_id']; + $db = PDOHandler::getInstance()->getPDO(); + $sql = "DELETE FROM follows WHERE (following_user_id=$current AND followed_user_id=$userid) OR (following_user_id=$userid AND followed_user_id=$current)"; + $result = $db->query($sql); + if($result){ + return true; + } + else{ + return false; + } + }catch(Exception $e){ + return false; + } + } } ?> \ No newline at end of file diff --git a/src/app/view/post.php b/src/app/view/post.php index bd9d1e6..868d651 100644 --- a/src/app/view/post.php +++ b/src/app/view/post.php @@ -9,7 +9,7 @@ require_once PAGE_PATH . "/templates/navbar.php"; <link rel="stylesheet" href="/public/css/home.css" /> <link rel="stylesheet" href="/public/css/shared.css" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Document</title> + <title>Home</title> </head> <body> <div class="layout"> diff --git a/src/app/view/profile.php b/src/app/view/profile.php new file mode 100644 index 0000000..de89ddb --- /dev/null +++ b/src/app/view/profile.php @@ -0,0 +1,33 @@ +<?php +require_once PAGE_PATH . "/templates/navbar.php"; +?> + +<!DOCTYPE html> +<html> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Profile</title> + <link rel="stylesheet" href="/public/css/shared.css" /> + <link rel="stylesheet" href="/public/css/profile.css" /> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"> +</head> + +<body> + <div class="layout"> + <?php + echo Navbar(); + ?> + <div class="box" id="box"> + <div class="iden"> + <img src="/public/assets/kajuha.jpg" alt="" class="fotoprofil"> + <div class="kolom"> + <p id="namaprofile"></p> + <p id="username"></p> + </div> + </div> + </div> + </div> + <script src="/public/js/profile.js"></script> +</body> +</html> \ No newline at end of file diff --git a/src/app/view/templates/navbar.php b/src/app/view/templates/navbar.php index e036bd4..261ad0c 100644 --- a/src/app/view/templates/navbar.php +++ b/src/app/view/templates/navbar.php @@ -22,8 +22,8 @@ function Navbar() Followed </div> </a> - <a href="#"> - <div class="sidebar-menu__item"> + <a href="/profiles"> + <div class="sidebar-menu__item sidebar-menu__item--active"> <img src="/public/assets/profile.svg" class="sidebar-menu__item-icon" /> Profile </div> @@ -33,6 +33,31 @@ function Navbar() Post </div> </a> + <a href="/login"> + <div class="sidebar-menu__compose_logout" id="logout"> + Logout + </div> + </a> + <script> + document.getElementById("logout").addEventListener("click", function() { + const xhr = new XMLHttpRequest(); + const url = 'http://localhost:8008/api/logout'; + + xhr.open('GET', url, true); + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + alert("Berhasil Logout"); + } else { + console.error('Gagal melakukan permintaan'); + } + } + }; + xhr.send(); + }); + </script> </div> </div> EOT; diff --git a/src/index.php b/src/index.php index a6ce3f1..4c0dad4 100644 --- a/src/index.php +++ b/src/index.php @@ -22,6 +22,10 @@ require_once CONTROLLER_PATH . "/Home/GetPostIDController.php"; require_once CONTROLLER_PATH . "/Home/ReplyPostController.php"; require_once CONTROLLER_PATH . "/Home/GetReplyPostController.php"; require_once CONTROLLER_PATH . "/Home/ClickPostController.php"; +require_once CONTROLLER_PATH . "/Home/ProfileController.php"; +require_once CONTROLLER_PATH . "/Home/ProfileUserController.php"; +require_once CONTROLLER_PATH . "/Home/FollowController.php"; +require_once CONTROLLER_PATH . "/Home/UnfollowController.php"; require_once CONTROLLER_PATH . "/Page/HomePage.php"; require_once CONTROLLER_PATH . "/Page/LoginPage.php"; @@ -32,6 +36,8 @@ require_once CONTROLLER_PATH . "/Page/UserPage.php"; require_once CONTROLLER_PATH . "/Page/HomePage.php"; require_once CONTROLLER_PATH . "/Page/PostPage.php"; require_once CONTROLLER_PATH . "/Page/AdminPageUnban.php"; +require_once CONTROLLER_PATH . "/Page/ProfilePage.php"; + require_once MIDDLEWARE_PATH . "/CheckAdmin.php"; require_once MIDDLEWARE_PATH . "/CheckLogin.php"; @@ -54,16 +60,24 @@ $router->addHandler("/api/getpostid/*/*", GetPostIDController::getInstance(), [] $router->addHandler("/api/reply/*/*", ReplyPostController::getInstance(), []); $router->addHandler("/api/getreply/*/*", GetReplyPostController::getInstance(), []); $router->addHandler("/api/clickpost", ClickPostController::getInstance(), []); +$router->addHandler("/api/profile", ProfileController::getInstance(), []); +$router->addHandler("/api/profileuser/*", ProfileUserController::getInstance(), []); +$router->addHandler("/api/follow", FollowController::getInstance(), []); +$router->addHandler("/api/unfollow", UnfollowController::getInstance(), []); $router->addHandler("/", HomePage::getInstance(), []); $router->addHandler("/login", LoginPage::getInstance(), []); $router->addHandler("/compose/kicau", ComposePage::getInstance(), [CheckLogin::getInstance()]); $router->addHandler("/compose/create", PostController::getInstance(), [CheckLogin::getInstance()]); -$router->addHandler("/*", UserPage::getInstance(), []); +// $router->addHandler("/*", UserPage::getInstance(), []); $router->addHandler("/settings/*", SettingsPage::getInstance(), [CheckLogin::getInstance()]); $router->addHandler("/admin/*", AdminPage::getInstance(), [CheckAdmin::getInstance()]); $router->addHandler("/admin/unban/*", AdminPageUnban::getInstance(), [CheckAdmin::getInstance()]); $router->addHandler("/post/*/*", PostPage::getInstance(), []); +$router->addHandler("/profiles", ProfilePage::getInstance(), []); +$router->addHandler("/profiles/*", ProfilePage::getInstance(), []); + + $router->run($_SERVER['REQUEST_URI'], $_SERVER['REQUEST_METHOD']); \ No newline at end of file diff --git a/src/public/css/profile.css b/src/public/css/profile.css new file mode 100644 index 0000000..2ebc094 --- /dev/null +++ b/src/public/css/profile.css @@ -0,0 +1,66 @@ +.box { + border: 2px solid #333; + padding: 20px; + max-width: 600px; + margin-top: 10px; + display: flex; + flex-direction: column; + width: 600px; + word-wrap: break-word; + overflow: hidden; + border-radius: 20px; +} +.iden{ + display: flex; + word-wrap: break-word; + overflow: hidden; + max-width: 100%; +} +.fotoprofil{ + border-radius: 100%; + width: 100px; + height: 100px; + margin-left: 10px; + margin-right: 10px; + margin-bottom: 10px; + margin-top: 10px; + float: left; + +} +.kolom{ + display: flex; + flex-direction: column; + word-wrap: break-word; + overflow: hidden; + max-width: 100%; +} +.buttonfollow{ + margin-top: 10px; + margin-bottom: 10px; + margin-left: 10px; + margin-right: 10px; + width: 100px; + height: 30px; + border-radius: 10px; + background-color: #1DA1F2; + color: white; + border: none; + font-size: 15px; + font-weight: bold; + cursor: pointer; +} +.buttonunfollow{ + margin-top: 10px; + margin-bottom: 10px; + margin-left: 10px; + margin-right: 10px; + width: 100px; + height: 30px; + border-radius: 10px; + background-color: #FF0000; + color: white; + border: none; + font-size: 15px; + font-weight: bold; + cursor: pointer; +} \ No newline at end of file diff --git a/src/public/css/shared.css b/src/public/css/shared.css index 2596d2e..07e0f2b 100644 --- a/src/public/css/shared.css +++ b/src/public/css/shared.css @@ -87,6 +87,20 @@ body{ font-weight: 700; color: #ffffff; + justify-content: center; + align-items: center; +} +.sidebar-menu__compose_logout { + margin-top: 10px; + display: flex; + padding: 15px; + border-radius: 30px; + background: #FF0000; + + font-size: 19px; + font-weight: 700; + color: #ffffff; + justify-content: center; align-items: center; } \ No newline at end of file diff --git a/src/public/js/home.js b/src/public/js/home.js index 9bd623f..6a56902 100644 --- a/src/public/js/home.js +++ b/src/public/js/home.js @@ -111,6 +111,7 @@ function gotoPost(postid,ownerid){ } function gotoProfile(userid){ console.log(userid,"user"); + window.location.href = "/profiles/"+userid; } function likeId(postid,userid){ console.log("like",postid); @@ -127,6 +128,7 @@ function likeId(postid,userid){ } else if(response.status==="success"){ console.log(response); + alert("Like post success"); } } else { console.error('Gagal melakukan permintaan'); diff --git a/src/public/js/post.js b/src/public/js/post.js index 198f96e..9dfffa3 100644 --- a/src/public/js/post.js +++ b/src/public/js/post.js @@ -26,7 +26,8 @@ function makePostID(element){ } const identitas = document.createElement('div'); - identitas.classList.add('iden-post'); + identitas.classList.add('iden'); + identitas.addEventListener('click',function(){window.location.href = '/profiles/'+ownerid}); identitas.appendChild(fotoprofile); identitas.appendChild(simpanidentitas); box.appendChild(identitas); @@ -90,7 +91,8 @@ function makeReply(element){ } const identitas = document.createElement('div'); - identitas.classList.add('iden-post'); + identitas.classList.add('iden'); + identitas.addEventListener('click',function(){window.location.href = '/profiles/'+element.id}); identitas.appendChild(fotoprofile); identitas.appendChild(simpanidentitas); box.appendChild(identitas); diff --git a/src/public/js/profile.js b/src/public/js/profile.js new file mode 100644 index 0000000..aead17e --- /dev/null +++ b/src/public/js/profile.js @@ -0,0 +1,121 @@ +const namaprofile = document.getElementById('namaprofile'); +const username = document.getElementById('username'); + + +let currUrl = window.location.href; +let splitUrl = currUrl.split('/'); +if(splitUrl[splitUrl.length-1] == "profiles"){ + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/api/profile'); + xhr.setRequestHeader('Content-type', 'application/json'); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + const response = JSON.parse(xhr.responseText); + if(response.status==="failed"){ + alert(response.message); + } + else{ + namaprofile.textContent = response.data.profile_name; + username.textContent = "@"+response.data.username; + } + } else { + console.error('Gagal melakukan permintaan'); + } + } + }; + xhr.send(); +} +else{ + let id = splitUrl[splitUrl.length-1]; + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/api/profileuser/'+id); + xhr.setRequestHeader('Content-type', 'application/json'); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + const response = JSON.parse(xhr.responseText); + console.log(response); + if(response.status==="success2"){ + namaprofile.textContent = response.data.profile_name; + username.textContent = "@"+response.data.username; + const buttonfollow = document.createElement('button'); + buttonfollow.classList.add('buttonfollow'); + buttonfollow.textContent = "Follow"; + buttonfollow.addEventListener('click', function(){ + follow(id); + }); + const box = document.getElementById('box'); + box.appendChild(buttonfollow); + } + else if(response.status==="success"){ + namaprofile.textContent = response.data.profile_name; + username.textContent = "@"+response.data.username; + const buttonfollow = document.createElement('button'); + buttonfollow.classList.add('buttonunfollow'); + buttonfollow.textContent = "Unfollow"; + buttonfollow.addEventListener('click', function(){ + unfollow(id); + }); + const box = document.getElementById('box'); + box.appendChild(buttonfollow); + } + else if(response.status==="success3"){ + window.location.href = '/profiles'; + } + else{ + window.location.href = '/'; + } + } else { + console.error('Gagal melakukan permintaan'); + } + } + }; + xhr.send(); +} + +function follow(id){ + const xhr = new XMLHttpRequest(); + xhr.open('POST', '/api/follow'); + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + const response = JSON.parse(xhr.responseText); + if(response.status==="failed"){ + alert(response.message); + } + else{ + alert(response.message); + window.location.reload(); + } + } else { + console.error('Gagal melakukan permintaan'); + } + } + }; + xhr.send(`userid=${encodeURIComponent(id)}`); +} + +function unfollow(id){ + const xhr = new XMLHttpRequest(); + xhr.open('DELETE', '/api/unfollow'); + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + const response = JSON.parse(xhr.responseText); + if(response.status==="failed"){ + alert(response.message); + } + else{ + alert(response.message); + window.location.reload(); + } + } else { + console.error('Gagal melakukan permintaan'); + } + } + }; + xhr.send(`userid=${encodeURIComponent(id)}`); +} \ No newline at end of file -- GitLab