import express, { Request, Response } from "express"; import dotenv from "dotenv"; 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(); export const uploadPost = async (req: Request, res: Response) => { const files = req.files as Express.Multer.File[]; // Mehrere Dateien // Cast req.file to Express.Multer.File there is no need to check if file is undefined since it is already checked in the middleware const user: JwtPayload = req.user!; // Get the user from the request const { description, status, tags } = uploadPostSchema.parse(req.body); const BUCKET = "images"; // Name of the bucket where the images are stored try { const uploads = await Promise.all( files.map(async (file) => { const objectName = `${user.sub}/posts/${Date.now()}-${file.originalname}`; await minioClient.putObject(BUCKET, objectName, file.buffer); const url = await minioClient.presignedGetObject( BUCKET, objectName, 60 * 10 ); return { originalName: file.originalname, objectName: objectName, size: file.size, mimetype: file.mimetype, url: url, }; }) ); const post: Post | null = await prisma.post.create({ data: { userId: user.sub!, description: description, status: status, media: { create: uploads.map((upload) => ({ originalFilename: upload.originalName, objectName: upload.objectName, size: upload.size, mimeType: upload.mimetype, bucket: BUCKET, uploader: { connect: { id: user.sub! } }, })), }, postTags: { create: tags.map((tag: string) => ({ tag: { connectOrCreate: { where: { name: tag }, create: { name: tag } }, }, })), }, }, }); // create a new post in the database res.status(StatusCodes.CREATED).json({ message: "Upload successful", post: post, }); } catch (err) { console.error(err); res .status(StatusCodes.INTERNAL_SERVER_ERROR) .json({ error: "Upload failed" }); } }; // get post from postId export const getPost = async (req: Request, res: Response) => { try { // get the postId from the request const postId: string = req.query.postId as string; const user: JwtPayload | undefined = req.user; const postObject = await prisma.post.findFirst({ // find the post by id where: { id: postId, ...(user ? { OR: [ { status: "PRIVATE", userId: user.id }, { status: "PUBLIC" }, ], } : { status: "PUBLIC" }), }, include: { user: true, media: true, postTags: { include: { tag: true, }, }, }, }); const likes: number = await prisma.like.count({ where: { postId: postId, }, }); if (!postObject) { res.status(StatusCodes.NOT_FOUND).json({ error: "Post not found", details: [ { message: `The Post does not exist`, }, ], }); return; } let isFollowing = false; if (user) { const following = await prisma.follow.findUnique({ where: { followingUserId_followedUserId: { followingUserId: user.sub!, followedUserId: postObject.userId, }, }, }); if (following) { isFollowing = true; } } const images = await Promise.all( // generate the presigned url for each image postObject?.media.map(async (image) => { try { await minioClient.statObject(image.bucket, image.objectName); return { originalName: image.originalFilename, mimetype: image.mimeType, url: await minioClient.presignedGetObject( image.bucket, image.objectName, 60 * 5 ), }; } catch (err) { return null; } }) ?? [] ); // map the images to the presigned urls res.status(StatusCodes.OK).json({ description: postObject.description, status: postObject.status, likes: likes, tags: postObject.postTags.map((tag) => tag.tag.name), user: { id: postObject.user.id, name: postObject.user.username, }, createdAt: postObject.createdAt, updatedAt: postObject.updatedAt, images: images.filter((image) => image !== null), // filter out the null images following: isFollowing, }); return; } catch (err: any) { if (err.code === "NotFound") { // Handle the case where the object does not exist res.status(StatusCodes.NOT_FOUND).json({ error: "Image not found", details: [ { message: `The image does not exist in the bucket `, }, ], }); return; } console.error(err); res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: "Failed to retrieve post", details: [{ message: "Server error" }], }); return; } }; // get all posts from a user export const getUserPosts = async (req: Request, res: Response) => { try { const username: string = req.params.username; const posts = await prisma.post.findMany({ where: { user: { username: username, // hier greifst du auf die relationierte User-Tabelle zu }, }, }); if (!posts || posts.length === 0) { res.status(StatusCodes.NOT_FOUND).json({ error: "No posts found", details: [ { message: `The user does not have any posts`, }, ], }); return; } res.status(StatusCodes.OK).json({ posts: posts, }); } catch (err: any) { console.error(err); res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: "Failed to retrieve posts", details: [{ message: "Server error" }], }); return; } }; export const like = async (req: Request, res: Response) => { const postId: string = req.params.postId; const user: JwtPayload = req.user!; if (!postId) { res.status(StatusCodes.BAD_REQUEST).json({ error: "no username", details: [{ message: "Username is required" }], }); return; } try { const post = await prisma.post.findUnique({ where: { id: postId }, }); if (!post) { res.status(StatusCodes.NOT_FOUND).json({ error: "Post not found", details: [{ message: `Post with PostId '${postId}' does not exist.` }], }); return; } const alreadyLiked = await prisma.like.findUnique({ where: { postId_userId: { postId: postId, userId: user.sub!, }, }, }); if (alreadyLiked) { res.status(StatusCodes.CONFLICT).json({ error: "Already following", details: [{ message: "You are already following this User" }], }); return; } const follow = await prisma.like.create({ data: { postId: postId, userId: user.sub!, }, }); res.status(StatusCodes.NO_CONTENT).send(); return; } catch (err) { console.error(err); res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: "Upload failed", details: [{ message: "Internal server error" }], }); } }; export const removeLike = async (req: Request, res: Response) => { const postId: string = req.params.postId; const user: JwtPayload = req.user!; if (!postId) { res.status(StatusCodes.BAD_REQUEST).json({ error: "no postId", details: [{ message: "postId is required" }], }); return; } try { const post = await prisma.post.findUnique({ where: { id: postId }, }); if (!post) { res.status(StatusCodes.NOT_FOUND).json({ error: "Post not found", details: [{ message: `Post with PostId '${postId}' does not exist.` }], }); return; } const alreadyLiked = await prisma.like.findUnique({ where: { postId_userId: { postId: postId!, userId: user.sub!, }, }, }); if (!alreadyLiked) { res.status(StatusCodes.CONFLICT).json({ error: "Already following", details: [{ message: "You are already following this User" }], }); return; } const follow = await prisma.like.delete({ where: { postId_userId: { postId: postId, userId: user.sub!, }, }, }); res.status(StatusCodes.NO_CONTENT).send(); return; } catch (err) { console.error(err); res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: "Upload failed", details: [{ message: "Internal server error" }], }); } };