Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bc32ffd
add express-list-endpoints to dependencies
jszor May 29, 2025
6fa29ff
add dotenv to dependencies
jszor May 29, 2025
9f7f23f
define endpoints and modify json file to use property id instead of _id
jszor May 29, 2025
2cefed7
add filtering with query parameters on posts endpoint
jszor May 29, 2025
90156f1
delete repeated post in data json file
jszor May 29, 2025
31f71d6
add listEndpoints to document API
jszor May 29, 2025
41b1ffc
add mongoose to dependencies and mongoose boilerplate to serverjs
jszor May 31, 2025
e596d9d
define post schema and function to seed database
jszor Jun 10, 2025
72ebcef
add endpoint for getting all posts
jszor Jun 10, 2025
62b520a
create endpoint for posting new post
jszor Jun 10, 2025
6d430ba
finish creating endpoint for posting new post
jszor Jun 10, 2025
1ad0b7d
correct schema format
jszor Jun 11, 2025
01288d4
correct schema model
jszor Jun 11, 2025
398e89c
correct seed db
jszor Jun 11, 2025
3f28eab
update nomenclature posts to thoughts throughout the code
jszor Jun 11, 2025
b7ca611
created models folder with thought and user schemas
jszor Jun 11, 2025
9fffc98
deleted thought schema from server js
jszor Jun 11, 2025
fbd47b5
modify thought schema
jszor Jun 11, 2025
9ed516d
added user schema to models
jszor Jun 11, 2025
b3dc9c5
update thought schema to include userid
jszor Jun 13, 2025
a6adfd2
finish creating endpoints, separate out controller functions, create …
jszor Jun 15, 2025
0586350
update postUser controller to issue jwt access token
jszor Jun 15, 2025
928cd3a
test minor bug fix in patchThought controller
jszor Jun 15, 2025
ee9d4d5
correct const userId in patchThoughtLikes controller code
jszor Jun 15, 2025
d257122
fix minor bug in patchThoughtLikes controller
jszor Jun 15, 2025
5505e97
fix minor bug in deleteThought controller code
jszor Jun 15, 2025
8c87c24
delete data.json and function for seeding database
jszor Jun 16, 2025
629480e
separate runtime dependencies from dev dependencies in package json
jszor Jun 25, 2025
519ba16
remove unused crypto import in user js
jszor Jun 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ node_modules
.env.development.local
.env.test.local
.env.production.local
package-lock.json
package-lock.json
todo.md
44 changes: 44 additions & 0 deletions controllers/deleteThought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Thought } from "../models/thought.js"

export const deleteThought = async (req, res) => {
const { id } = req.params
const userId = req.user._id

try {

const thought = await Thought.findById(id)

if (!thought) {
return res.status(404).json({
success: false,
response: [],
message: "Failed to delete thought: no thought found for the given id."
})
}

if (thought.userId.toString() !== userId.toString()) {
return res.status(403).json({
success: false,
response: [],
message: "Failed to delete thought: you are not authorized to delete this thought."
})
}

await Thought.findByIdAndDelete(id)

res.status(200).json({
success: true,
response: [],
message: "Thought deleted successfully."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to delete thought. Please try again later."
})

}
}
31 changes: 31 additions & 0 deletions controllers/getThought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Thought } from "../models/thought.js"

export const getThought = async (req, res) => {
const { id } = req.params

try {
const thought = await Thought.findById(id)

if (!thought) {
return res.status(404).json({
success: false,
response: [],
message: "No thought found for the given id. Please try again with a different id."
})
}

res.status(200).json({
success: true,
response: thought,
message: "Success."
})
}

catch (error) {
res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to fetch thought. Please try again later."
})
}
}
34 changes: 34 additions & 0 deletions controllers/getThoughts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Thought } from "../models/thought.js"

export const getThoughts = async (req, res) => {
const { hearts } = req.query;
const query = {}

if (hearts) {
query.hearts = hearts
}

try {
const filteredThoughts = await Thought.find(query)

if (filteredThoughts.length === 0) {
return res.status(404).json({
success: false,
response: [],
message: "No thoughts found for given query. Please try again with a different query"
})
}
res.status(200).json({
success: true,
response: filteredThoughts,
message: "Success"
})

} catch (error) {
res.status(500).json({
success: false,
response: error,
message: "Failed to fetch thoughts"
})
}
}
31 changes: 31 additions & 0 deletions controllers/getUserData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { User } from "../models/user.js"

