Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4ffef48
Initial commit
HIPPIEKICK May 22, 2025
878b1a8
Change name on project
May 22, 2025
6f36df9
Create dataset
May 22, 2025
c219fef
initial com, adding all dependencies
Bianka2112 May 29, 2025
4cbcffb
code endpoints for collection of thoughts and single thought return
Bianka2112 May 29, 2025
db2663f
add list endpoints, api doc
Bianka2112 Jun 2, 2025
220fe2e
mongodb, mongoose methods added for database seed
Bianka2112 Jun 4, 2025
ef7a9f5
mongoose method to fetch all thoughts
Bianka2112 Jun 4, 2025
83d0416
edit to make frontend fetch work successfully
Bianka2112 Jun 4, 2025
39e775d
success add mongoose method by id
Bianka2112 Jun 4, 2025
e9ec654
can see successful post path in postman
Bianka2112 Jun 4, 2025
4707209
success delete method by id
Bianka2112 Jun 4, 2025
dd28ad0
success patch method
Bianka2112 Jun 4, 2025
95075fd
udpate dotenv to link properly, update post a like fx
Bianka2112 Jun 10, 2025
caeb78f
fix _id path for post a like
Bianka2112 Jun 10, 2025
fcf4ff3
update await fx inside of try block
Bianka2112 Jun 10, 2025
ff9bd4e
update id path again, for real?
Bianka2112 Jun 10, 2025
841e7e3
create user, login user paths work, codecleanup
Bianka2112 Jun 16, 2025
c476392
add authRouter for user and login
Bianka2112 Jun 16, 2025
78e1229
new routes, trying to fix .env, add render link
Bianka2112 Jun 17, 2025
97a6ed8
Remove .env* from version control
Bianka2112 Jun 17, 2025
dc500ed
fix double routes folder?
Bianka2112 Jun 17, 2025
e76e511
update error handling for authentication
Bianka2112 Jun 17, 2025
3207134
create users, auth, thoughts routes
Bianka2112 Jun 17, 2025
a7d145e
path fix for thoughts, users path test works
Bianka2112 Jun 17, 2025
a0b97df
update err handling in register
Bianka2112 Jun 17, 2025
502c2d9
err handling for thoughts path
Bianka2112 Jun 17, 2025
58780b6
added back get single thought path
Bianka2112 Jun 17, 2025
b55db29
Merge branch 'master' into technigo-base
Bianka2112 Jun 17, 2025
5629d8b
show thoughts by most recent top
Bianka2112 Jun 18, 2025
2c907f2
fix userid naming error
Bianka2112 Jun 18, 2025
7977400
usage for endpoints
Bianka2112 Jun 18, 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
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
node_modules
.DS_Store
.env
.env*
.env.dev
.env.prod
.env.local
.env.development.local
.env.test.local
.env.production.local
package-lock.json
package-lock.json
todo.md
114 changes: 114 additions & 0 deletions data/thoughtsList.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
[

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the db is seeded you dont really need to keep this json. It's okay if you want to keep it but not really necessary

{
"_id": "682bab8c12155b00101732ce",
"message": "Berlin baby",
"hearts": 37,
"createdAt": "2025-05-19T22:07:08.999Z",
"__v": 0
},
{
"_id": "682e53cc4fddf50010bbe739",
"message": "My family!",
"hearts": 0,
"createdAt": "2025-05-22T22:29:32.232Z",
"__v": 0
},
{
"_id": "682e4f844fddf50010bbe738",
"message": "The smell of coffee in the morning....",
"hearts": 23,
"createdAt": "2025-05-22T22:11:16.075Z",
"__v": 0
},
{
"_id": "682e48bf4fddf50010bbe737",
"message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED 🤞🏼\n",
"hearts": 6,
"createdAt": "2025-05-21T21:42:23.862Z",
"__v": 0
},
{
"_id": "682e45804fddf50010bbe736",
"message": "I am happy that I feel healthy and have energy again",
"hearts": 13,
"createdAt": "2025-05-21T21:28:32.196Z",
"__v": 0
},
{
"_id": "682e23fecf615800105107aa",
"message": "cold beer",
"hearts": 2,
"createdAt": "2025-05-21T19:05:34.113Z",
"__v": 0
},
{
"_id": "682e22aecf615800105107a9",
"message": "My friend is visiting this weekend! <3",
"hearts": 6,
"createdAt": "2025-05-21T18:59:58.121Z",
"__v": 0
},
{
"_id": "682cec1b17487d0010a298b6",
"message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!",
"hearts": 12,
"createdAt": "2025-05-20T20:54:51.082Z",
"__v": 0
},
{
"_id": "682cebbe17487d0010a298b5",
"message": "Tacos and tequila🌮🍹",
"hearts": 2,
"createdAt": "2025-05-19T20:53:18.899Z",
"__v": 0
},
{
"_id": "682ceb5617487d0010a298b4",
"message": "Netflix and late night ice-cream🍦",
"hearts": 1,
"createdAt": "2025-05-18T20:51:34.494Z",
"__v": 0
},
{
"_id": "682c99ba3bff2d0010f5d44e",
"message": "Summer is coming...",
"hearts": 2,
"createdAt": "2025-05-20T15:03:22.379Z",
"__v": 0
},
{
"_id": "682c706c951f7a0017130024",
"message": "Exercise? I thought you said extra fries! 🍟😂",
"hearts": 14,
"createdAt": "2025-05-20T12:07:08.185Z",
"__v": 0
},
{
"_id": "682c6fe1951f7a0017130023",
"message": "I’m on a seafood diet. I see food, and I eat it.",
"hearts": 4,
"createdAt": "2025-05-20T12:04:49.978Z",
"__v": 0
},
{
"_id": "682c6f0e951f7a0017130022",
"message": "Cute monkeys🐒",
"hearts": 2,
"createdAt": "2025-05-20T12:01:18.308Z",
"__v": 0
},
{
"_id": "682c6e65951f7a0017130021",
"message": "The weather is nice!",
"hearts": 0,
"createdAt": "2025-05-20T11:58:29.662Z",
"__v": 0
},
{
"_id": "682bfdb4270ca300105af221",
"message": "good vibes and good things",
"hearts": 3,
"createdAt": "2025-05-20T03:57:40.322Z",
"__v": 0
}
]
23 changes: 23 additions & 0 deletions models/Thought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import mongoose from "mongoose";

