Added routes for Types and Vegetables

This commit is contained in:
dbroqua 2018-09-08 00:00:47 +02:00
parent a8dc7f8323
commit e738d80579
17 changed files with 3938 additions and 304 deletions

21
app.js
View file

@ -3,12 +3,23 @@ const express = require('express')
const path = require('path') const path = require('path')
const cookieParser = require('cookie-parser') const cookieParser = require('cookie-parser')
const logger = require('morgan') const logger = require('morgan')
const passport = require('passport')
const indexRouter = require('./routes/index') const session = require('express-session')
const usersRouter = require('./routes/users')
const app = express() const app = express()
require('./libs/passport')(passport)
app.use(session({
secret: 'CFA_Nimes',
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 180000
}
}))
app.use(passport.initialize())
app.use(passport.session())
app.set('views', path.join(__dirname, 'views')) app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug') app.set('view engine', 'pug')
@ -18,8 +29,8 @@ app.use(express.urlencoded({ extended: false }))
app.use(cookieParser()) app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public'))) app.use(express.static(path.join(__dirname, 'public')))
app.use('/', indexRouter) app.use('/', require('./routes/vegetableTypes')(passport))
app.use('/users', usersRouter) app.use('/', require('./routes/vegetables')(passport))
app.use(function (req, res, next) { app.use(function (req, res, next) {
next(createError(404)) next(createError(404))

111
libs/aws.js Normal file
View file

@ -0,0 +1,111 @@
const AWS = require('aws-sdk')
const fs = require('fs')
const path = require('path')
const imagemin = require('imagemin')
const imageminJpegtran = require('imagemin-jpegtran')
const imageminPngquant = require('imagemin-pngquant')
class Aws {
constructor () {
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
})
}
_send (params, callback) {
fs.readFile(params.path, (err, data) => {
if (err) {
callback(err, null)
return false
}
const base64data = Buffer.from(data, 'binary')
const dest = path.join(process.env.AWS_BASEFOLDER, params.filename)
const s3 = new AWS.S3()
s3.putObject({
Bucket: process.env.AWS_BUCKET,
Key: dest,
Body: base64data,
ACL: 'public-read'
}, (err, res) => {
if (err) {
callback(err, res)
} else {
callback(null, {
file: process.env.AWS_URL + dest
})
}
})
})
}
_compress (params, callback) {
const newFile = params.path + '.' + params.filename.split('.')[1]
fs.copyFile(params.path, newFile, (err, res) => {
if (err) {
callback(err, null)
return false
}
(async () => {
const file = await imagemin([newFile], '/tmp', {
plugins: [
imageminJpegtran(),
imageminPngquant({ quality: '65-80' })
]
})
this._send({
path: file[0].path,
filename: params.filename
}, (err, res) => {
callback(err, res)
fs.unlink(file[0].path, () => {})
})
})()
})
}
/**
* Upload file on s3
* @param {Object} params {path: String, filename: String}
* @param {Function} callback
*/
upload (params, callback) {
fs.readFile(params.path, (err, data) => {
if (err) {
callback(err, null)
return false
}
this._compress(params, callback)
})
}
deleteObjects (files, callback) {
const s3 = new AWS.S3()
const basePath = process.env.AWS_URL + process.env.AWS_BASEFOLDER
let items = []
files.forEach((file) => {
if (file) {
items.push({ Key: file.replace(basePath, '') })
}
})
if (items.length > 0) {
s3.deleteObjects({
Bucket: process.env.AWS_BUCKET,
Delete: { // required
Objects: items
}
}, callback)
} else {
callback(null, { code: 200, res: 'No file deleted' })
}
}
}
module.exports = Aws

67
libs/passport.js Normal file
View file

@ -0,0 +1,67 @@
const BasicAuth = require('passport-http').BasicStrategy
const bCrypt = require('bcrypt-nodejs')
const users = require('../models').Users
/**
* Compare bcrypt password
* @param {Object} user
* @param {String} password
* @returns {Boolean}
*/
let isValidPassword = function (user, password) {
return bCrypt.compareSync(password, user.password)
}
module.exports = function (passport) {
passport.serializeUser(
function (user, done) {
done(null, user.id)
}
)
passport.deserializeUser(
function (id, done) {
users.findById(id)
.then(user => {
if (!user) {
done(new Error('No user found'), user)
return false
}
done(null, user)
})
.catch(e => {
done(e, null)
})
}
)
passport.use(
'basic-auth', new BasicAuth({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function (req, email, password, done) {
users.find({
where: {
email: email
}
})
.then(user => {
if (!user) {
done(new Error('No user found'))
return false
}
if (!isValidPassword(user, password)) {
return done(null, false, {
message: 'Invalid password'
})
}
return done(null, user)
})
.catch(e => {
done(e, null)
})
})
)
}

View file

@ -0,0 +1,90 @@
const vegetableTypes = require('../models').vegetableTypes
class VegetableTypes {
static getAll (req, callback) {
vegetableTypes.findAndCountAll({
order: [
['name', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No vegetable type found'), 204)
return false
}
callback(null, items)
})
.catch((e) => {
callback(e, null)
})
}
createOne (req, callback) {
vegetableTypes.create(req.body)
.then(item => {
callback(null, item)
})
.catch(e => {
callback(e, null)
})
}
static getOne (req, callback) {
vegetableTypes.findById(Number(req.params.vegetableTypesId))
.then(item => {
if (!item) {
callback(new Error('Item vegetable type not found'), 404)
return false
}
callback(null, item)
})
.catch((e) => {
callback(e, null)
})
}
patchOne (req, callback) {
VegetableTypes.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
item.update(req.body)
.then(animal => {
callback(null, animal)
})
.catch(e => {
callback(e, null)
})
})
}
deleteOne (req, callback) {
VegetableTypes.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
vegetableTypes.destroy({
where: {
id: req.params.vegetableTypesId
}
})
.then(deleted => {
if (deleted === 0) {
callback(new Error('Error when trying to delete item'))
return false
}
callback(null, null)
})
.catch(e => {
callback(e, null)
})
})
}
}
module.exports = VegetableTypes

