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

NotesRouter.put -async moodiin #5

Open
wants to merge 21 commits into
base: part3-1
Choose a base branch
from
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
mongo.js
31 changes: 31 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = {
'env': {
'commonjs': true,
'es2021': true,
'node': true,
'jest': true,
},
'extends': 'eslint:recommended',
'parserOptions': {
'ecmaVersion': 12
},
'rules': {
'indent': [
'error',
2
],
'linebreak-style': [
'error',
'unix'
],
'quotes': [
'error',
'single'
],
'semi': [
'error',
'never'
],
'no-console': 0,
}
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules/
node_modules/
.env
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: npm start
35 changes: 35 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const config = require('./utils/config')
const express = require('express')
const mongoose = require('mongoose')
const app = express()
require('express-async-errors')
const cors = require('cors')
const notesRouter = require('./controllers/notes')
const usersRouter = require('./controllers/users')
const loginRouter = require('./controllers/login')
const middleware = require('./utils/middleware')
const logger = require('./utils/logger')

logger.info('connecting to', config.MONGODB_URI)

mongoose.connect(config.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, useCreateIndex: true })
.then(() => {
logger.info('connected to MongoDB')
})
.catch((error) => {
logger.error('error connection to MongoDB:', error.message)
})

app.use(cors())
app.use(express.static('build'))
app.use(express.json())
app.use(middleware.requestLogger)

app.use('/api/notes', notesRouter)
app.use('/api/users', usersRouter)
app.use('/api/login', loginRouter)

app.use(middleware.unknownEndpoint)
app.use(middleware.errorHandler)

module.exports = app
32 changes: 32 additions & 0 deletions controllers/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const loginRouter = require('express').Router()
const User = require('../models/user')

loginRouter.post('/', async (request, response) => {
const body = request.body

const user = await User.findOne({ username: body.username })
const passwordCorrect = user === null
? false
: await bcrypt.compare(body.password, user.passwordHash)

if (!(user && passwordCorrect)) {
return response.status(401).json({
error: 'invalid username or password'
})
}

const userForToken = {
username: user.username,
id: user._id,
}

const token = jwt.sign(userForToken, process.env.SECRET)

response
.status(200)
.send({ token, username: user.username, name: user.name })
})

module.exports = loginRouter
70 changes: 70 additions & 0 deletions controllers/notes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const jwt = require('jsonwebtoken')
const notesRouter = require('express').Router()
const Note = require('../models/note')
const User = require('../models/user')

notesRouter.get('/', async (request, response) => {
const notes = await Note
.find({}).populate('user', { username: 1, name: 1 })

response.json(notes.map(note => note.toJSON()))
})

const getTokenFrom = request => {
const authorization = request.get('authorization')
if (authorization && authorization.toLowerCase().startsWith('bearer ')) {
return authorization.substring(7)
}
return null
}

notesRouter.post('/', async (request, response) => {
const body = request.body
const token = getTokenFrom(request)
const decodedToken = jwt.verify(token, process.env.SECRET)
if (!token || !decodedToken.id) {
return response.status(401).json({ error: 'token missing or invalid' })
}
const user = await User.findById(decodedToken.id)

const note = new Note({
content: body.content,
important: body.important === undefined ? false : body.important,
date: new Date(),
user: user._id
})

const savedNote = await note.save()
user.notes = user.notes.concat(savedNote._id)
await user.save()

response.json(savedNote.toJSON())
})
notesRouter.get('/:id', async (request, response) => {
const note = await Note.findById(request.params.id)
if (note) {
response.json(note.toJSON())
} else {
response.status(404).end()
}
})

notesRouter.delete('/:id', async (request, response) => {
await Note.findByIdAndRemove(request.params.id)
response.status(204).end()
})

notesRouter.put('/:id', async (request, response, next) => {
const body = request.body
const id = {_id: request.params.id}

const note = {
content: body.content,
important: body.important,
}

await Note.findOneAndUpdate(id, note, { new: true })
response.status(200).end()
})

module.exports = notesRouter
29 changes: 29 additions & 0 deletions controllers/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const bcrypt = require('bcrypt')
const usersRouter = require('express').Router()
const User = require('../models/user')

usersRouter.post('/', async (request, response) => {
const body = request.body

const saltRounds = 10
const passwordHash = await bcrypt.hash(body.password, saltRounds)

const user = new User({
username: body.username,
name: body.name,
passwordHash,
})

const savedUser = await user.save()

response.json(savedUser)
})

usersRouter.get('/', async (request, response) => {
const users = await User
.find({}).populate('notes', { content: 1, date: 1 })

response.json(users.map(u => u.toJSON()))
})

module.exports = usersRouter
89 changes: 7 additions & 82 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,10 @@
const express = require('express')
const app = express()
const app = require('./app') // varsinainen Express-sovellus
const http = require('http')
const config = require('./utils/config')
const logger = require('./utils/logger')

app.use(express.json())
const server = http.createServer(app)


let notes = [
{
id: 1,
content: "HTML is easy",
date: "2020-01-10T17:30:31.098Z",
important: true
},
{
id: 2,
content: "Browser can execute only Javascript",
date: "2020-01-10T18:39:34.091Z",
important: false
},
{
id: 3,
content: "GET and POST are the most important methods of HTTP protocol",
date: "2020-01-10T19:20:14.298Z",
important: true
}
]

app.get('/', (req, res) => {
res.send('<h1>Hello World!</h1>')
})

app.get('/api/notes', (req, res) => {
res.json(notes)
})

const generateId = () => {
const maxId = notes.length > 0
? Math.max(...notes.map(n => n.id))
: 0
return maxId + 1
}

app.post('/api/notes', (request, response) => {
const body = request.body

if (!body.content) {
return response.status(400).json({
error: 'content missing'
})
}

const note = {
content: body.content,
important: body.important || false,
date: new Date(),
id: generateId(),
}

notes = notes.concat(note)

response.json(note)
})

app.get('/api/notes/:id', (request, response) => {
const id = Number(request.params.id)
const note = notes.find(note => note.id === id)

if (note) {
response.json(note)
} else {
response.status(404).end()
}
})

app.delete('/api/notes/:id', (request, response) => {
const id = Number(request.params.id)
notes = notes.filter(note => note.id !== id)

response.status(204).end()
})

const PORT = 3001
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
server.listen(config.PORT, () => {
logger.info(`Server running on port ${config.PORT}`)
})
25 changes: 25 additions & 0 deletions models/note.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const mongoose = require('mongoose')

const noteSchema = new mongoose.Schema({
content: {
type: String,
required: true,
minlength: 5
},
date: Date,
important: Boolean,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
})

noteSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
}
})

module.exports = mongoose.model('Note', noteSchema)
33 changes: 33 additions & 0 deletions models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const mongoose = require('mongoose')
const uniqueValidator = require('mongoose-unique-validator')

const userSchema = mongoose.Schema({
username: {
type: String,
unique: true
},
name: String,
passwordHash: String,
notes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Note'
}
],
})

userSchema.plugin(uniqueValidator)

userSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
// the passwordHash should not be revealed
delete returnedObject.passwordHash
}
})

const User = mongoose.model('User', userSchema)

module.exports = User
Loading