Skip to content

Commit

Permalink
Merge pull request #24 from Fibii/Fibii/meta/add-edit-many-things
Browse files Browse the repository at this point in the history
Fibii/meta/add edit many things
  • Loading branch information
Fibii committed Nov 7, 2020
2 parents bf035a0 + d3b2da9 commit 8b6697f
Show file tree
Hide file tree
Showing 58 changed files with 4,517 additions and 2,280 deletions.
2 changes: 2 additions & 0 deletions backend/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
DB=mongodb://127.0.0.1:27017/qaTEST
PORT=1530
SECRET='SECRET'
FRONTEND=http://localhost:3000
22 changes: 10 additions & 12 deletions backend/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
module.exports = {
env: {
browser: true,
commonjs: true,
es6: true,
jest: true
jest: true,
},
extends: [
'plugin:react/recommended',
'airbnb',
'airbnb-base',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
"semi": [
"error",
"never"
semi: [
'error',
'never',
],
"import/extensions": "off",
"no-console": "off",
"no-alert": "off",
"no-shadow": "off",
'no-underscore-dangle': 'off',
'no-shadow': 'off',
'no-param-reassign': 'off',
},
};
}
63 changes: 46 additions & 17 deletions backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,76 @@ const express = require('express')
const path = require('path')
const fs = require('fs')
const logger = require('morgan')
const mongoose = require('mongoose')
const cors = require('cors')
const cookieParser = require('cookie-parser')
const middleware = require('./utils/middleware')

const indexRouter = require('./controllers/index')
const usersRouter = require('./controllers/users')
const questionRouter = require('./controllers/questions')
const loginRouter = require('./controllers/login')

const mongoose = require('mongoose')
const cors = require('cors')

const app = express()
app.use(logger('dev'))
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' })
app.use(logger('combined', { stream: accessLogStream }))

const DB = process.env.DB
console.log(DB)
const { DB, FRONTEND } = process.env

mongoose.connect('mongodb://127.0.0.1:27017/qaTEST', {
if (!DB) {
console.log('no database uri was found in .env, please provide one')
console.log('quitting')
process.exit(0)
}

let TIMEOUT_SECONDS = 1000

if (process.env.NODE_ENV === 'PROD') {
TIMEOUT_SECONDS = 10000
console.log("NOTE THAT IF THE SERVER CAN'T ESTABLISH A CONNECTION TO THE DATABASE")
console.log(`IT WILL KEEP TRYING TO ESTABLISH ONE FOR ${TIMEOUT_SECONDS} MS`)
console.log(`AND YOU WON'T GET ANY ERRORS UNTIL ${TIMEOUT_SECONDS} MS PASS`)
console.log('read more about that here https://mongoosejs.com/docs/connections.html')
}

const mongooseOptions = {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useCreateIndex: true
})
serverSelectionTimeoutMS: TIMEOUT_SECONDS,
}

mongoose.connect(DB, mongooseOptions)
.then(() => {
console.log("connected to db")
})
.catch(error => {
console.log(error)
})
// eslint-disable-next-line no-console
console.log('connected to db')
})
.catch((err) => {
// eslint-disable-next-line no-console
console.log(`Error on start: ${err.stack}`)
process.exit(1)
})

app.use(cors())
app.use(cookieParser())
app.use(cors({
origin: FRONTEND,
credentials: true,
}))
app.use(express.json())
app.use(middleware.tokenExtractor)
app.use(express.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.static(path.join(__dirname, '../frontend/build')))

app.use('/', indexRouter)
app.use('/api/users', usersRouter)
app.use('/api/questions', questionRouter)
app.use('/api/login', loginRouter)

if (process.env.NODE_ENV === 'PROD') {
app.get('*', (request, response) => {
response.sendFile(path.resolve(__dirname, '../frontend', 'build', 'index.html'))
})
}

app.use(middleware.errorLogger)
app.use(middleware.unknownEndpoint)
app.use(middleware.errorHandler)
Expand Down
180 changes: 180 additions & 0 deletions backend/controllers/comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
const express = require('express')

const router = express.Router()
const Question = require('../models/question')
const Comment = require('../models/comment')
const userService = require('../utils/user')