export const getUserData = async (req, res) => {
try {

const user = req.user

if (!user) {
return res.status(404).json({
success: false,
response: [],
message: "Failed to get user data: no user found for the given id."
})
}

res.status(200).json({
success: true,
response: { name: user.name },
message: "Success"
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to get user data. Please try again later."
})

}
}
44 changes: 44 additions & 0 deletions controllers/loginUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import bcrypt from "bcrypt"
import jwt from "jsonwebtoken"
import { User } from "../models/user.js"

export const loginUser = async (req, res) => {
const { email, password } = req.body

try {
const user = await User.findOne({ email })

if (!user || !bcrypt.compareSync(password, user.password)) {
return res.status(401).json({
success: false,
response: [],
message: "Failed to log in: invalid email or password."
})
}

const accessToken = jwt.sign(
{ userId: user._id },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN}
)

res.status(200).json({
success: true,
response: {
accessToken,
name: user.name,
userId: user._id
},
message: "Log in successful."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to log in. Please try again later."
})

}
}
45 changes: 45 additions & 0 deletions controllers/patchThought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Thought } from "../models/thought.js"

export const patchThought = async (req, res) => {
const { id } = req.params
const { updatedMessage } = req.body
const userId = req.user._id

try {
const thought = await Thought.findById(id)

if (!thought) {
return res.status(404).json({
success: false,
response: [],
message: "Failed to update thought: no thought found for given id."
})
}

if (thought.userId.toString() !== userId.toString()) {
return res.status(403).json({
success: false,
response: [],
message: "Failed to update thought: you are not authorized to update this thought."
})
}

thought.message = updatedMessage
await thought.save()

res.status(200).json({
success: true,
response: thought,
message: "Thought updated successfully."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to update thought. Please try again later."
})

}
}
46 changes: 46 additions & 0 deletions controllers/patchThoughtLikes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Thought } from "../models/thought.js"

export const patchThoughtLikes = async (req, res) => {
const { id } = req.params
const userId = req.user._id

try {

const thought = await Thought.findById(id)

if (!thought) {
return res.status(404).json({
success: false,
response: [],
message: "No thought found for the given id. Please try again with a different id."
})
}

const hasLiked = thought.likes.includes(userId)

if (hasLiked) {
// remove like
thought.likes = thought.likes.filter(like => like.toString() !== userId.toString())
} else {
// add like
thought.likes.push(userId)
}

await thought.save()

res.status(200).json({
success: true,
response: thought,
message: "Likes updated successfully."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to update likes. Please try again later."
})

}
}
33 changes: 33 additions & 0 deletions controllers/postThought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Thought } from "../models/thought.js"

export const postThought = async (req, res) => {
const { message } = req.body
const user = req.user

try {
const newThought = await new Thought({ message, userId: user._id }).save()

if (!newThought) {
return res.status(400).json({
success: false,
response: [],
message: "Failed to post thought."
})
}

res.status(201).json({
success: true,
response: newThought,
message: "Thought posted successfully."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to post thought. Please try again later."
})

}
}
40 changes: 40 additions & 0 deletions controllers/postUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import bcrypt from "bcrypt"
import jwt from "jsonwebtoken"
import { User } from "../models/user.js"

export const postUser = async (req, res) => {
try {

const { name, email, password } = req.body

const salt = bcrypt.genSaltSync()
const hashedPassword = bcrypt.hashSync(password, salt)

const newUser = await new User({ name, email, password: hashedPassword }).save()

const accessToken = jwt.sign(
{ userId: newUser._id },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN }
)

res.status(201).json({
success: true,
response: {
userId: newUser._id,
name: newUser.name,
accessToken
},
message: "User registered successfully."
})

} catch (error) {

res.status(500).json({
success: false,
response: error,
message: "Internal server error: failed to register user. Please try again later."
})

}
}
Loading