223
middleware/Vegetables.js Normal file
View file

@ -0,0 +1,223 @@
const vegetables = require('../models').vegetables
const VegetableTypes = require('./VegetableTypes')
const uuid = require('uuid/v4')
const multer = require('multer')
const path = require('path')
const fs = require('fs')
const Aws = require('../libs/aws')
class Vegetables {
constructor () {
this._upload = multer({
storage: multer.diskStorage({}),
fileFilter: function (req, file, cb) {
const filetypes = /jpg|jpeg|png|JPG|JPEG|PNG/
const mimetype = filetypes.test(file.mimetype)
const extname = filetypes.test(path.extname(file.originalname).toLowerCase())
if (mimetype && extname) {
return cb(null, true)
}
cb(new Error('Error: File upload only supports the following filetypes - ' + filetypes))
}
}).single('mainPicture')
}
_createItem (req, callback) {
let newItem = req.body
newItem.vegetableTypeId = req.params.vegetableTypesId
vegetables.create(newItem)
.then(item => {
callback(null, item)
})
.catch(e => {
callback(e, null)
})
}
_patchOne (item, values, callback) {
item.update(values)
.then(item => {
callback(null, item)
})
.catch(e => {
callback(e, null)
})
}
_deleteOne (item, req, callback) {
vegetables.destroy({
where: {
id: req.params.vegetablesId
}
})
.then(deleted => {
if (deleted === 0) {
callback(new Error('Error when trying to delete item'))
return false
}
callback(null, null)
})
.catch(e => {
callback(e, null)
})
}
_deleteMedias (path, callback) {
const aws = new Aws()
if (!callback) {
callback = (e) => {
if (e) {
console.error(e)
}
}
}
aws.deleteObjects([path], callback)
}
static getAll (req, callback) {
vegetables.findAndCountAll({
where: {
vegetableTypeId: req.params.vegetableTypesId
},
order: [
['name', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No vegetable found'), 204)
return false
}
callback(null, items)
})
.catch((e) => {
callback(e, null)
})
}
createOne (req, callback) {
VegetableTypes.getOne(req, (err, universe) => {
if (err) {
callback(err, universe)
return false
}
this._upload(req, req.body, (err) => {
if (err) {
callback(err, null)
return false
}
if (req.file) {
let aws = new Aws()
aws.upload({
path: req.file.path,
filename: `main_${uuid()}.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (!err) { req.body.mainPicture = res.file }
this._createItem(req, callback)
fs.unlink(req.file.path, () => {})
})
} else {
this._createItem(req, callback)
}
})
})
}
static getOne (req, callback) {
vegetables.find({
where: {
vegetableTypeId: req.params.vegetableTypesId,
id: req.params.vegetablesId
},
include: ['Type']
})
.then(item => {
if (!item) {
callback(new Error('Vegetable not found'), 404)
return false
}
callback(null, item)
})
.catch((e) => {
callback(e, null)
})
}
patchOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
this._upload(req, req.body, (err) => {
if (err) {
callback(err, null)
return false
}
let values = req.body
if (req.file) {
let aws = new Aws()
if (item.mainPicture !== null && item.mainPicture !== '') {
this._deleteMedias(item.mainPicture)
}
aws.upload({
path: req.file.path,
filename: `main_${req.params.vegetablesId}${path.extname(req.file.originalname).toLowerCase()}`
}, (err, res) => {
if (!err) {
values.mainPicture = res.file
}
this._patchOne(item, values, callback)
fs.unlink(req.file.path, () => {})
})
} else {
this._patchOne(item, values, callback)
}
})
})
}
deleteOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
if (item.mainPicture !== null && item.mainPicture !== '') {
const aws = new Aws()
if (!callback) {
callback = (e) => {
if (e) {
console.error(e)
}
}
}
this._deleteMedias(item.mainPicture, (e, res) => {
if (e) {
callback(e, null)
return false
}
this._deleteOne(item, req, callback)
})
} else {
this._deleteOne(item, req, callback)
}
})
}
}
module.exports = Vegetables

View file

@ -22,7 +22,7 @@ module.exports = {
lng: { lng: {
type: Sequelize.INTEGER type: Sequelize.INTEGER
}, },
vegetableTypes_id: { vegetableTypeId: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
references: { model: 'vegetableTypes', key: 'id' } references: { model: 'vegetableTypes', key: 'id' }
}, },

View file

@ -13,7 +13,7 @@ module.exports = {
order: { order: {
type: Sequelize.INTEGER type: Sequelize.INTEGER
}, },
vegetables_id: { vegetablesId: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
references: { model: 'vegetables', key: 'id' } references: { model: 'vegetables', key: 'id' }
}, },

View file

@ -5,7 +5,7 @@ module.exports = (sequelize, DataTypes) => {
description: DataTypes.TEXT, description: DataTypes.TEXT,
lat: DataTypes.INTEGER, lat: DataTypes.INTEGER,
lng: DataTypes.INTEGER, lng: DataTypes.INTEGER,
vegetableTypes_id: { vegetableTypeId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
references: 'vegetableTypes', references: 'vegetableTypes',
referencesKey: 'id' referencesKey: 'id'
@ -13,8 +13,8 @@ module.exports = (sequelize, DataTypes) => {
}, {}) }, {})
vegetables.associate = function (models) { vegetables.associate = function (models) {
vegetables.hasOne(models.vegetableTypes, { vegetables.hasOne(models.vegetableTypes, {
as: 'VegetableTypes', as: 'Type',
foreignKey: 'vegetableTypes_id' foreignKey: 'id'
}) })
vegetables.hasMany(models.vegetablePictures, { vegetables.hasMany(models.vegetablePictures, {
as: 'Pictures', as: 'Pictures',

View file

@ -2,14 +2,14 @@ module.exports = (sequelize, DataTypes) => {
const vegetablePictures = sequelize.define('vegetablePictures', { const vegetablePictures = sequelize.define('vegetablePictures', {
url: DataTypes.STRING, url: DataTypes.STRING,
order: DataTypes.INTEGER, order: DataTypes.INTEGER,
vegetables_id: { vegetablesId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
references: 'vegetables', references: 'vegetables',
referencesKey: 'id' referencesKey: 'id'
} }
}, {}) }, {})
vegetablePictures.associate = function (models) { vegetablePictures.associate = function (models) {
vegetablePictures.hasOne(models.vegetables, { as: 'Vegetables', foreignKey: 'vegetables_id' }) vegetablePictures.hasOne(models.vegetables, { as: 'Vegetables', foreignKey: 'id' })
} }
return vegetablePictures return vegetablePictures
} }

3507
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,14 +7,24 @@
"dev": "DEBUG=myapp:* nodemon" "dev": "DEBUG=myapp:* nodemon"
}, },
"dependencies": { "dependencies": {
"aws-sdk": "^2.311.0",
"bcrypt-nodejs": "0.0.3",
"cookie-parser": "~1.4.3", "cookie-parser": "~1.4.3",
"debug": "~2.6.9", "debug": "~2.6.9",
"express": "~4.16.0", "express": "~4.16.0",
"express-session": "^1.15.6",
"http-errors": "~1.6.2", "http-errors": "~1.6.2",
"imagemin": "^6.0.0",
"imagemin-jpegtran": "^5.0.2",
"imagemin-pngquant": "^6.0.0",
"morgan": "~1.9.0", "morgan": "~1.9.0",
"multer": "^1.3.1",
"mysql2": "^1.6.1", "mysql2": "^1.6.1",
"passport": "^0.4.0",
"passport-http": "^0.3.0",
"pug": "2.0.0-beta11", "pug": "2.0.0-beta11",
"sequelize": "^4.38.0" "sequelize": "^4.38.0",
"uuid": "^3.3.2"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^5.5.0", "eslint": "^5.5.0",

View file

@ -1,8 +0,0 @@
const express = require('express')
const router = express.Router()
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' })
})
module.exports = router

View file

@ -1,8 +0,0 @@
const express = require('express')
const router = express.Router()
router.get('/', function (req, res, next) {
res.send('respond with a resource')
})
module.exports = router

75
routes/vegetableTypes.js Normal file
View file

@ -0,0 +1,75 @@
const express = require('express')
const router = express.Router()
const VegetableTypes = require('../middleware/VegetableTypes')
module.exports = function (passport) {
const basePath = '/api/types/'
const itemPath = basePath + ':vegetableTypesId'
router.route(basePath)
.get(
function (req, res) {
VegetableTypes.getAll(req, function (err, items) {
if (err) {
res.status(items || 500).send(err.message)
} else {
res.status(200).json(items)
}
})
}
)
.post(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
router.route(itemPath)
.get(
function (req, res) {
VegetableTypes.getOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.patch(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.patchOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.delete(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.deleteOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
return router
}

75
routes/vegetables.js Normal file
View file

@ -0,0 +1,75 @@
const express = require('express')
const router = express.Router()
const VegetableTypes = require('../middleware/Vegetables')
module.exports = function (passport) {
const basePath = '/api/types/:vegetableTypesId/vegetables/'
const itemPath = basePath + ':vegetablesId'
router.route(basePath)
.get(
function (req, res) {
VegetableTypes.getAll(req, function (err, items) {
if (err) {
res.status(items || 500).send(err.message)
} else {
res.status(200).json(items)
}
})
}
)
.post(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
router.route(itemPath)
.get(
function (req, res) {
VegetableTypes.getOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.patch(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.patchOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.delete(
passport.authenticate(['basic-auth']),
function (req, res) {
const vegetableTypes = new VegetableTypes()
vegetableTypes.deleteOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
return router
}

8
run.sh Executable file
View file

@ -0,0 +1,8 @@
#! /bin/bash
AWS_ACCESS_KEY_ID=AKIAJ67E5YL5KLB7MYQQ \
AWS_SECRET_ACCESS_KEY=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 \
AWS_BUCKET=cfa-nimes \
AWS_BASEFOLDER= \
AWS_URL=https://s3.eu-west-3.amazonaws.com/cfa-nimes/ \
npm run dev

View file

@ -0,0 +1,23 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('Users', [
{
firstName: 'Damien',
lastName: 'Broqua',
email: 'contact@darkou.fr',
password: '$2a$10$J4M5xlpdvtEGBY6BQhYhHe9Kz1lr9zt6oJB9Wz8qgFaTXdg4w9RvO', // cfanimes
createdAt: new Date(),
updatedAt: new Date()
},
{
firstName: 'Sharlotte',
lastName: 'Demerson',
email: 'charlotte.cecile@live.fr',
password: '$2a$10$J4M5xlpdvtEGBY6BQhYhHe9Kz1lr9zt6oJB9Wz8qgFaTXdg4w9RvO', // cfanimes
createdAt: new Date(),
updatedAt: new Date()
}
], {})
}
}