const thoughtSchema = new mongoose.Schema({
message: {
required: true,
type: String,
minlength: 5,
maxlength: 140},
hearts: {
type: Number,
default: 0},
createdAt: {
type: Date,
default: Date.now
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
default: null,
}
})

export const Thought = mongoose.model("Thought", thoughtSchema)
36 changes: 36 additions & 0 deletions models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import crypto from "crypto"
import mongoose from "mongoose"

const userSchema = new mongoose.Schema({
username: {
type: String,
unique: true,
required: true,
minlength: 2,
trim: true,
},
email: {
type: String,
unique: true,
sparse: true,
lowercase: true,
trim: true,
validate: {
validator: (email) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
},
Comment on lines +18 to +21

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message: props => `${props.value} is not a valid email address!`
}
Comment on lines +12 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of a custom message and validator for the email field!
I'm curious about your use of sparse — did you include it intentionally? If so, that’s a clever way to allow the email to be unique without making it required. I like how you're thinking about flexibility in your data model!

},
password: {
type: String,
required: true,
minlength: 4,
},
accessToken: {
type: String,
default: () => crypto.randomBytes(128).toString("hex"),
}
})

export const User = mongoose.model("User", userSchema)
16 changes: 11 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.17.9",
"@babel/node": "^7.16.8",
"@babel/preset-env": "^7.16.11",
"@babel/core": "^7.27.3",
"@babel/node": "^7.27.1",
"@babel/preset-env": "^7.27.2",
"bcrypt-nodejs": "^0.0.3",
"bcryptjs": "^3.0.2",
Comment on lines +15 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you're only using bcryptjs — maybe remove bcrypt-nodejs to keep things clean?

"cors": "^2.8.5",
"express": "^4.17.3",
"nodemon": "^3.0.1"
"dotenv": "^16.5.0",
"express": "^4.21.2",
"express-list-endpoints": "^7.1.1",
"mongodb": "^6.17.0",
"mongoose": "^8.15.1",
"nodemon": "^3.1.10"
}
}
4 changes: 3 additions & 1 deletion pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Please include your Render link here.
Please include your Render link here:

https://js-project-api-b8sd.onrender.com
119 changes: 119 additions & 0 deletions routes/authRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import bcrypt from "bcryptjs"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great structure and very clear authentication!

import { Router } from "express"

import { User } from "../models/User"

const authRouter = Router()

// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE)
authRouter.post("/register", async (req, res) => {
try {
const { username, email, password } = req.body
if (!username || !password) {
return res.status(400).json({ error: "username and password are required"})
}

const salt = bcrypt.genSaltSync()
const user = new User({
username,
email: email || null ,
password: bcrypt.hashSync(password, salt) })

await user.save()

res.status(200).json({
message: "Signup success",
success: true,
userid: user._id,
username: user.username,
accessToken: user.accessToken})

} catch(err) {
if (err.code === 11000) {
const field = Object.keys(err.keyPattern)[0]
return res.status(409).json({
success: false,
message: `A user with that ${field} already exists.`,
})
}
if (err.errors) {
const validationErrors = Object.values(err.errors).map(e => e.message)
return res.status(400).json({
success: false,
message: "Invalid input",
errors: validationErrors
})
}
console.error(err)
res.status(500).json({
success: false,
message: "Unexpected server error."
})
}
})

// LOGIN ENDPOINT (FINDS USER)
authRouter.post("/login", async (req, res) => {
try {
const { username, password } = req.body

const user = await User.findOne({ username: req.body.username })
if (!user) {
return res.status(404).json({
success: false,
message: "User does not exist"})
}

if (user && bcrypt.compareSync(req.body.password, user.password)) {
res.status(201).json({
success: true,
message: "User successfully logged in",
userId: user._id,
username: user.username,
accessToken: user.accessToken
})
} else {
res.status(401).json({
success: false,
message: "Invalid password"
})

}} catch(err) {
res.status(400).json({
success: false,
notFound: true})
}
})

// MIDDLEWARE TO AUTH
export const authenticateUser = async (req, res, next) => {
try {

const token = req.header("Authorization")
if (!token) {
return res.status(401).json({
success: false,
message: "Access token missing. Please login to continue."
})
}

const user = await User.findOne({ accessToken: token })
if(!user) {
return res.status(401).json({
success: false,
message: "Invalid token. Please login in again.",
loggedOut: true
})
}
req.user = user
next()
} catch (err) {
console.error("Authentication error", err)
res.status(500).json({
success: false,
message: "Server error during authentication."
})
}
}

export default authRouter
Loading