Source: controllers/postController.ts

import { PrismaClient } from '@prisma/client';
import { Request, Response } from 'express';
import Joi from 'joi';

const prisma = new PrismaClient();

// Define validation schema for post creation and update
const postSchema = Joi.object({
  title: Joi.string().min(3).max(100).required().messages({
    'string.base': 'Title must be a string',
    'string.empty': 'Title is required',
    'string.min': 'Title should have a minimum length of {#limit}',
    'string.max': 'Title should have a maximum length of {#limit}',
  }),
  imageUrl: Joi.string().uri().required().messages({
    'string.uri': 'Image URL must be a valid URI',
    'string.empty': 'Image URL is required',
  }),
  tags: Joi.array().items(Joi.string()).required().messages({
    'array.base': 'Tags must be an array of strings',
    'any.required': 'Tags are required',
  }),
  nsfw: Joi.boolean().required().messages({
    'boolean.base': 'NSFW must be a boolean',
    'any.required': 'NSFW is required',
  }),
  isPrivate: Joi.boolean().required().messages({
    'boolean.base': 'isPrivate must be a boolean',
    'any.required': 'isPrivate is required',
  }),
  authorId: Joi.number().integer().required().messages({
    'number.base': 'Author ID must be a number',
    'any.required': 'Author ID is required',
  }),
});

/**
 * Create a new post.
 *
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @returns {Promise<void>} - Sends the created post as a JSON response.
 */
export const createPost = async (req: Request, res: Response): Promise<void> => {
  const { error } = postSchema.validate(req.body);
  if (error) {
    res.status(400).json({ error: error.details[0].message });
    return;
  }

  try {
    const { title, imageUrl, tags, nsfw, isPrivate, authorId } = req.body;

    const post = await prisma.post.create({
      data: {
        title,
        imageUrl,
        tags,
        nsfw,
        isPrivate,
        author: { connect: { id: authorId } },
      },
    });

    res.status(201).json(post);
  } catch (error) {
    res.status(500).json({ error: (error as any).message });
  }
};

/**
 * Get a single post by ID.
 *
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @returns {Promise<void>} - Sends the post data as a JSON response.
 */
export const getPost = async (req: Request, res: Response): Promise<void> => {
  const { id } = req.params;

  try {
    const post = await prisma.post.findUnique({
      where: { id: Number(id) },
      include: {
        author: true,
        comments: true, // Include comments
      },
    });

    if (!post) {
      res.status(404).json({ message: 'Post not found' });
      return;
    }

    res.status(200).json(post);
  } catch (error) {
    res.status(500).json({ error: (error as any).message });
  }
};

/**
 * Get all posts with optional filtering.
 *
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @returns {Promise<void>} - Sends the list of posts as a JSON response.
 */
export const getAllPosts = async (req: Request, res: Response): Promise<void> => {
  const { nsfw, isPrivate } = req.query;

  try {
    const posts = await prisma.post.findMany({
      where: {
        nsfw: nsfw === 'true' ? true : undefined, // Optional filtering based on NSFW
        isPrivate: isPrivate === 'true' ? true : undefined, // Optional filtering based on privacy
      },
      include: {
        author: true,
        comments: true,
      },
    });

    res.status(200).json(posts);
  } catch (error) {
    res.status(500).json({ error: (error as any).message });
  }
};

/**
 * Update an existing post.
 *
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @param {string} req.params.id - The ID of the post to update.
 * @returns {Promise<void>} - Sends the updated post as a JSON response.
 */
export const updatePost = async (req: Request, res: Response): Promise<void> => {
  const { error } = postSchema.validate(req.body);
  if (error) {
    res.status(400).json({ error: error.details[0].message });
    return;
  }

  const { id } = req.params;
  try {
    const post = await prisma.post.findUnique({
      where: { id: Number(id) },
    });

    if (!post) {
      res.status(404).json({ message: 'Post not found' });
      return;
    }

    const updatedPost = await prisma.post.update({
      where: { id: Number(id) },
      data: req.body,
    });

    res.status(200).json(updatedPost);
  } catch (error) {
    res.status(500).json({ error: (error as any).message });
  }
};

/**
 * Delete an existing post.
 *
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @param {string} req.params.id - The ID of the post to delete.
 * @returns {Promise<void>} - Sends a 204 status if the post is successfully deleted.
 */
export const deletePost = async (req: Request, res: Response): Promise<void> => {
  const { id } = req.params;
  try {
    const post = await prisma.post.findUnique({
      where: { id: Number(id) },
    });

    if (!post) {
      res.status(404).json({ message: 'Post not found' });
      return;
    }

    await prisma.post.delete({
      where: { id: Number(id) },
    });

    res.status(204).json();
  } catch (error) {
    res.status(500).json({ error: (error as any).message });
  }
};