diff --git a/code/backend/src/controllers/feedController.ts b/code/backend/src/controllers/feedController.ts index d202f7f..e6c7c54 100644 --- a/code/backend/src/controllers/feedController.ts +++ b/code/backend/src/controllers/feedController.ts @@ -2,11 +2,12 @@ import express, { Request, Response } from "express"; import { StatusCodes } from "http-status-codes"; import { PrismaClient, Post } from "../../prisma/app/generated/prisma/client"; import { feedQuerySchema } from "../schemas/feedSchemas"; +import { z } from "zod"; const prisma = new PrismaClient(); export const feed = async (req: Request, res: Response) => { try { const query = feedQuerySchema.parse(req.query); - const take = query.limit || 10; + const take = query.limit; const posts = await prisma.post.findMany({ take: take + 1, @@ -25,6 +26,13 @@ export const feed = async (req: Request, res: Response) => { res.status(200).json({ posts, nextCursor }); } catch (err) { + if (err instanceof z.ZodError) { + res.status(400).json({ + error: "Invalid query parameters", + details: err.errors, + }); + return; + } console.error(err); res.status(400).json({ error: "Invalid query parameters" }); } diff --git a/code/backend/src/controllers/followerController.ts b/code/backend/src/controllers/followerController.ts index bab2056..8911985 100644 --- a/code/backend/src/controllers/followerController.ts +++ b/code/backend/src/controllers/followerController.ts @@ -3,6 +3,7 @@ import express, { Request, Response } from "express"; import { JwtPayload } from "jsonwebtoken"; import { PrismaClient, Follow } from "../../prisma/app/generated/prisma/client"; const prisma = new PrismaClient(); + export const followUser = async (req: Request, res: Response) => { const username: string = req.params.username; const followingUser: JwtPayload = req.user!; @@ -27,7 +28,7 @@ export const followUser = async (req: Request, res: Response) => { }); return; } - if (user.username == username) { + if (user.id == followingUser.sub) { res.status(StatusCodes.BAD_REQUEST).json({ error: "Bad Request", details: [{ message: "You can`t follow yourself" }], diff --git a/code/backend/src/controllers/postController.ts b/code/backend/src/controllers/postController.ts index 6bbb15f..1b79d0b 100644 --- a/code/backend/src/controllers/postController.ts +++ b/code/backend/src/controllers/postController.ts @@ -4,7 +4,6 @@ import { StatusCodes } from "http-status-codes"; import { JwtPayload } from "jsonwebtoken"; import { PrismaClient, Post } from "../../prisma/app/generated/prisma/client"; import { minioClient } from "../server"; -import { object } from "zod"; import { uploadPostSchema } from "../schemas/postSchemas"; dotenv.config(); const prisma = new PrismaClient(); @@ -190,11 +189,20 @@ export const getPost = async (req: Request, res: Response) => { // get all posts from a user export const getUserPosts = async (req: Request, res: Response) => { try { + const user: JwtPayload | undefined = req.user; const username: string = req.params.username; const posts = await prisma.post.findMany({ where: { + ...(user + ? { + OR: [ + { status: "PRIVATE", userId: user.id }, + { status: "PUBLIC" }, + ], + } + : { status: "PUBLIC" }), user: { - username: username, // hier greifst du auf die relationierte User-Tabelle zu + username: username, }, }, }); @@ -329,3 +337,31 @@ export const removeLike = async (req: Request, res: Response) => { }); } }; + +export const getTags = async (req: Request, res: Response) => { + try { + const tags = await prisma.tag.findMany({ + take: 150, + include: { + _count: { + select: { + posts: true, + }, + }, + }, + orderBy: { + posts: { + _count: "desc", + }, + }, + }); + const data: string[] = tags.map((tag) => tag.name); + res.status(StatusCodes.OK).json(data); + } catch (err) { + console.error(err); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: "Failed to retrieve tags", + details: [{ message: "Internal server error" }], + }); + } +}; diff --git a/code/backend/src/controllers/profileController.ts b/code/backend/src/controllers/profileController.ts index ba88950..3ce1644 100644 --- a/code/backend/src/controllers/profileController.ts +++ b/code/backend/src/controllers/profileController.ts @@ -19,6 +19,7 @@ type PublicUser = { profilePictureUrl: string | null; followers: number; following: number; + posts: number; }; const getUser: (userId: string) => Promise = async ( userId: string @@ -47,6 +48,11 @@ const getUser: (userId: string) => Promise = async ( followingUserId: userId, }, }); + const postCount = await prisma.post.count({ + where: { + userId: userId, + }, + }); const publicUser: PublicUser = { id: user.id, username: user.username, @@ -54,6 +60,7 @@ const getUser: (userId: string) => Promise = async ( profilePictureUrl, followers: followerCount, following: followingCount, + posts: postCount, }; return publicUser; } diff --git a/code/backend/src/routes/postRoutes.ts b/code/backend/src/routes/postRoutes.ts index e9556bb..303eea1 100644 --- a/code/backend/src/routes/postRoutes.ts +++ b/code/backend/src/routes/postRoutes.ts @@ -1,6 +1,7 @@ import express from "express"; import { getPost, + getTags, getUserPosts, like, removeLike, @@ -156,4 +157,29 @@ router.post("/like/:postId", authenticateToken(), like); */ router.delete("/removeLike/:postId", authenticateToken(), removeLike); +/** + * @swagger + * /api/posts/tags: + * get: + * summary: Get posttags + * description: Returns posttags + * tags: + * - Posts + * responses: + * 200: + * description: List of tags + * content: + * application/json: + * schema: + * type: object + * properties: + * tags: + * type: array + * items: + * type: string + * 500: + * description: Server error + */ +router.get("/tags", getTags); + export default router; diff --git a/code/backend/src/routes/profileRoutes.ts b/code/backend/src/routes/profileRoutes.ts index ffc8fc2..61ff87a 100644 --- a/code/backend/src/routes/profileRoutes.ts +++ b/code/backend/src/routes/profileRoutes.ts @@ -8,7 +8,7 @@ import { } from "../controllers/profileController"; const profileRouter = express.Router(); import { upload } from "../middleware/uploadSingle"; -import { updateBioSchema } from "../schemas/feedSchemas"; +import { updateBioSchema } from "../schemas/profileSchemas"; import { validateData } from "../middleware/validationMiddleware"; /** * @swagger @@ -97,7 +97,7 @@ profileRouter.get("/getProfilePicture/:username", getProfilePicture); * 401: * description: Unauthorized */ -profileRouter.post( +profileRouter.put( "/updateBio", authenticateToken(), validateData(updateBioSchema), @@ -105,7 +105,7 @@ profileRouter.post( ); /** * @swagger - * /api/profile/get/{username}: + * /api/profile/{username}: * get: * summary: Get user data * tags: [Profile] @@ -124,5 +124,5 @@ profileRouter.post( * 401: * description: Ungültige Anmeldedaten */ -profileRouter.get("/get/:username", getProfile); +profileRouter.get("/:username", getProfile); export default profileRouter; diff --git a/code/backend/src/schemas/feedSchemas.ts b/code/backend/src/schemas/feedSchemas.ts index 4c21275..eb0fca8 100644 --- a/code/backend/src/schemas/feedSchemas.ts +++ b/code/backend/src/schemas/feedSchemas.ts @@ -1,4 +1,4 @@ -import { string, z } from "zod"; +import { z } from "zod"; export const feedQuerySchema = z.object({ createdAt: z.string().datetime().optional(), @@ -7,9 +7,5 @@ export const feedQuerySchema = z.object({ .transform((val) => parseInt(val, 10)) .refine((num) => num > 0 && num <= 30, { message: "Limit must be between 1 and 30", - }) - .optional(), -}); -export const updateBioSchema = z.object({ - bio: z.string(), + }), }); diff --git a/code/backend/src/schemas/profileSchemas.ts b/code/backend/src/schemas/profileSchemas.ts new file mode 100644 index 0000000..4f491e0 --- /dev/null +++ b/code/backend/src/schemas/profileSchemas.ts @@ -0,0 +1,4 @@ +import { z } from "zod"; +export const updateBioSchema = z.object({ + bio: z.string(), +});