From cd487d155c557c6f37156d75c2620ab336b17ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Ryb=C3=A1rsky?= Date: Sat, 27 Apr 2024 10:30:01 +0200 Subject: [PATCH] Test meme voting --- assets/script.js | 20 ++++++++++++++++ assets/style.css | 15 ++++++++++++ endpoints/meme.php | 4 +++- lib/meme.php | 58 ++++++++++++++++++++++++++++++++++++++++++--- templates/meme.html | 25 ++++++++++++------- 5 files changed, 110 insertions(+), 12 deletions(-) diff --git a/assets/script.js b/assets/script.js index 36ec5f9..7f3155d 100644 --- a/assets/script.js +++ b/assets/script.js @@ -621,4 +621,24 @@ async function getMemeImages() { memeImageSelector.appendChild(option); }); +} + +async function reloadMemeVotes(memeID) { + let memeVoteCounterElement = document.getElementById(`meme_votes_counter_${memeID}`); + + let memeVoteResponse = await doAction('/meme', { + action: "getMemeVotes", + meme_id: memeID + }, "Počet hlasov k meme-u bol stiahnutý", "Nastala chyba pri sťahovaní počtu hlasov k meme-u", true); + + memeVoteCounterElement.innerText = memeVoteResponse.NetVotes; +} + +async function voteMeme(memeID, isUpvote){ + await doAction("/meme", { + action: "voteMeme", + meme_id: memeID, + is_upvote: isUpvote + }, "Meme bol upvotenutý", "Nastala chyba pri upvoteovaní meme-u", true); + await reloadMemeVotes(memeID); } \ No newline at end of file diff --git a/assets/style.css b/assets/style.css index 9b57556..fc47e4f 100644 --- a/assets/style.css +++ b/assets/style.css @@ -356,6 +356,21 @@ div#articleslist>article{ height: auto; } +.meme_info { + display: flex; + flex-direction: row; +} + +.meme { + display: flex; + flex-direction: column; +} + +.meme_body { + display: flex; + flex-direction: column; +} + @media (max-width: 1050px) { div#articleslist { diff --git a/endpoints/meme.php b/endpoints/meme.php index 05d636f..305e78f 100644 --- a/endpoints/meme.php +++ b/endpoints/meme.php @@ -9,6 +9,8 @@ function endpoint($endpoint_data): array "addMeme" => addMeme($endpoint_data['meme_title'], $endpoint_data['meme_text'], $endpoint_data['meme_image_id']), "renderGallery" => renderMemeGallery(), "deleteMeme" => deleteMeme($endpoint_data['meme_id']), - default => ["Status" => "Fail", "message" => "Invalid action"], + "getMemeVotes" => getMemeVotes($endpoint_data['meme_id']), + "voteMeme" => voteMeme($endpoint_data['meme_id'], $endpoint_data['is_upvote']), + default => ["Status" => "Fail", "Message" => "Invalid action"], }; } \ No newline at end of file diff --git a/lib/meme.php b/lib/meme.php index e790072..f11c1f4 100644 --- a/lib/meme.php +++ b/lib/meme.php @@ -27,6 +27,14 @@ function renderMeme(int $id, int $authorId, string $title, string $textContent, $meme_out = str_replace('__TEMPLATE_MEME_IMAGE__', '/' . htmlspecialchars($filePath), $meme_out); $meme_out = str_replace('__TEMPLATE_MEME_DELETE_BUTTON__', (isModerator() || $_SESSION['ID'] == $authorId) ? "" : '', $meme_out); + $meme_votes = calculateNetVotes($id); + $meme_upvote = isLoggedIn() ? "" : ''; + $meme_downvote = isLoggedIn() ? "" : ''; + + $meme_out = str_replace('__TEMPLATE_MEME_VOTES_NUMBER__', $meme_votes, $meme_out); + $meme_out = str_replace('__TEMPLATE_MEME_UPVOTE__', $meme_upvote, $meme_out); + $meme_out = str_replace('__TEMPLATE_MEME_DOWNVOTE__', $meme_downvote, $meme_out); + $meme_out = str_replace('__TEMPLATE_MEME_ID__', $id, $meme_out); return str_replace('__TEMPLATE_MEME_TEXT__', htmlspecialchars($textContent), $meme_out); } @@ -69,7 +77,7 @@ function renderMemeGallery(): string return $meme_gallery_out; } -function deleteMeme(int $memeId): array +function deleteMeme(int $memeID): array { global $mysqli; $out = ["Status" => "Fail"]; @@ -77,14 +85,58 @@ function deleteMeme(int $memeId): array $query = !isModerator() ? 'DELETE FROM Memes WHERE ID = ? AND AuthorID = ?' : 'DELETE FROM Memes WHERE ID = ?'; $stmtDelete = $mysqli->prepare($query); if (!isModerator()) { - $stmtDelete->bind_param('ii', $memeId, $_SESSION['ID']); + $stmtDelete->bind_param('ii', $memeID, $_SESSION['ID']); } else { - $stmtDelete->bind_param('i', $memeId); + $stmtDelete->bind_param('i', $memeID); } $stmtDelete->execute(); if ($stmtDelete->affected_rows > 0) { $out['Status'] = 'Success'; } + $stmtDelete->close(); } return $out; +} + +function voteMeme(int $memeID, bool $isUpvote): array +{ + global $mysqli; + $out = ["Status" => "Fail"]; + $vote = $isUpvote ? 1 : 0; + $memeVoteConn = $mysqli->prepare('INSERT INTO MemeVotes (MemeID, UserID, isUpvote) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE isUpvote = VALUES(isUpvote)'); + $memeVoteConn->bind_param('iii', $memeID, $_SESSION['ID'], $vote); + $memeVoteConn->execute(); + if ($memeVoteConn->affected_rows > 0) { + $out['Status'] = 'Success'; + } + $memeVoteConn->close(); + return $out; +} + +function calculateNetVotes(int $memeID): int +{ + global $mysqli; + + $query = 'SELECT isUpvote FROM MemeVotes WHERE MemeID = ?'; + $stmt = $mysqli->prepare($query); + $stmt->bind_param('i', $memeID); + $stmt->execute(); + $result = $stmt->get_result(); + + $netVotes = 0; + while ($row = $result->fetch_assoc()) { + $netVotes += ($row['isUpvote'] == 1) ? 1 : -1; + } + + $stmt->close(); + + return $netVotes; +} + +function getMemeVotes(int $memeID): array +{ + return [ + "Status" => "Success", + "NetVotes" => calculateNetVotes($memeID) + ]; } \ No newline at end of file diff --git a/templates/meme.html b/templates/meme.html index 030f7fd..139e153 100644 --- a/templates/meme.html +++ b/templates/meme.html @@ -1,10 +1,19 @@ -
-

__TEMPLATE_MEME_TITLE__

-
-

__TEMPLATE_MEME_AUTHOR__

- __TEMPLATE_MEME_DELETE_BUTTON__ -

__TEMPLATE_MEME_DATE__

- meme image -

__TEMPLATE_MEME_TEXT__

+
+
+

__TEMPLATE_MEME_TITLE__

+
+
+ __TEMPLATE_MEME_UPVOTE__ +

__TEMPLATE_MEME_VOTES_NUMBER__

+ __TEMPLATE_MEME_DOWNVOTE__ +
+

__TEMPLATE_MEME_AUTHOR__

+ __TEMPLATE_MEME_DELETE_BUTTON__ +

__TEMPLATE_MEME_DATE__

+
+
+
+ meme image +

__TEMPLATE_MEME_TEXT__

\ No newline at end of file