Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend #15

Merged
merged 6 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/node_modules
node_modules

.env
/.env

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
Expand All @@ -20,4 +26,4 @@

npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn-error.log*
2 changes: 2 additions & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PORT=8000
SECRET_KEY={your-secret-key}
11 changes: 11 additions & 0 deletions server/config/jwt.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const jwt = require("jsonwebtoken");

module.exports.auth = (req, res, next) => {
jwt.verify(req.cookies.usertoken, process.env.SECRET_KEY, (err, payload) => {
if (err) {
res.status(401).json({ verified: false });
} else {
next();
}
});
};
12 changes: 12 additions & 0 deletions server/config/mongoose.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const mongoose = require("mongoose");
DATABASE = require("../server");

mongoose
.connect(`mongodb://127.0.0.1/${DATABASE}`, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("Established a connection to the database"))
.catch((err) =>
console.log("Something went wrong when connecting to the database ", err)
);
53 changes: 53 additions & 0 deletions server/controllers/applications.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const { ApplicationModel } = require("../models/applications.model");
const User = require("../models/user.model");

class ApplicationController {
// Create new Application
createApplication = async (req, res) => {
try {
const newApplication = new ApplicationModel(req.body);
await newApplication.save();
await User.findOneAndUpdate(
{ _id: newApplication.userId },
{ $push: { applications: newApplication } }
);
res.json(newApplication);
} catch (err) {
res.status(400).json(err);
}
};

// Read applications
getAllApplications = (req, res) => {
// sorts returned query in descending order
ApplicationModel.find({})
.sort({ createdAt: -1 })
.then((applications) => res.json(applications))
.catch((err) => res.status(400).json(err));
};

getOneApplication = (req, res) => {
ApplicationModel.findOne(req.params)
.then((application) => res.json(application))
.catch((err) => res.status(400).json(err));
};

// Update Applications
updateApplication = (req, res) => {
ApplicationModel.findOneAndUpdate(req.params, req.body, {
new: true,
runValidators: true,
})
.then((update) => res.json(update))
.catch((err) => res.status(400).json(err));
};

// Delete Applications
deleteApplication = (req, res) => {
ApplicationModel.deleteOne(req.params)
.then((deleteConfirm) => res.json(deleteConfirm))
.catch((err) => res.json(err));
};
}

module.exports = new ApplicationController();
125 changes: 125 additions & 0 deletions server/controllers/user.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
const User = require("../models/user.model");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");

class UserController {
// functions this class has available to use
// Create
register = (req, res) => {
User.find({ email: req.body.email })
.then((userEmail) => {
if (userEmail.length === 0) {
User.create(req.body)
.then((user) => {
const userToken = jwt.sign(
{ id: user._id },
process.env.SECRET_KEY
);
res
.cookie("usertoken", userToken, process.env.SECRET_KEY, {
httpOnly: true,
})
.json(user);
})
.catch((err) => res.status(400).json(err));
} else {
res.status(400).json({
errors: {
email: {
message: "Email is already taken, please provide another",
},
},
});
}
})
.catch((err) => res.status(400).json(err));
};

// READ
getAllUsers = (req, res) => {
User.find().populate('applications')
.then((allUsers) => res.json(allUsers))
.catch((err) => res.status(400).json(err));
};

getOneUser = (req, res) => {
User.findOne(req.params)
.then((user) => res.json(user))
.catch((err) => res.status(400).json(err));
};

// UPDATE
updateUser = (req, res) => {
User.findOneAndUpdate(req.params, req.body, {
new: true,
runValidators: true,
})
.then((update) => res.json(update))
.catch((err) => res.status(400).json(err));
};

// DELETE
deleteUser = (req, res) => {
User.deleteOne(req.params)
.then((deleteConfirm) => res.json(deleteConfirm))
.catch((err) => res.json(err));
};

// AUTH functions
// Login
login = async (req, res) => {
const user = await User.findOne({ email: req.body.email });

// if user is not found in database, return error status 400
if (user === null) {
return res.sendStatus(400);
}

// user exists in database, check submitted password is the same as password in database
const correctPassword = await bcrypt.compare(
req.body.password,
user.password
);

if (!correctPassword) {
// password does not match
return res.sendStatus(400);
}

// password is correct, create jwt token
const userToken = jwt.sign(
{
id: user._id,
},
process.env.SECRET_KEY
);

res
.cookie("usertoken", userToken, process.env.SECRET_KEY, {
httpOnly: true,
})
.json({ msg: "success!" });
};

logout = (req, res) => {
res.clearCookie("usertoken");
res.sendStatus(200);
};

/* use this method to retrieve logged in USER data from the backend via jwt cookies
example:
axios
.get(`http://localhost:8000/api/users/getloggedinuser`, {withCredentials: true})
.then(res => console.log(res.data[0]))
*/
getLoggedInUser = (req, res) => {
// use info stored in cookie to get id of logged in user and query db to find user with that id, return that users info
const decodedJwt = jwt.decode(req.cookies.usertoken, { complete: true });
User.find({ _id: decodedJwt.payload.id })
.then((foundUser) => res.json(foundUser))
.catch((err) => res.json(err));
};
}

// export a new instance of the UserController class
module.exports = new UserController();
24 changes: 24 additions & 0 deletions server/models/applications.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const mongoose = require("mongoose");

const ApplicationSchema = new mongoose.Schema(
{
userId: String,
title: {
type: String,
required: [true, "Title is required"],
minLength: [5, "Title must be at least 5 characters"],
},
company: {
type: String,
required: [true, "Company is required"],
minLength: [5, "Company must be at least 5 characters"],
},
status: String,
},
{ timestamps: true }
);

module.exports = {
ApplicationModel: mongoose.model("Application", ApplicationSchema),
ApplicationSchema,
};
58 changes: 58 additions & 0 deletions server/models/user.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const { ApplicationSchema } = require("./applications.model");

const UserSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: [true, "is required"],
},
lastName: {
type: String,
required: [true, "is required"],
},
email: {
type: String,
required: [true, "Email is required"],
validate: {
validator: (val) => /^([\w-\.]+@([\w-]+\.)+[\w-]+)?$/.test(val),
message: "Please enter a valid email",
},
},
password: {
type: String,
required: [true, "is required"],
},
applications: [ApplicationSchema],
},
// created at, updated at
{ timestamps: true }
);

// creates a virtual field used JUST for validations, this is not saved in the database ['confirmPassword'] needs to match field in postman/frontend form
UserSchema.virtual("confirmPassword")
.get(() => this._confirmPassword)
.set((value) => (this._confirmPassword = value));

// before(pre) running other model validations [required: true]
// validate if confirm password matches password
UserSchema.pre("validate", function (next) {
if (this.password !== this.get("confirmPassword")) {
// creates a validation error message (similar to above required: [true, "error message"])
this.invalidate("confirmPassword", "Passwords must match");
}
next();
});

// before(pre) saving to database, encrypt the users password
UserSchema.pre("save", function (next) {
bcrypt.hash(this.password, 10).then((hash) => {
this.password = hash;
next();
});
});



module.exports = mongoose.model("User", UserSchema);
Loading