From 57c21e66443fb6b5e964d07626550560ccfc7fdd Mon Sep 17 00:00:00 2001 From: AnaValdes29 Date: Mon, 23 Sep 2024 16:52:19 -0600 Subject: [PATCH 1/2] session 01 challenge --- apps/api/src/main.ts | 2 + apps/api/src/models/models.ts | 14 +++ apps/api/src/routes/posts.ts | 179 ++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 apps/api/src/models/models.ts 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/models/models.ts b/apps/api/src/models/models.ts new file mode 100644 index 00000000..2f8b969d --- /dev/null +++ b/apps/api/src/models/models.ts @@ -0,0 +1,14 @@ +export interface Post { + id: string; + title: string; + image: string; + description: string; + category: string; + comments: string[]; +} + +export interface Comment { + id: string; + author: string; + content: string; +} diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts new file mode 100644 index 00000000..a8ef5769 --- /dev/null +++ b/apps/api/src/routes/posts.ts @@ -0,0 +1,179 @@ +import express from 'express'; +import { Post, Comment } from '../models/models'; + +export const getPostsByCategory = (category: string) => { + return posts.find((p) => p.category === category); +}; + +export const getPostsById = (id: string) => { + return posts.find((p) => p.id === id); +}; + +const router = express.Router(); + +// Initialize categories array to save data in memory +const posts: Post[] = []; +const comments: Comment[] = []; + +// Get all posts +router.get('/', (req, res) => { + // Return all the categories with a 200 status code + res.status(200).json(posts); +}); + +router.get('/category/:category', (req, res) => { + // Retrieve the category from the route params + const { category } = req.params; + + if (!category) { + // If the user doesn't specify a category, return a 400 status code with a message + return res.status(400).json({ message: 'Category is required' }); + } + + const posts = getPostsByCategory(category); + + if (!posts) { + // If we don't find any posts, return a 404 status code with a message + return res.status(404).json({ message: 'No posts found' }); + } + + //Return an array of all the posts by category with status code 200 + res.status(200).json(posts); +}); + +router.get('/:id', (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + + if (!id) { + // If the user doesn't specify an ID, return a 400 status code with a message + return res.status(400).json({ message: 'ID is required' }); + } + + const posts = getPostsById(id); + + if (!posts) { + // If we don't find any posts, return a 404 status code with a message + return res.status(404).json({ message: 'No posts found' }); + } + + //Return an array of all the posts by category with status code 200 + res.status(200).json(posts); +}); + +router.post('/', (req, res) => { + // Retrieve the post information from the request body + const { title, image, description, category } = req.body; + + if (!title || !image || !description || !category) { + // If name is empty or undefined return a 400 status code with a message + return res.status(400).json({ message: 'Missing fields.' }); + } + + // Generate a new post + const newPost = { + id: Date.now().toString(), // Convert id to string to match the value in get by id endpoint + title: title, + image: image, + description: description, + category: category, + comments: [] + }; + // Add the new post to our array + posts.push(newPost); + + // Return the created post with a 201 status code + res.status(201).json(newPost); +}) + +router.post('/:id/comments', (req, res) => { + // Retrieve the name from the request body + const { id } = req.params; + const { author, content } = req.body; + + if (!author || !content) { + // If name is empty or undefined return a 400 status code with a message + return res.status(400).json({ message: 'Missing fields.' }); + } + + const post = getPostsById(id); + + if (!post) { + // If we don't find any posts, return a 404 status code with a message + return res.status(404).json({ message: 'No post found' }); + } + + // Generate a new post + const newComment = { + id: Date.now().toString(), // Convert id to string to match the value in get by id endpoint + author: author, + content: content + }; + + // Add the new post to our array + comments.push(newComment); + + post.comments.push(newComment.id) + + // Return the created post with a 201 status code + res.status(201).json(newComment); +}); + +router.patch('/:id', (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + // Retrieve the index of the post in the array + const postIndex = posts.findIndex((p) => p.id === id); + + // "findIndex" will return -1 if there is no match + if (postIndex === -1) { + // If we don't find the post return a 404 status code with a message + return res.status(404).json({ message: 'Post not found' }); + } + + // Generate a copy of our cateogory + const updatedPost = { ...posts[postIndex] }; + // Retrieve the name from the request body + const { title, image, description, category } = req.body; + + // Check if we have a name, if so update the property + if (title) { + updatedPost.title = title; + } + if (image) { + updatedPost.image = image; + } + if (description) { + updatedPost.description = description; + } + if (category) { + updatedPost.category = category; + } + + // Update the post in our array + posts[postIndex] = updatedPost; + + // Return the updated post with a 200 status code + res.status(200).json(updatedPost); +}); + +router.delete('/:id', (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + // Retrieve the index of the post in the array + const postIndex = posts.findIndex((p) => p.id === id); + + // "findIndex" will return -1 if there is no match + if (postIndex === -1) { + // If we don't find the post return a 404 status code with a message + return res.status(404).json({ message: 'Post not found' }); + } + + // Remove the post from the array + posts.splice(postIndex, 1); + + // Return a 204 status code + res.status(204).send(); +}); + +export default router; From b8fd81cafd594b7eed40ec56b8f881117f9d5a63 Mon Sep 17 00:00:00 2001 From: AnaValdes29 Date: Mon, 30 Sep 2024 18:07:40 -0600 Subject: [PATCH 2/2] challenge session 05 --- apps/api/.env | 2 +- apps/api/src/controllers/post.ts | 147 +++++++++++++++++ apps/api/src/models/comments.ts | 26 +++ apps/api/src/models/models.ts | 14 -- apps/api/src/models/post.ts | 43 +++++ apps/api/src/routes/posts.ts | 180 ++------------------ package-lock.json | 271 ++++++++++++++++++++++--------- package.json | 1 + 8 files changed, 429 insertions(+), 255 deletions(-) create mode 100644 apps/api/src/controllers/post.ts create mode 100644 apps/api/src/models/comments.ts delete mode 100644 apps/api/src/models/models.ts create mode 100644 apps/api/src/models/post.ts diff --git a/apps/api/.env b/apps/api/.env index ecaf5a7c..db13b1d3 100644 --- a/apps/api/.env +++ b/apps/api/.env @@ -1,3 +1,3 @@ ACCESS_TOKEN_SECRET=[YOUR_ACCESS_TOKEN_SECRET_HERE] REFRESH_TOKEN_SECRET=[YOUR_REFRESH_TOKEN_SECRET_HERE] -MONGO_URL=[YOUR_MONGO_CONNECTION_STRING_HERE] \ No newline at end of file +MONGO_URL=mongodb+srv://ana:gSW0Y2m7EuyYgaR7@cluster0.xnnqz.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0 diff --git a/apps/api/src/controllers/post.ts b/apps/api/src/controllers/post.ts new file mode 100644 index 00000000..11e3476d --- /dev/null +++ b/apps/api/src/controllers/post.ts @@ -0,0 +1,147 @@ +import Post from "../models/post"; +import Comment from "../models/comments"; + +//Get all posts +const getPosts = async (req, res) => { + try { + const posts = await Post.find().populate('category').populate('comments'); + + // Return all the posts with a 200 status code + res.status(200).json(posts); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +} + +//Get post by id +const getPostById = async (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + try { + const post = await Post.findById(id).populate('category').populate('comments'); + + if (!post) { + // If we don't find the category return a 404 status code with a message + return res.status(404).json({ message: 'Post not found' }); + } + + // Return the category with a 200 status code + res.status(200).json(post); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +} + +//Get post by category +const getPostsByCategory = async (req, res) => { + const category = req.params.category; + try { + const post = await Post.find({ category: category }).populate('category').populate('comments'); + 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 }); + } + +} + +//Create post +const createPost = async (req, res) => { + try { + const post = await Post.create(req.body); + + // Return the created post with a 201 status code + res.status(200).json(post); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +} + +//Create post comment +const createPostComment = async (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + try { + const post = await Post.findById(id); + + if (!post) { + // If we don't find the category return a 404 status code with a message + return res.status(404).json({ message: 'Post not found' }); + } + + const comment = await Comment.create(req.body); + post.comments.push(comment.id); + await post.save(); + + // Return the created post with a 201 status code + res.status(200).json(comment); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +} + +//Update post +const updatePost = async (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + try { + const post = await Post.findByIdAndUpdate(id, req.body, { new: true }); + + if (!post) { + // If we don't find the category return a 404 status code with a message + return res.status(404).json({ message: 'Post not found' }); + } + + // Return the category with a 200 status code + res.status(200).json(post); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +} + +//Delete post +const deletePost = async (req, res) => { + // Retrieve the id from the route params + const { id } = req.params; + + try { + // Check and delete if we have a post with that id + const post = await Post.findById(id); + + // If we don't find the post return a 404 status code with a message + if (!post) { + return res.status(404).json({ message: 'Post not found' }); + } + + await Comment.deleteMany({ + _id: { $in: post.comments }, + }); + + await post.deleteOne(); + + // Return a 200 status code + res.status(200).json(post); + } catch (error) { + const { message } = error; + res.status(500).json({ message }); + } +}; + +export default { + getPosts, + getPostById, + getPostsByCategory, + createPost, + createPostComment, + updatePost, + deletePost +}; diff --git a/apps/api/src/models/comments.ts b/apps/api/src/models/comments.ts new file mode 100644 index 00000000..d7f34939 --- /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, 'Property is required'] + }, + content: { + type: String, + required: [true, 'Property is required'] + } + }, + { + timestamps: true + } +); + +const Comment = mongoose.model('Comment', commentSchema); + +export default Comment; diff --git a/apps/api/src/models/models.ts b/apps/api/src/models/models.ts deleted file mode 100644 index 2f8b969d..00000000 --- a/apps/api/src/models/models.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface Post { - id: string; - title: string; - image: string; - description: string; - category: string; - comments: string[]; -} - -export interface Comment { - id: string; - author: string; - content: string; -} diff --git a/apps/api/src/models/post.ts b/apps/api/src/models/post.ts new file mode 100644 index 00000000..42c8db94 --- /dev/null +++ b/apps/api/src/models/post.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, 'Property is required'] + }, + image: { + type: String, + required: [true, 'Property is required'] + }, + description: { + type: String, + required: [true, 'Property is required'] + }, + category: { + type: Schema.Types.ObjectId, + required: [true, 'Property is required'], + ref: "Category" + }, + comments: { + type: [Schema.Types.ObjectId], + required: [true, 'Property is required'], + 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 index a8ef5769..b8abd5bc 100644 --- a/apps/api/src/routes/posts.ts +++ b/apps/api/src/routes/posts.ts @@ -1,179 +1,27 @@ import express from 'express'; -import { Post, Comment } from '../models/models'; - -export const getPostsByCategory = (category: string) => { - return posts.find((p) => p.category === category); -}; - -export const getPostsById = (id: string) => { - return posts.find((p) => p.id === id); -}; +import postController from '../controllers/post'; const router = express.Router(); -// Initialize categories array to save data in memory -const posts: Post[] = []; -const comments: Comment[] = []; - // Get all posts -router.get('/', (req, res) => { - // Return all the categories with a 200 status code - res.status(200).json(posts); -}); - -router.get('/category/:category', (req, res) => { - // Retrieve the category from the route params - const { category } = req.params; - - if (!category) { - // If the user doesn't specify a category, return a 400 status code with a message - return res.status(400).json({ message: 'Category is required' }); - } - - const posts = getPostsByCategory(category); - - if (!posts) { - // If we don't find any posts, return a 404 status code with a message - return res.status(404).json({ message: 'No posts found' }); - } - - //Return an array of all the posts by category with status code 200 - res.status(200).json(posts); -}); - -router.get('/:id', (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - - if (!id) { - // If the user doesn't specify an ID, return a 400 status code with a message - return res.status(400).json({ message: 'ID is required' }); - } - - const posts = getPostsById(id); - - if (!posts) { - // If we don't find any posts, return a 404 status code with a message - return res.status(404).json({ message: 'No posts found' }); - } - - //Return an array of all the posts by category with status code 200 - res.status(200).json(posts); -}); - -router.post('/', (req, res) => { - // Retrieve the post information from the request body - const { title, image, description, category } = req.body; - - if (!title || !image || !description || !category) { - // If name is empty or undefined return a 400 status code with a message - return res.status(400).json({ message: 'Missing fields.' }); - } - - // Generate a new post - const newPost = { - id: Date.now().toString(), // Convert id to string to match the value in get by id endpoint - title: title, - image: image, - description: description, - category: category, - comments: [] - }; - // Add the new post to our array - posts.push(newPost); - - // Return the created post with a 201 status code - res.status(201).json(newPost); -}) - -router.post('/:id/comments', (req, res) => { - // Retrieve the name from the request body - const { id } = req.params; - const { author, content } = req.body; - - if (!author || !content) { - // If name is empty or undefined return a 400 status code with a message - return res.status(400).json({ message: 'Missing fields.' }); - } - - const post = getPostsById(id); - - if (!post) { - // If we don't find any posts, return a 404 status code with a message - return res.status(404).json({ message: 'No post found' }); - } - - // Generate a new post - const newComment = { - id: Date.now().toString(), // Convert id to string to match the value in get by id endpoint - author: author, - content: content - }; - - // Add the new post to our array - comments.push(newComment); - - post.comments.push(newComment.id) - - // Return the created post with a 201 status code - res.status(201).json(newComment); -}); - -router.patch('/:id', (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - // Retrieve the index of the post in the array - const postIndex = posts.findIndex((p) => p.id === id); - - // "findIndex" will return -1 if there is no match - if (postIndex === -1) { - // If we don't find the post return a 404 status code with a message - return res.status(404).json({ message: 'Post not found' }); - } - - // Generate a copy of our cateogory - const updatedPost = { ...posts[postIndex] }; - // Retrieve the name from the request body - const { title, image, description, category } = req.body; - - // Check if we have a name, if so update the property - if (title) { - updatedPost.title = title; - } - if (image) { - updatedPost.image = image; - } - if (description) { - updatedPost.description = description; - } - if (category) { - updatedPost.category = category; - } +router.get('/', postController.getPosts); - // Update the post in our array - posts[postIndex] = updatedPost; +//Get post by id +router.get('/:id', postController.getPostById); - // Return the updated post with a 200 status code - res.status(200).json(updatedPost); -}); +//Get post by category +router.get('/category/:category', postController.getPostsByCategory); -router.delete('/:id', (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - // Retrieve the index of the post in the array - const postIndex = posts.findIndex((p) => p.id === id); +//Create post +router.post('/', postController.createPost); - // "findIndex" will return -1 if there is no match - if (postIndex === -1) { - // If we don't find the post return a 404 status code with a message - return res.status(404).json({ message: 'Post not found' }); - } +//Create comment +router.post('/:id/comments', postController.createPostComment); - // Remove the post from the array - posts.splice(postIndex, 1); +//Update post +router.patch('/:id', postController.updatePost); - // Return a 204 status code - res.status(204).send(); -}); +//Delete post +router.delete('/:id', postController.deletePost); export default router; diff --git a/package-lock.json b/package-lock.json index b27ba381..99e2b343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "express": "~4.18.1", "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", + "mongodb": "^6.9.0", "mongoose": "^8.0.3", "normalize.css": "^8.0.1", "react": "18.2.0", @@ -5608,9 +5609,10 @@ } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", - "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -8395,14 +8397,15 @@ "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { - "@types/node": "*", "@types/webidl-conversions": "*" } }, @@ -10675,9 +10678,10 @@ } }, "node_modules/bson": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", - "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "license": "Apache-2.0", "engines": { "node": ">=16.20.1" } @@ -17552,7 +17556,8 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -17904,13 +17909,14 @@ } }, "node_modules/mongodb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", - "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", + "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", + "license": "Apache-2.0", "dependencies": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^6.2.0", - "mongodb-connection-string-url": "^2.6.0" + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" }, "engines": { "node": ">=16.20.1" @@ -17949,35 +17955,26 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" } }, "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", "dependencies": { - "tr46": "^3.0.0", + "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=16" } }, "node_modules/mongoose": { @@ -18001,11 +17998,102 @@ "url": "https://opencollective.com/mongoose" } }, + "node_modules/mongoose/node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongoose/node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, "node_modules/mongoose/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/mongoose/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", @@ -21643,6 +21731,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } @@ -22597,7 +22686,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, "dependencies": { "punycode": "^2.3.0" }, @@ -27696,9 +27784,9 @@ } }, "@mongodb-js/saslprep": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", - "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", "requires": { "sparse-bitfield": "^3.0.3" } @@ -29703,11 +29791,10 @@ "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, "@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "requires": { - "@types/node": "*", "@types/webidl-conversions": "*" } }, @@ -31433,9 +31520,9 @@ } }, "bson": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", - "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==" + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==" }, "buffer": { "version": "5.7.1", @@ -36840,38 +36927,30 @@ } }, "mongodb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", - "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", + "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", "requires": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^6.2.0", - "mongodb-connection-string-url": "^2.6.0" + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" } }, "mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", "requires": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" }, "dependencies": { - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { - "punycode": "^2.1.1" - } - }, "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", "requires": { - "tr46": "^3.0.0", + "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" } } @@ -36891,10 +36970,55 @@ "sift": "16.0.1" }, "dependencies": { + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "mongodb": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "requires": { + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } } } }, @@ -40266,7 +40390,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, "requires": { "punycode": "^2.3.0" } diff --git a/package.json b/package.json index 221fc6d9..8096b9ba 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "express": "~4.18.1", "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", + "mongodb": "^6.9.0", "mongoose": "^8.0.3", "normalize.css": "^8.0.1", "react": "18.2.0",