Skip to content
Open
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
22 changes: 22 additions & 0 deletions api/models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const mongoose = require("mongoose");

const schema = mongoose.Schema(
{
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
admin: {
type: Boolean,
default: false,
required: true
}
},
{ timestamps: { createdAt: "created_at", updatedAt: "updated_at" } }
);

module.exports = mongoose.model("User", schema);
129 changes: 129 additions & 0 deletions api/routes/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const router = require("express").Router();
const User = require("../models/user");
const bcrypt = require("bcrypt");
const jwot = require("jsonwebtoken");
const { SECRET_KEY } = process.env;

// Starting route
// http://localhost:5000/api/

// GET
// http://localhost:5000/api/users

router.get("/users", async (req, res, next) => {
const status = 200;
const response = await User.find().select("-__v -password");
res.json({ status, response });
});

// POST
// http://localhost:5000/api/signup
// username & password in the body

router.post("/signup", async (req, res, next) => {
const status = 201;
try {
//get username and password, make sure both are provided
const username = req.body.username;
const password = req.body.password;
if (!username || !password)
throw new Error(`Please enter a valid username and password`);
if (password.length < 8) throw new Error(`Please create stronger password`);

//make sure username already exists
let user = await User.findOne({ username });
if (user) throw new Error(`User ${username} already exists.`);

//hash password
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(password, saltRounds);
const userInformation = await User.create({
username,
password: hashedPassword
});

//reassign user, this time find the one you just created
user = await User.findOne({ username });

//JWOT
const payload = { id: user._id };
const options = { expiresIn: "1 day" };
const token = jwot.sign(payload, SECRET_KEY, options);

const response = token;

res.json({ status, response });
} catch (e) {
console.error(e);
const error = e;
error.status = 400;
next(error);
}
});

//POST
// http://localhost:5000/api/login

router.post("/login", async (req, res, next) => {
const status = 200;
try {
//get username and password, make sure both are provided
const username = req.body.username;
const password = req.body.password;
if (!username || !password)
throw new Error(`Please enter a valid username and password`);
//username lookup
const user = await User.findOne({ username });
if (!user) throw new Error(`Account could not be found`);

//check password
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) throw new Error(`Please enter a valid username and password`);

//JWOT
const payload = { id: user._id };
const options = { expiresIn: "1 day" };
const token = jwot.sign(payload, SECRET_KEY, options);

const response = token;
res.json({ status, response });
} catch (e) {
console.error(e);
const error = e;
error.status = 400;
next(error);
}
});

// PATCH
// http://localhost:5000/api/users/5d4fcfb6b64f4427ea074fd4/permissions
// send admin jwot in auth header

router.patch("/users/:id/permissions", async (req, res, next) => {
let status = 204;
try {
//check jwot for permissions
const token = req.headers.authorization.split("Bearer ")[1];
const payload = jwot.verify(token, SECRET_KEY);
const requestor = await User.findOne({ _id: payload.id });
const requestorIsAdmin = requestor.admin === true ? true : false;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just using requester.admin would have the same effect.


if (!token || !payload || !requestor || !requestorIsAdmin)
throw new Error(`You are not authorized to change permissions`);

const user = await User.findById(req.params.id);
if (!user) throw new Error(`Account could not be found`);

user.admin = true;
user.save();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You'll want this to be await user.save()


res.json({ status });
} catch (e) {
console.error(e);
const error = e;
error.status = 400;
next(error);
}
});

module.exports = router;
17 changes: 17 additions & 0 deletions api/routes/books.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const router = require('express').Router()
const Book = require('../models/book')
const User = require("../models/user");
const jwot = require("jsonwebtoken");
const { SECRET_KEY } = process.env;

//GET
// http://localhost:5000/api/books
router.get('/', async (req, res, next) => {
const status = 200
const response = await Book.find().select('-__v')
Expand All @@ -24,10 +29,22 @@ router.get('/:id', async (req, res, next) => {
}
})

// POST
// http://localhost:5000/api/books

// You should only be able to create a book if the user is an admin
router.post('/', async (req, res, next) => {
const status = 200
try {
//check jwot for permissions
const token = req.headers.authorization.split("Bearer ")[1];
const payload = jwot.verify(token, SECRET_KEY);
const requestor = await User.findOne({ _id: payload.id });
const requestorIsAdmin = requestor.admin === true ? true : false;

if (!token || !payload || !requestor || !requestorIsAdmin)
throw new Error(`You are not authorized to change permissions`);

const book = await Book.create(req.body)
if (!book) throw new Error(`Request body failed: ${JSON.stringify(req.body)}`)

Expand Down
1 change: 1 addition & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ app.use(require('body-parser').json())

// Routes
app.use('/api/books', require('./api/routes/books'))
app.use('/api', require('./api/routes/auth'))

// Not Found Handler
app.use((req, res, next) => {
Expand Down
114 changes: 68 additions & 46 deletions db/seeds.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,71 @@
const mongoose = require('mongoose')
const Book = require('../api/models/book')
const config = require('../nodemon.json')
const mongoose = require("mongoose");
const Book = require("../api/models/book");
const User = require("../api/models/user");
const config = require("../nodemon.json");
const bcrypt = require("bcrypt");

const reset = async () => {
mongoose.connect(config.env.MONGO_DB_CONNECTION, { useNewUrlParser: true })
await Book.deleteMany() // Deletes all records
return await Book.create([
{
title: 'The Colour of Magic',
published: 1983,
authors: [
{
name: 'Sir Terry Pratchett',
dob: '04-28-1948'
}
]
},
{
title: 'Stardust',
published: 1997,
authors: [
{
name: 'Neil Gaiman',
dob: '11-10-1960'
}
]
},
{
title: 'Good Omens: The Nice and Accurate Prophecies of Agnes Nutter, Witch',
published: 1990,
authors: [
{
name: 'Neil Gaiman',
dob: '11-10-1960'
},
{
name: 'Sir Terry Pratchett',
dob: '04-28-1948'
}
]
}
])
}
mongoose.connect(config.env.MONGO_DB_CONNECTION, { useNewUrlParser: true });
await Book.deleteMany(); // Deletes all records
await User.deleteMany(); // Deletes all records

reset().catch(console.error).then((response) => {
console.log(`Seeds successful! ${response.length} records created.`)
return mongoose.disconnect()
})
const hashedPassword = await bcrypt.hash('password', 10);
return (
await Book.create([
{
title: "The Colour of Magic",
published: 1983,
authors: [
{
name: "Sir Terry Pratchett",
dob: "04-28-1948"
}
]
},
{
title: "Stardust",
published: 1997,
authors: [
{
name: "Neil Gaiman",
dob: "11-10-1960"
}
]
},
{
title:
"Good Omens: The Nice and Accurate Prophecies of Agnes Nutter, Witch",
published: 1990,
authors: [
{
name: "Neil Gaiman",
dob: "11-10-1960"
},
{
name: "Sir Terry Pratchett",
dob: "04-28-1948"
}
]
}
]),
User.create([
{
username: "admin",
password: hashedPassword,
admin: "true"
},
{
username: "regularUser",
password: hashedPassword,
admin: "false"
}
])
);
};

reset()
.catch(console.error)
.then(response => {
console.log(`Seeds successful! ${response.length} records created.`);
return mongoose.disconnect();
});
Loading