diff --git a/apps/api/src/controllers/posts.ts b/apps/api/src/controllers/posts.ts new file mode 100644 index 00000000..0f913d0a --- /dev/null +++ b/apps/api/src/controllers/posts.ts @@ -0,0 +1,128 @@ +import Post from '../models/posts'; +import Comment from '../models/comments'; + +const getAllPosts = async ( req, res ) => { + try { + const posts = await Post.find().populate('category'); + res.status(200).json(posts); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } +} + +const getPostsByCategory = async (req, res) => { + const category = req.params.category; + try { + const post = await Post.find({category: category}).populate('category'); + if( !post ) { + return res.status(404).json({ message: 'Post by category not found' }); + } + + res.status(200).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } + +} + +const getPostsById = async (req, res) => { + const { id } = req.params; + + try { + const post = await Post.findById(id); + + if( !post ) { + return res.status(404).json({ message: 'Post by id not found' }); + } + + res.status(200).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } + +} + +const createPost = async (req, res) => { + try { + const post = await Post.create(req.body); + + res.status(201).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } +} + +const createComment = async (req, res) => { + const { id } = req.params; + + try { + const post = await Post.findById(id); + if ( !post ) { + return res.status(404).json({ message: 'Post not found' }); + } + + const comment = await Comment.create(req.body); + if ( !comment ) { + return res.status(400).json({ message: 'Comment not created' }); + } + post.comments.push(comment._id); + await post.save(); + + res.status(201).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } +} + +const updatePost = async (req, res) => { + const { title } = req.body; + const { id } = req.params; + + if (!title) { + return res.status(400).json({ message: 'Title is required' }); + } + + try { + const post = await Post.findByIdAndUpdate(id, { + title: req.body.title + }, + {new: true}); + + res.status(200).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } +} + +const deletePost = async (req, res) => { + const { id } = req.params; + + try { + const post = await Post.findById(id); + if (!post) { + return res.status(404).json({ message: 'Post not found' }); + } + await Comment.deleteMany({_id: {$in: post.comments}}); + const postDeleted = await Post.findByIdAndDelete(id); + res.status(204).json(postDeleted); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } +} + +export default { + getAllPosts, + getPostsByCategory, + getPostsById, + createPost, + createComment, + updatePost, + deletePost +} \ No newline at end of file diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index daf9dc2e..96888e1e 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -8,6 +8,7 @@ import { verifyToken } from './middleware/auth'; import { errorHandler } from './middleware/errorHandler'; import auth from './routes/auth'; import categories from './routes/categories'; +import posts from './routes/posts'; const host = process.env.HOST ?? 'localhost'; const port = process.env.PORT ? Number(process.env.PORT) : 3000; @@ -22,6 +23,7 @@ app.use('/api/auth', auth); app.use(verifyToken); app.use('/api/categories', categories); +app.use('/api/posts', posts); app.use(errorHandler); diff --git a/apps/api/src/models/comments.ts b/apps/api/src/models/comments.ts new file mode 100644 index 00000000..e275d3d7 --- /dev/null +++ b/apps/api/src/models/comments.ts @@ -0,0 +1,26 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +interface IComment extends Document { + author: string; + content: string; +} + +export const commentSchema = new Schema( + { + author: { + type: String, + required: [true, 'Author is required'] + }, + content: { + type: String, + required: [true, 'Content is required'] + } + }, + { + timestamps: true + } +); + +const Comment = mongoose.model('Comment', commentSchema); + +export default Comment; diff --git a/apps/api/src/models/posts.ts b/apps/api/src/models/posts.ts new file mode 100644 index 00000000..5deb5f27 --- /dev/null +++ b/apps/api/src/models/posts.ts @@ -0,0 +1,43 @@ +import mongoose, { Document, Schema, Types } from 'mongoose'; + +interface IPost extends Document { + title: string; + image: string; + description: string; + category: Types.ObjectId; + comments: [Types.ObjectId]; +} + +export const postSchema = new Schema( + { + title: { + type: String, + required: [true, 'Title is required'] + }, + image: { + type: String, + required: [true, 'Image is required'] + }, + description: { + type: String, + required: [true, 'Description is required'] + }, + category: { + type: Schema.Types.ObjectId, + ref: 'Category' + }, + comments: [ + { + type: Schema.Types.ObjectId, + ref: 'Comment' + } + ] + }, + { + timestamps: true + } +); + +const Post = mongoose.model('Post', postSchema); + +export default Post; diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts new file mode 100644 index 00000000..10d3870a --- /dev/null +++ b/apps/api/src/routes/posts.ts @@ -0,0 +1,20 @@ +import express from 'express'; +import postsController from '../controllers/posts'; + +const router = express.Router(); + +router.get('/', postsController.getAllPosts); + +router.get('/category/:category', postsController.getPostsByCategory); + +router.get('/:id', postsController.getPostsById); + +router.post('/', postsController.createPost); + +router.post('/:id/comments', postsController.createComment); + +router.patch('/:id', postsController.updatePost); + +router.delete('/:id', postsController.deletePost); + +export default router; \ No newline at end of file