From 6949b3c3b4e677c1ea12b6779489ff4265e67148 Mon Sep 17 00:00:00 2001 From: Karen Rodriguez Acosta Date: Wed, 18 Sep 2024 19:38:19 -0600 Subject: [PATCH 1/3] challenges session 1 --- apps/api/src/main.ts | 2 + apps/api/src/routes/posts.ts | 123 +++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 apps/api/src/routes/posts.ts diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 7f6b1e10..9862eaea 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -5,6 +5,7 @@ import helmet from 'helmet'; import { corsOptions } from './config/corsConfig'; 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; @@ -16,6 +17,7 @@ app.use(helmet()); app.use(cors(corsOptions)); app.use('/api/categories', categories); +app.use('/api/posts', posts); app.listen(port, host, () => { console.log(`[ ready ] http://${host}:${port}`); diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts new file mode 100644 index 00000000..27cfc3b6 --- /dev/null +++ b/apps/api/src/routes/posts.ts @@ -0,0 +1,123 @@ +import express from 'express'; + +export const getPostsById = (id: string) => { + return posts.find((p) => p.id === id); +}; + +export const getPostsByCategory = (category: string) => { + return posts.find((p) => p.category === category); +}; + +const router = express.Router(); + +const posts = []; + +router.get('/', (req, res) => { + res.status(200).json(posts); +}); + +router.get('/category/:category', (req, res) => { + const category = req.params.category; + + const post = getPostsByCategory(category); + if( !post ) { + return res.status(404).json({ message: 'Post by category not found' }); + } + + res.status(200).json(post); +}); + +router.get('/:id', (req, res) => { + const { id } = req.params; + const post = getPostsById(id); + + if( !post ) { + return res.status(404).json({ message: 'Post by id not found' }); + } + + res.status(200).json(post); +}); + +router.post('/', (req, res) => { + const title = req.body.title, + image = req.body.image, + description = req.body.description, + category = req.body.category; + + if( !title || !image || !description || !category ) { + return res.status(400).json({ message: 'title, image, description, category are required' }); + } + + const newPost = { + id: Date.now().toString(), + title, + image, + description, + category, + comments: [] + } + + posts.push(newPost); + + res.status(201).json(newPost); +}); + +router.post('/:id/comments', (req, res) => { + const { id } = req.params; + + const author = req.body.author, + content = req.body.content; + if( !author || !content ) { + return res.status(400).json({ message: 'author and contents params are required' }); + } + + const post = getPostsById(id); + if ( !post ) { + return res.status(404).json({ message: 'Post not found.' }); + } + + const newComment = { + id: `comment-${Date.now().toString()}`, + author, + content + } + + post.comments.push(newComment.id); + + res.status(201).json(newComment); +}); + + +router.patch('/:id', (req, res) => { + const { title } = req.body; + const { id } = req.params; + + if (!title) { + return res.status(400).json({ message: 'Title is required' }); + } + + const post = posts.find((p) => p.id === id); + if (!post) { + return res.status(404).json({ message: 'Post not found' }); + } + + post.title = title; + + return res.status(200).json({ post }); +}); + +router.delete('/:id', (req, res) => { + const { id } = req.params; + + const post = posts.findIndex((p) => p.id === id); + + if (post === -1) { + return res.status(404).json({ message: 'Post not found' }); + } + + posts.splice(post, 1); + + res.status(204).send(); +}); + +export default router; \ No newline at end of file From 96d3eab83520b67b7bf9cd3785c2b14021309c49 Mon Sep 17 00:00:00 2001 From: Karen Rodriguez Acosta Date: Wed, 18 Sep 2024 20:15:44 -0600 Subject: [PATCH 2/3] challenge session 2 --- apps/api/src/controllers/posts.ts | 126 ++++++++++++++++++++++++++++++ apps/api/src/routes/posts.ts | 121 +++------------------------- 2 files changed, 135 insertions(+), 112 deletions(-) create mode 100644 apps/api/src/controllers/posts.ts diff --git a/apps/api/src/controllers/posts.ts b/apps/api/src/controllers/posts.ts new file mode 100644 index 00000000..7eab0b0d --- /dev/null +++ b/apps/api/src/controllers/posts.ts @@ -0,0 +1,126 @@ +const posts = []; + +export const getPostById = (id: string) => { + return posts.find((p) => p.id === id); +}; + +export const getPostByCategory = (category: string) => { + return posts.find((p) => p.category === category); +}; + +const getAllPosts = ( req, res ) => { + res.status(200).json(posts); +} + +const getPostsByCategory = (req, res) => { + const category = req.params.category; + + const post = getPostByCategory(category); + if( !post ) { + return res.status(404).json({ message: 'Post by category not found' }); + } + + res.status(200).json(post); +} + +const getPostsById = (req, res) => { + const { id } = req.params; + const post = getPostById(id); + + if( !post ) { + return res.status(404).json({ message: 'Post by id not found' }); + } + + res.status(200).json(post); +} + +const createPost = (req, res) => { + const title = req.body.title, + image = req.body.image, + description = req.body.description, + category = req.body.category; + + if( !title || !image || !description || !category ) { + return res.status(400).json({ message: 'title, image, description, category are required' }); + } + + const newPost = { + id: Date.now().toString(), + title, + image, + description, + category, + comments: [] + } + + posts.push(newPost); + + res.status(201).json(newPost); +} + +const createComment = (req, res) => { + const { id } = req.params; + + const author = req.body.author, + content = req.body.content; + if( !author || !content ) { + return res.status(400).json({ message: 'author and contents params are required' }); + } + + const post = getPostById(id); + if ( !post ) { + return res.status(404).json({ message: 'Post not found.' }); + } + + const newComment = { + id: `comment-${Date.now().toString()}`, + author, + content + } + + post.comments.push(newComment.id); + + res.status(201).json(newComment); +} + +const updatePost = (req, res) => { + const { title } = req.body; + const { id } = req.params; + + if (!title) { + return res.status(400).json({ message: 'Title is required' }); + } + + const post = posts.find((p) => p.id === id); + if (!post) { + return res.status(404).json({ message: 'Post not found' }); + } + + post.title = title; + + return res.status(200).json({ post }); +} + +const deletePost = (req, res) => { + const { id } = req.params; + + const post = posts.findIndex((p) => p.id === id); + + if (post === -1) { + return res.status(404).json({ message: 'Post not found' }); + } + + posts.splice(post, 1); + + res.status(204).send(); +} + +export default { + getAllPosts, + getPostsByCategory, + getPostsById, + createPost, + createComment, + updatePost, + deletePost +} \ No newline at end of file diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts index 27cfc3b6..10d3870a 100644 --- a/apps/api/src/routes/posts.ts +++ b/apps/api/src/routes/posts.ts @@ -1,123 +1,20 @@ import express from 'express'; - -export const getPostsById = (id: string) => { - return posts.find((p) => p.id === id); -}; - -export const getPostsByCategory = (category: string) => { - return posts.find((p) => p.category === category); -}; - -const router = express.Router(); - -const posts = []; - -router.get('/', (req, res) => { - res.status(200).json(posts); -}); - -router.get('/category/:category', (req, res) => { - const category = req.params.category; - - const post = getPostsByCategory(category); - if( !post ) { - return res.status(404).json({ message: 'Post by category not found' }); - } - - res.status(200).json(post); -}); - -router.get('/:id', (req, res) => { - const { id } = req.params; - const post = getPostsById(id); +import postsController from '../controllers/posts'; - if( !post ) { - return res.status(404).json({ message: 'Post by id not found' }); - } - - res.status(200).json(post); -}); - -router.post('/', (req, res) => { - const title = req.body.title, - image = req.body.image, - description = req.body.description, - category = req.body.category; - - if( !title || !image || !description || !category ) { - return res.status(400).json({ message: 'title, image, description, category are required' }); - } - - const newPost = { - id: Date.now().toString(), - title, - image, - description, - category, - comments: [] - } - - posts.push(newPost); - - res.status(201).json(newPost); -}); - -router.post('/:id/comments', (req, res) => { - const { id } = req.params; - - const author = req.body.author, - content = req.body.content; - if( !author || !content ) { - return res.status(400).json({ message: 'author and contents params are required' }); - } - - const post = getPostsById(id); - if ( !post ) { - return res.status(404).json({ message: 'Post not found.' }); - } +const router = express.Router(); - const newComment = { - id: `comment-${Date.now().toString()}`, - author, - content - } +router.get('/', postsController.getAllPosts); - post.comments.push(newComment.id); - - res.status(201).json(newComment); -}); +router.get('/category/:category', postsController.getPostsByCategory); +router.get('/:id', postsController.getPostsById); -router.patch('/:id', (req, res) => { - const { title } = req.body; - const { id } = req.params; - - if (!title) { - return res.status(400).json({ message: 'Title is required' }); - } - - const post = posts.find((p) => p.id === id); - if (!post) { - return res.status(404).json({ message: 'Post not found' }); - } - - post.title = title; - - return res.status(200).json({ post }); -}); +router.post('/', postsController.createPost); -router.delete('/:id', (req, res) => { - const { id } = req.params; +router.post('/:id/comments', postsController.createComment); - const post = posts.findIndex((p) => p.id === id); - - if (post === -1) { - return res.status(404).json({ message: 'Post not found' }); - } +router.patch('/:id', postsController.updatePost); - posts.splice(post, 1); - - res.status(204).send(); -}); +router.delete('/:id', postsController.deletePost); export default router; \ No newline at end of file From 20045b68904d7e891a42637ff87c853972697696 Mon Sep 17 00:00:00 2001 From: Karen Rodriguez Acosta Date: Thu, 19 Sep 2024 00:02:00 -0600 Subject: [PATCH 3/3] challenge session 5 --- apps/api/src/controllers/posts.ts | 170 +++++++++++++++--------------- apps/api/src/models/comments.ts | 26 +++++ apps/api/src/models/posts.ts | 43 ++++++++ 3 files changed, 155 insertions(+), 84 deletions(-) create mode 100644 apps/api/src/models/comments.ts create mode 100644 apps/api/src/models/posts.ts diff --git a/apps/api/src/controllers/posts.ts b/apps/api/src/controllers/posts.ts index 7eab0b0d..0f913d0a 100644 --- a/apps/api/src/controllers/posts.ts +++ b/apps/api/src/controllers/posts.ts @@ -1,118 +1,120 @@ -const posts = []; +import Post from '../models/posts'; +import Comment from '../models/comments'; -export const getPostById = (id: string) => { - return posts.find((p) => p.id === id); -}; - -export const getPostByCategory = (category: string) => { - return posts.find((p) => p.category === category); -}; - -const getAllPosts = ( req, res ) => { - res.status(200).json(posts); +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 = (req, res) => { +const getPostsByCategory = async (req, res) => { const category = req.params.category; - - const post = getPostByCategory(category); - if( !post ) { - return res.status(404).json({ message: 'Post by category not found' }); + 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}); } - - res.status(200).json(post); + } -const getPostsById = (req, res) => { +const getPostsById = async (req, res) => { const { id } = req.params; - const post = getPostById(id); - if( !post ) { - return res.status(404).json({ message: 'Post by id not found' }); + 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}); } - - res.status(200).json(post); + } -const createPost = (req, res) => { - const title = req.body.title, - image = req.body.image, - description = req.body.description, - category = req.body.category; - - if( !title || !image || !description || !category ) { - return res.status(400).json({ message: 'title, image, description, category are required' }); - } - - const newPost = { - id: Date.now().toString(), - title, - image, - description, - category, - comments: [] - } - - posts.push(newPost); +const createPost = async (req, res) => { + try { + const post = await Post.create(req.body); - res.status(201).json(newPost); + res.status(201).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } } -const createComment = (req, res) => { +const createComment = async (req, res) => { const { id } = req.params; - const author = req.body.author, - content = req.body.content; - if( !author || !content ) { - return res.status(400).json({ message: 'author and contents params are required' }); - } - - const post = getPostById(id); - if ( !post ) { - return res.status(404).json({ message: 'Post not found.' }); - } - - const newComment = { - id: `comment-${Date.now().toString()}`, - author, - content - } - - post.comments.push(newComment.id); + 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(newComment); + res.status(201).json(post); + } catch (error) { + const {message} = error; + res.status(500).json({message}); + } } -const updatePost = (req, res) => { +const updatePost = async (req, res) => { const { title } = req.body; const { id } = req.params; if (!title) { return res.status(400).json({ message: 'Title is required' }); } - - const post = posts.find((p) => p.id === id); - if (!post) { - return res.status(404).json({ message: 'Post not found' }); + + 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}); } - - post.title = title; - - return res.status(200).json({ post }); } -const deletePost = (req, res) => { +const deletePost = async (req, res) => { const { id } = req.params; - - const post = posts.findIndex((p) => p.id === id); - - if (post === -1) { - return res.status(404).json({ message: 'Post not found' }); + + 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}); } - - posts.splice(post, 1); - - res.status(204).send(); } export default { 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;