diff --git a/server/my_sql/create_tables.sql b/server/my_sql/create_tables.sql index 5f92225..6997d64 100644 --- a/server/my_sql/create_tables.sql +++ b/server/my_sql/create_tables.sql @@ -151,3 +151,13 @@ CREATE TABLE IF NOT EXISTS posts ( FOREIGN KEY (post_plant_id) REFERENCES plants(id), FOREIGN KEY (post_user_id) REFERENCES users(id) ); + +-- Likes +CREATE TABLE IF NOT EXISTS likes ( + id INT NOT NULL AUTO_INCREMENT, + like_post_id INT, + like_user_id INT, + PRIMARY KEY (id), + FOREIGN KEY (like_post_id) REFERENCES posts(id), + FOREIGN KEY (like_user_id) REFERENCES users(id) +); \ No newline at end of file diff --git a/website/public/media/images/Liked.svg b/website/public/media/images/Liked.svg new file mode 100644 index 0000000..fee5114 --- /dev/null +++ b/website/public/media/images/Liked.svg @@ -0,0 +1,4 @@ + + + diff --git a/website/src/lib/databse.ts b/website/src/lib/databse.ts index 4c5cbbc..bac5615 100644 --- a/website/src/lib/databse.ts +++ b/website/src/lib/databse.ts @@ -97,6 +97,10 @@ export class SQLDatabase { post_date: string; post_image: string; + // Likes Table + like_post_id: string; + like_user_id: string; + constructor() { this.database = "rongoa8jwons3_rongoadb" @@ -187,6 +191,10 @@ export class SQLDatabase { this.post_date = "post_date"; this.post_image = "post_image"; + + // Likes Table + this.like_post_id = "like_post_id"; + this.like_user_id = "like_user_id"; } } diff --git a/website/src/pages/admin/settings.tsx b/website/src/pages/admin/settings.tsx index 0adc3db..e9837dd 100644 --- a/website/src/pages/admin/settings.tsx +++ b/website/src/pages/admin/settings.tsx @@ -6,19 +6,21 @@ import {useSession} from "next-auth/react"; import {makeRequestWithToken} from "@/lib/api_tools"; import {globalStyles} from "@/lib/global_css"; import { useLogger } from 'next-axiom'; -import {FileInput, ValidationState} from "@/components/input_sections"; +import {FileInput, SmallInput, ValidationState} from "@/components/input_sections"; import {useRouter} from "next/router"; import {Layout} from "@/components/layout"; +import {RongoaUser, UserDatabaseDetails} from "@/lib/users"; export default function Admin(){ const pageName = "Admin"; const log = useLogger(); const router = useRouter() - const { data: session } = useSession() + const { data: session, update } = useSession() // Back up file const [fileError, setFileError] = useState(""); const [fileState, setFileState] = useState("normal"); + const [userId, setUserId] = useState(""); // Load the data const [loadingMessage, setLoadingMessage] = useState("") @@ -119,6 +121,31 @@ export default function Admin(){ window.location.reload() } + const submitSudo = async () => { + + // Get the user data + const user = await makeRequestWithToken('get', `/api/user/data?id=${userId}`) + const userData = user.data.data as UserDatabaseDetails + + // Set the session + await update({ + database: { + id: userData.id, + user_name: userData.user_name, + user_email: userData.user_email, + user_image: userData.user_image, + user_type: userData.user_type, + user_last_login: userData.user_last_login, + user_restricted_access: userData.user_restricted_access + + } + }).then(r => console.log(r)) + + // Redirect to the account page + await router.push("/account") + + } + return ( <> @@ -158,6 +185,10 @@ export default function Admin(){

Import Back Up

+ +

Sudo Mode

+ + diff --git a/website/src/pages/api/posts/likes.ts b/website/src/pages/api/posts/likes.ts new file mode 100644 index 0000000..e9ebd08 --- /dev/null +++ b/website/src/pages/api/posts/likes.ts @@ -0,0 +1,88 @@ +import {NextApiRequest, NextApiResponse} from 'next'; +import {getClient, getTables, makeQuery} from "@/lib/databse"; +import {getServerSession} from "next-auth"; +import {authOptions} from "@/pages/api/auth/[...nextauth]"; +import {checkApiPermissions} from "@/lib/api_tools"; +import {getStrings, RongoaUser} from "@/lib/users"; +import { Logger } from 'next-axiom'; +export default async function handler( + request: NextApiRequest, + response: NextApiResponse, +) { + + // Get the client + const client = await getClient() + + // Get the logger + const logger = new Logger() + + // Get the tables + const tables = getTables(); + + // Check if the user is permitted to access the API + const session = await getServerSession(request, response, authOptions) + let permission = await checkApiPermissions(request, response, session, client, makeQuery, "api:user:follow:access") + if (!permission) return response.status(401).json({error: "Not Authorized"}) + + let query = '' + + const {id, publicUserID} = request.query; + + try { + + // Get the session + const session = await getServerSession(request, response, authOptions) + + // If there is no session then return an error + if (!session || !session.user) { + return response.status(401).json({error: 'User not logged in'}); + } + + // Get the user details + const user = session.user as RongoaUser; + const userId = user.database.id; + + // Get the operation + const {operation, id} = request.query; + if (!operation) { + return response.status(400).json({error: 'No operation specified'}); + } + + switch (operation) { + + case "likes": + query = `SELECT COUNT(*) FROM likes WHERE ${tables.like_post_id} = ${id}`; + break; + + case "like": + query = `INSERT INTO likes (${tables.like_user_id}, ${tables.like_post_id}) VALUES (${userId}, ${id})`; + break; + + case "unlike": + query = `DELETE FROM likes WHERE ${tables.like_user_id} = ${userId} AND ${tables.like_post_id} = ${id}`; + break; + + case "check": + query = `SELECT COUNT(*) FROM likes WHERE ${tables.like_user_id} = ${userId} AND ${tables.like_post_id} = ${id}`; + break; + + case "list": + query = `SELECT * FROM likes WHERE ${tables.like_user_id} = ${userId}`; + break; + + default: + return response.status(400).json({error: 'Invalid operation'}); + + } + + const follow = await makeQuery(query, client) + return response.status(200).json({data: follow}); + + // Execute the query + + + } catch (e : any) { + logger.error(e) + return response.status(500).json({error: 'Internal Server Error'}) + } +} diff --git a/website/src/pages/media/components/cards.tsx b/website/src/pages/media/components/cards.tsx index 5461007..bea0716 100644 --- a/website/src/pages/media/components/cards.tsx +++ b/website/src/pages/media/components/cards.tsx @@ -32,6 +32,7 @@ export function PostCard(props: PostCardProps) { const [likes, setLikes] = useState(0) const [plantName, setPlantName] = useState("Loading...") const [width, setWidth] = useState(0) + const [liked, setLiked] = useState(false) const router = useRouter(); const dataFetch = useRef(false); @@ -116,7 +117,14 @@ export function PostCard(props: PostCardProps) { } // Get the likes - //todo + const likes = await makeRequestWithToken("get", `/api/posts/likes?operation=likes&id=${props.id}`); + setLikes(likes.data.data[0]["COUNT(*)"]); + + // Check if the user has liked the post + const liked = await makeRequestWithToken("get", `/api/posts/likes?operation=check&id=${props.id}`); + if(liked.data.data[0]["COUNT(*)"] > 0) { + setLiked(true); + } } @@ -126,6 +134,26 @@ export function PostCard(props: PostCardProps) { router.push("/media/profile?id="+props.post_user_id) } + const likePost = async () => { + await makeRequestWithToken("post", `/api/posts/likes?operation=like&id=${props.id}`); + } + + const unlikePost = async () => { + await makeRequestWithToken("post", `/api/posts/likes?operation=unlike&id=${props.id}`); + } + + const toggleLike = async () => { + if(liked) { + setLiked(false); + await unlikePost(); + setLikes(likes - 1); + } else { + setLiked(true); + await likePost(); + setLikes(likes + 1); + } + } + return( <>
@@ -151,8 +179,8 @@ export function PostCard(props: PostCardProps) {
Share -