-
Notifications
You must be signed in to change notification settings - Fork 0
Ht 6 create endpoints for login and register #2
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
Merged
JakeMinor
merged 7 commits into
develop
from
HT-6-create-endpoints-for-login-and-register
Feb 1, 2022
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9b2e713
HT-6 Create auth route
jarrodback 1ac1997
HT-6 Add auth endpoints and data layer
jarrodback 06bdc67
HT-6 Add integration tests for login and register
jarrodback 09e9d56
HT-6 Pull in develop
jarrodback cf688f1
HT-6 Review comments
jarrodback 55ea031
HT-6 Change 200 to 201 for request response
jarrodback 8f50d4d
HT-6 Fix test failing
jarrodback File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"processes":{"ecd4285b-d9dc-4104-b850-fcf81a763c89":{"parent":null,"children":[]}},"files":{"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\app.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\database\\index.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\config\\db.config.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\models\\user.model.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\routes\\auth.routes.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\controllers\\auth.controller.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\business\\user.business.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"],"C:\\Users\\Jarrod\\Documents\\AAF\\CSSD\\server\\datalayer\\mongo.js":["ecd4285b-d9dc-4104-b850-fcf81a763c89"]},"externalIds":{}} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| const DataLayer = require("../datalayer/mongo"); | ||
| const model = require("../database").getModel("user"); | ||
| const httpError = require("http-errors"); | ||
| const jwt = require("jsonwebtoken"); | ||
| const bcrypt = require("bcryptjs"); | ||
|
|
||
| class UserBusiness { | ||
| constructor() { | ||
| // Create an instance of the data layer. | ||
| this.dataLayer = new DataLayer(model); | ||
| } | ||
|
|
||
| /** | ||
| * Login a user. | ||
| */ | ||
| async login(email, password) { | ||
| return this.findUserByEmail(email) | ||
| .then((user) => { | ||
| const passwordIsValid = bcrypt.compareSync( | ||
| password, | ||
| user.password | ||
| ); | ||
| // Invalid password, return 401 | ||
| if (!passwordIsValid) { | ||
| throw httpError( | ||
| 401, | ||
| "Your email or password is incorrect." | ||
| ); | ||
| } | ||
| // Create token and store in the session cookie | ||
| const token = jwt.sign( | ||
| { | ||
| id: user._id, | ||
| type: user.type, | ||
| email: user.email, | ||
| username: user.username, | ||
| }, | ||
| process.env.TOKEN_SECRET, | ||
| { | ||
| expiresIn: 3600, // 1 hour | ||
| } | ||
| ); | ||
| return { | ||
| token: token, | ||
| username: user.username, | ||
| type: user.type, | ||
| id: user._id, | ||
| }; | ||
| }) | ||
| .catch(() => { | ||
| throw httpError(400, "Your email or password is incorrect."); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Register a user. | ||
| */ | ||
| async register(user) { | ||
| return this.createUser({ | ||
| username: user.username, | ||
| email: user.email, | ||
| password: user.password, | ||
| type: "Driver", | ||
| }).catch((error) => { | ||
| throw httpError(400, error.message); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Create a user and save it to the User collection. | ||
| */ | ||
| async createUser(userToCreate) { | ||
| if (!isUserDataValid(userToCreate)) { | ||
| throw httpError(400, "User data is invalid."); | ||
| } | ||
| const user = { | ||
| username: userToCreate.username, | ||
| email: userToCreate.email, | ||
| type: userToCreate.type, | ||
| password: bcrypt.hashSync(userToCreate.password, 8), | ||
| }; | ||
|
|
||
| return this.dataLayer.create(user).catch((error) => { | ||
| if (error.message.includes("username")) | ||
| throw httpError(400, "Username is already in use."); | ||
| if (error.message.includes("email")) | ||
| throw httpError(400, "Email is already in use."); | ||
| throw httpError(404, error.message); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Find a user by email | ||
| */ | ||
| async findUserByEmail(email) { | ||
| return this.dataLayer | ||
| .findByProperty({ email: email }) | ||
| .then((users) => { | ||
| // Email is unique so only 1 can be returned. | ||
| return users[0]; | ||
| }) | ||
| .catch((error) => { | ||
| throw httpError(404, error.message); | ||
| }); | ||
| } | ||
| } | ||
| module.exports = UserBusiness; | ||
|
|
||
| /** | ||
| * Validates the data in a User. | ||
| */ | ||
| function isUserDataValid(user) { | ||
| if (!user || !user.username || !user.email || !user.password) { | ||
| return false; | ||
| } else { | ||
| return true; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,8 @@ | ||
| module.exports = { | ||
| url: "mongodb://localhost:27017/highwaytrackerdb", | ||
| dev: { | ||
| url: "mongodb://localhost:27017/highwaytrackerdb", | ||
| }, | ||
| test: { | ||
| url: "mongodb://localhost:27017/highwaytrackerdb_testing", | ||
| }, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| const UserBusiness = require("../business/user.business"); | ||
| const userBusiness = new UserBusiness(); | ||
|
|
||
| /** | ||
| * Login the user | ||
| */ | ||
| exports.login = async (req, res) => { | ||
| userBusiness | ||
| .login(req.body.email, req.body.password) | ||
| .then((data) => { | ||
| req.session.token = data.token; | ||
| req.session.username = data.username; | ||
| req.session.role = data.role; | ||
| req.session.id = data.id; | ||
|
|
||
| res.status(200).send({ | ||
jarrodback marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| message: "Successfully logged in.", | ||
| username: data.username, | ||
| role: data.role, | ||
| id: data.id, | ||
| }); | ||
| }) | ||
| .catch((error) => { | ||
| res.status(error.status).send({ message: error.message }); | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * Register the user | ||
| */ | ||
| exports.register = (req, res) => { | ||
| userBusiness | ||
| .register(req.body) | ||
| .then(() => { | ||
| res.status(201).send({ | ||
| message: "User was successfully created.", | ||
jarrodback marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }); | ||
| }) | ||
| .catch((error) => { | ||
| res.status(error.status).send({ message: error.message }); | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * Logs the user out | ||
| */ | ||
| exports.logout = (req, res) => { | ||
| req.session = null; | ||
| res.status(200).send({ | ||
| message: "User was successfully logged out.", | ||
| }); | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| const mongoose = require("mongoose"); | ||
| mongoose.users = require("../models/user.model")(mongoose); | ||
| const bcrypt = require("bcryptjs"); | ||
|
|
||
| mongoose | ||
| .connect("mongodb://localhost:27017/highwaytrackerdb_testing", { | ||
| useNewUrlParser: true, | ||
| useUnifiedTopology: true, | ||
| }) | ||
| .then(() => { | ||
| console.log("Connection to database successful."); | ||
| }) | ||
| .catch(() => { | ||
| console.log("Connection to database unsuccessful."); | ||
| }); | ||
|
|
||
| const users = [ | ||
| { | ||
| username: "test_username", | ||
| email: "test@email.com", | ||
| password: bcrypt.hashSync("admin", 8), | ||
| type: "Driver", | ||
| }, | ||
| ]; | ||
| const seedDB = async () => { | ||
| await mongoose.users.deleteMany(); | ||
| await mongoose.users.insertMany(users); | ||
| }; | ||
|
|
||
| seedDB() | ||
| .then(() => { | ||
| console.log("Successfully seeded database."); | ||
| }) | ||
| .catch((error) => { | ||
| console.log("An error occurred while seeding databases: ", error); | ||
| }) | ||
| .finally(() => { | ||
| mongoose.connection.close(); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| class DataLayer { | ||
| constructor(model) { | ||
| // Set the collections model to use. | ||
| this.model = model; | ||
| } | ||
|
|
||
| /** | ||
| * Create and save the record to the database. | ||
| */ | ||
| async create(recordToCreate) { | ||
| return this.model.create(recordToCreate); | ||
| } | ||
|
|
||
| /** | ||
| * Find a record by property in the database. | ||
| */ | ||
| async findByProperty(propertyToFind) { | ||
| return this.model.find(propertyToFind); | ||
| } | ||
| } | ||
|
|
||
| module.exports = DataLayer; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| const jwt = require("jsonwebtoken"); | ||
|
|
||
| // Check if token is valid | ||
| checkJwtToken = (req, res, next) => { | ||
| if (!req.session || !req.session.token) { | ||
| return res.status(401).send({ | ||
| message: "Unauthorized: No token provided.", | ||
| }); | ||
| } | ||
| const token = req.session.token; | ||
|
|
||
| jwt.verify(token, process.env.TOKEN_SECRET, (err, decoded) => { | ||
| if (err) { | ||
| return res.status(401).send({ | ||
| message: "Unauthorized: Invalid token.", | ||
| }); | ||
| } | ||
|
|
||
| req.userId = decoded.id; | ||
| req.username = decoded.username; | ||
| req.email = decoded.email; | ||
| req.type = decoded.type; | ||
| return next(); | ||
| }); | ||
| }; | ||
|
|
||
| isOperator = (req, res, next) => { | ||
| const type = req.type; | ||
|
|
||
| if (type != "Toll Operator") { | ||
| return res.status(403).send({ | ||
| message: | ||
| "Unauthorized: You not do have permission to view this page.", | ||
| }); | ||
| } | ||
| return next(); | ||
| }; | ||
|
|
||
| module.exports = { | ||
| checkJwtToken, | ||
| isOperator, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // Model for the User | ||
| module.exports = (mongoose) => { | ||
| var UserSchema = mongoose.Schema({ | ||
| username: { | ||
| type: String, | ||
| required: [true, "You must supply the user's username."], | ||
| minlength: [5, "Your username must be at least 5 letters."], | ||
| unique: true, | ||
| }, | ||
| email: { | ||
| type: String, | ||
| required: [true, "You must supply the user's email."], | ||
| unique: true, | ||
| }, | ||
| password: { | ||
| type: String, | ||
| required: [true, "You must supply the user's password"], | ||
| minlength: [5, "Your password must be at least 8 letters."], | ||
| }, | ||
| type: { | ||
| type: String, | ||
| required: [true, "You must supply the user's role."], | ||
| enum: { | ||
| values: ["Driver", "Toll Operator"], | ||
| message: "Type is not valid. Must be 'Driver'.", | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| return mongoose.model("user", UserSchema); | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.