router.post('/', async (request, response, next) => {
try {
const { body, questionId } = request
const question = await Question.findById(questionId)

if (!question) {
return response.status(401).json({ error: 'invalid question id' })
}

const user = await userService.isAuthenticated(request.cookies.token)
if (user.error) {
return response.status(401).json(user.error)
}

if (!body.content) {
return response.status(401)
.json({ error: 'content must be provided' })
}

const comment = new Comment({
content: body.content,
likes: [{
value: 0,
}],
postedBy: user.id,
})

await comment.save()

const updatedQuestion = {
...question._doc,
comments: question._doc.comments.concat(comment),
}

await Question.findByIdAndUpdate(questionId, updatedQuestion)
return response.status(200).json(comment)
} catch (error) {
return next(error)
}
})

router.post('/:commentId/likes', async (request, response, next) => {
try {
const { body, questionId } = request
const { commentId } = request.params
const comment = await Comment.findById(commentId)
const question = await Question.findById(questionId)

if (!comment || !question) {
return response.status(401).json({ error: 'invalid comment id or question id' })
}

const user = await userService.isAuthenticated(request.cookies.token)
if (user.error) {
return response.status(401).json(user.error)
}

if (!body.likes) {
return response.status(401)
.json({ error: 'value must be provided as a number' })
}

const likeUsers = comment.likes.map((like) => like.likedBy)

// if the user upvotes or downvotes again
if (likeUsers.includes(user.id)) {
const currentLike = body.likes >= 0 ? 1 : -1
const userLikes = comment.likes.filter((like) => String(like.likedBy) === String(user.id))
const userLike = userLikes[userLikes.length - 1].value
if (currentLike === userLike || currentLike * 2 === userLike) {
return response.status(401).end()
}

const updatedComment = {
...comment._doc,
likes: comment.likes.concat({
value: body.likes >= 0 ? 2 : -2,
likedBy: user.id,
}),
}

await Comment.findByIdAndUpdate(comment.id, updatedComment)
return response.status(200).end()
}

const updatedComment = {
...comment._doc,
likes: comment.likes.concat({
value: body.likes >= 0 ? 1 : -1,
likedBy: user.id,
}),
}

await Comment.findByIdAndUpdate(comment.id, updatedComment)
return response.status(200).end()
} catch (error) {
return next(error)
}
})

router.put('/:commentId', async (request, response, next) => {
try {
const { body, questionId } = request
const { commentId } = request.params
const comment = await Comment.findById(commentId)
const question = await Question.findById(questionId)

if (!comment || !question) {
return response.status(401).json({ error: 'invalid comment id or question id' })
}

const user = await userService.isAuthenticated(request.cookies.token)
if (user.error) {
return response.status(401).json(user.error)
}

if (comment.postedBy.toString() !== user._id.toString()) {
return response.status(401).json({ error: 'comments can be deleted by authors only' })
}

if (!body.content) {
return response.status(401)
.json({ error: 'content must be provided' })
}

const updatedComment = {
...comment._doc,
content: body.content,
}

await Comment.findByIdAndUpdate(commentId, updatedComment)
return response.status(200).end()
} catch (error) {
return next(error)
}
})

router.delete('/:commentId', async (request, response, next) => {
try {
const { questionId } = request
const { commentId } = request.params
const comment = await Comment.findById(commentId)
const question = await Question.findById(questionId)

if (!comment || !question) {
return response.status(401).json({ error: 'invalid comment id or question id' })
}

const user = await userService.isAuthenticated(request.cookies.token)
if (user.error) {
return response.status(401).json(user.error)
}

if (comment.postedBy.toString() !== user._id.toString()) {
return response.status(401).json({ error: 'comments can be deleted by authors only' })
}

const updatedQuestion = {
...question._doc,
comments: question._doc.comments.filter((commentID) => commentID !== commentId),
}

await Promise.all([
Question.findByIdAndUpdate(questionId, updatedQuestion),
Comment.findByIdAndRemove(commentId),
])
return response.status(200).end()
} catch (error) {
return next(error)
}
})

module.exports = router
5 changes: 3 additions & 2 deletions backend/controllers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const express = require('express')

const router = express.Router()

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
router.get('/', (req, res) => {
res.render('index', { title: 'Express' })
})

module.exports = router
Loading

0 comments on commit 8b6697f

Please sign in to comment.