Compare commits

...

55 Commits

Author SHA1 Message Date
dbroqua 53cebca836 Improved Search 2019-04-12 13:20:17 +02:00
dbroqua c121746380 Fixed bug on search 2019-04-11 19:31:31 +02:00
dbroqua e0468e5805 Fixed bug on search 2019-04-11 19:27:04 +02:00
dbroqua 932b93b9c7 Alpha sort for search 2019-04-11 19:20:24 +02:00
dbroqua 2bba8fb6f4 Fixed localeCompare() 2019-04-11 13:40:52 +02:00
dbroqua 71b6805621 Fixed 2019-04-11 13:39:30 +02:00
dbroqua 0134087eee Fixed ASC 2019-04-11 13:20:05 +02:00
dbroqua 38aff94e26 Fixed bug 2019-04-11 13:17:39 +02:00
dbroqua b2cccada23 Debug 2019-04-11 13:13:01 +02:00
dbroqua f67c8e0167 Fixed bug 2019-04-11 12:57:48 +02:00
dbroqua 9dc6c5385f Added debug 2019-04-11 12:55:16 +02:00
dbroqua dc27bb9f08 Updated default order 2019-04-11 12:47:20 +02:00
dbroqua c6b8219d1e Fixed bug 2019-04-11 12:34:20 +02:00
dbroqua b18612205a Fixed bug 2019-04-11 12:31:56 +02:00
dbroqua e00a165ce2 Updated default order for vegetables in types 2019-04-11 12:28:09 +02:00
dbroqua faaee98022 Fixed bug on delete vegetable 2019-04-09 19:45:00 +02:00
dbroqua 219c2f449c Added limit 2019-03-15 13:56:56 +01:00
dbroqua 218f5de6a0 Fixed bug on full search 2019-03-15 13:55:10 +01:00
dbroqua 338eeb4562 Added vegetable search route 2019-03-15 13:51:11 +01:00
dbroqua b7f909ba09 Removed console.log() 2019-03-12 23:14:45 +01:00
dbroqua a850629661 Fixed bug in AWS lib 2019-03-12 23:13:47 +01:00
dbroqua 823e6f0de3 Removed console.log 2019-03-12 23:11:28 +01:00
dbroqua 8b8f20a6d1 Debug 2019-03-12 23:08:50 +01:00
dbroqua 51e379f104 next debug 2019-03-12 23:03:03 +01:00
dbroqua 1406f4645b Added debug mode 2019-03-12 23:00:37 +01:00
dbroqua 43a5234ab3 Fixed bug 2019-03-12 22:51:32 +01:00
dbroqua cd11c01c9b Added catch on imagemin 2019-03-12 22:50:05 +01:00
dbroqua 3e466925d6 Added catch on fail resize 2019-03-12 22:41:45 +01:00
dbroqua 2c03395371 Fixed bug 2018-10-10 21:20:47 +02:00
dbroqua 3392600861 Fixed bug 2018-10-10 21:17:25 +02:00
dbroqua a09d88684e Fixed bug 2018-10-10 21:14:38 +02:00
dbroqua e93ad5d7b3 Auto add properties 2018-10-10 21:10:43 +02:00
dbroqua dcc78c725b Fixed bug in VegetableProperties 2018-10-06 17:24:11 +02:00
dbroqua abffdc9438 Added Vegetable <-> Properties 2018-10-06 16:17:27 +02:00
dbroqua 6d94b5f60c Added Properties to Vegetable 2018-10-02 19:18:05 +02:00
dbroqua c9652c1366 Reduced size for large image 2018-10-02 07:58:26 +02:00
dbroqua 2397868a5e Removed useless directory 2018-10-02 07:58:15 +02:00
dbroqua a737f48433 Debug AWS 2018-09-20 15:27:37 +02:00
dbroqua 56ddad5ae9 DEBUG 2018-09-20 15:22:46 +02:00
dbroqua defd3cf8a0 DEBUG 2018-09-20 15:16:06 +02:00
dbroqua 745bdab145 Debug test 2018-09-20 15:11:53 +02:00
dbroqua 90f4f688eb Test 2018-09-20 15:06:21 +02:00
dbroqua 8dab5968c3 Debug 2018-09-19 22:15:00 +02:00
dbroqua ca364f202e Fixed bug 2018-09-19 22:12:42 +02:00
dbroqua e4f06185fe Updated Vegetables pictures 2018-09-19 22:08:11 +02:00
dbroqua 405d908a09 Added resize lib 2018-09-19 21:49:02 +02:00
dbroqua b3dc18e57d Ajout de la galerie d'images 2018-09-16 23:46:39 +02:00
dbroqua 4b9bed8926 Set produciton env 2018-09-10 10:14:56 +02:00
dbroqua ddce225376 Updated CORS 2018-09-09 22:56:53 +02:00
dbroqua 4c6f670297 Updated CORS 2018-09-09 22:44:51 +02:00
dbroqua 60cd0f69cc Some changes 2018-09-09 18:15:19 +02:00
dbroqua e738d80579 Added routes for Types and Vegetables 2018-09-08 00:00:47 +02:00
dbroqua a8dc7f8323 Setting up project 2018-09-07 21:14:05 +02:00
dbroqua d07237cc6b Corrections ortho 2018-09-07 17:37:20 +02:00
dbroqua 1eff672f06 MAJ CDC 2018-09-07 16:20:45 +02:00
43 changed files with 11427 additions and 2 deletions

3
.eslintrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
"extends": "standard"
};

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/node_modules

View File

@ -1,3 +1,76 @@
# cfa-nimes
# Projet WEB CFA Nimes
Projet WEB
## Introduction
Le but de ce projet est de créer un mini site administrable permettant de visualiser les végétaux visibles sur le lycée.
## Front
Le front, partie visible par les visiteurs, se compose de 2 blocs :
* Header
* Main
### Header
Le header contient un logo, un menu ainsi qu'une zone de recherche.
Le menu contient 2 éléments :
* Plan
* Végétaux
Le plan renvoie sur la page plan.
Végétaux contient un sous menu listant les différents types de végétaux.
### Main
La zone main contient le contenu de la page courante.
Le site contient 3 types de pages :
* Page d'accueil
* Page listant l'ensemble des végétaux d'une famille
* Plan du lycée
### Recherche
Le module de recherche permet de faire une recherche AJAX avec auto complétion.
Le fait de cliquer sur un résultat de la recherche renvoie sur le plan du lycée.
Sur le plan des marqueurs sont placés aux endroits ou se trouve le végétal recherché.
Les détails du végétal sont affichés sur la droite.
### Plan
La page plan du lycée affiche une carte du lycée.
Des zones sont cliquables. Un clic sur une zone permet d'afficher, sur la droite, le détails du végétal choisi, de la même manière que lors d'une recherche.
## Back
Le back permet aux utilisateurs enregistrés (liste pré définie) de saisir les informations suivantes :
* Type de végétaux (permettant de peupler le menu "Végétal")
* Végétaux
* Placer des marqueurs sur la carte
### Type de Végétaux
L'entité "Type de végétaux" contient simplement un nom.
### Végétaux
L'entité "Végétaux" contient :
* Un nom
* Un "type de Végétaux"
* Une photo principale
* Une ou plusieurs photos secondaires (?)
* Une description
* Une position sur la carte
```
DEBUG=cfa-nimes:* npm start
```

53
app.js Normal file
View File

@ -0,0 +1,53 @@
const createError = require('http-errors')
const express = require('express')
const path = require('path')
const cookieParser = require('cookie-parser')
const logger = require('morgan')
const passport = require('passport')
const session = require('express-session')
const cors = require('cors')
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('view engine', 'pug')
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
app.use(cors())
app.use('/', require('./routes/vegetableTypes')(passport))
app.use('/', require('./routes/vegetables')(passport))
app.use('/', require('./routes/properties')(passport))
app.use('/', require('./routes/user')(passport))
app.use('/', require('./routes/search')(passport))
app.use(function (req, res, next) {
next(createError(404))
})
app.use(function (err, req, res, next) {
res.locals.message = err.message
res.locals.error = req.app.get('env') === 'development' ? err : {}
res.status(err.status || 500)
res.render('error')
})
module.exports = app

59
bin/www Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env node
var app = require('../app')
var debug = require('debug')('cfa-nimes:server')
var http = require('http')
var port = normalizePort(process.env.PORT || '3000')
app.set('port', port)
var server = http.createServer(app)
server.listen(port)
server.on('error', onError)
server.on('listening', onListening)
function normalizePort (val) {
var port = parseInt(val, 10)
if (isNaN(port)) {
// named pipe
return val
}
if (port >= 0) {
// port number
return port
}
return false
}
function onError (error) {
if (error.syscall !== 'listen') {
throw error
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
default:
throw error
}
}
function onListening () {
var addr = server.address()
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port
debug('Listening on ' + bind)
}

23
config/config.json Normal file
View File

@ -0,0 +1,23 @@
{
"development": {
"username": "cfanimes",
"password": "kojee9Mo",
"database": "cfa_nimes",
"host": "cfanimes.c6flpj4u5fit.eu-west-3.rds.amazonaws.com",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "cfanimes",
"password": "bdGGcaAoEeDgDkwG",
"database": "cfanimes",
"host": "127.0.0.1",
"dialect": "mysql"
}
}

106
libs/aws.js Normal file
View File

@ -0,0 +1,106 @@
const AWS = require('aws-sdk')
const fs = require('fs')
const path = require('path')
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
})
fs.unlink(params.path, () => { })
}
})
})
}
_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
}
this._send({
path: newFile,
// 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)
})
})
)
}

64
libs/resize.js Normal file
View File

@ -0,0 +1,64 @@
const fs = require('fs')
const resizeImg = require('resize-img')
class Resize {
constructor (width, heigth) {
this.size = {
width: 128,
heigth: 128
}
if (width && heigth) {
this.setSize(width, heigth)
}
}
_createOutputFilename (input) {
return `${input}_${this.size.width}x${this.size.heigth}`
}
_resize (input, output, callback) {
fs.readFile(input, (err, data) => {
if (err) {
callback(err, null)
return false
}
resizeImg(data, this.size)
.then(buf => {
fs.writeFile(output, buf, (err) => {
if (err) {
callback(err, null)
return false
}
callback(null, { input: input, output: output, size: this.size })
})
})
.catch(callback)
})
}
setSize (width, heigth) {
this.size = {
width: width,
heigth: heigth
}
}
createThumbnail (file, callback) {
this.setSize(128, 128)
this._resize(file, this._createOutputFilename(file), callback)
}
createLargeImage (file, callback) {
this.setSize(1200, 900)
this._resize(file, this._createOutputFilename(file), callback)
}
resize (file, width, heigth, callback) {
this.setSize(width, heigth)
this._resize(file, this._createOutputFilename(file), callback)
}
}
module.exports = Resize

229
middleware/Pictures.js Normal file
View File

@ -0,0 +1,229 @@
const pictures = require('../models').vegetablePictures
const multer = require('multer')
const Vegetables = require('./Vegetables')
const path = require('path')
const fs = require('fs')
const Aws = require('../libs/aws')
const Resize = require('../libs/resize')
const uuid = require('uuid/v4')
class Pictures {
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('picture')
}
_reOrderPictures (position, vegetableId) {
pictures.findAll({
where: {
vegetableId: vegetableId
}
})
.then(items => {
items.forEach((item) => {
let itemPosition = item.order
if (itemPosition >= position) {
item.update({ order: itemPosition - 1 })
.catch((e) => {
console.log(e)
})
}
})
})
.catch((error) => {
console.log(error)
})
}
static getAll (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
pictures.findAndCountAll({
where: {
vegetableId: req.params.vegetablesId
},
order: [
['order', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No picture found'), 204)
return false
}
callback(null, items)
})
.catch((e) => {
callback(e, null)
})
})
}
static getOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
pictures.find({
where: {
id: req.params.pictureId,
vegetableId: req.params.vegetablesId
},
order: [
['order', 'ASC']
]
})
.then(item => {
if (!item) {
callback(new Error('Picture not found'), 404)
return false
}
callback(null, item)
})
.catch((e) => {
callback(e, null)
})
})
}
_createOne (req, callback) {
pictures.create({
order: req.body.order,
url: req.body.url,
vegetableId: req.params.vegetablesId
})
.then(item => {
callback(null, item)
})
.catch(e => {
console.log(e)
callback(e, null)
})
fs.unlink(req.file.path, () => { })
}
createOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
Pictures.getAll(req, (err, items) => {
if (err) {
callback(err, item)
return false
}
const order = items.count + 1
this._upload(req, req.body, (err) => {
if (err) {
callback(err, null)
return false
}
if (req.file) {
const key = uuid()
let aws = new Aws()
let resize = new Resize()
resize.createLargeImage(req.file.path, (err, large) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: large.output,
filename: `picture_${req.params.vegetablesId}_${key}_large.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (err) { callback(err, null) }
req.body = {
order: order,
url: res.file
}
fs.unlink(large.output, () => { })
resize.createThumbnail(req.file.path, (err, file) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: file.output,
filename: `picture_${req.params.vegetablesId}_${key}_thumb.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (err) { callback(err, null) }
this._createOne(req, callback)
fs.unlink(file.output, () => { })
})
})
})
})
} else {
callback(new Error('No file sent'), 406)
}
})
})
})
}
deleteOne (req, callback) {
Pictures.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
const aws = new Aws()
aws.deleteObjects([item.url, item.url.replace('_large.', '_tumb.')], (err) => {
if (err) {
callback(err, null)
return false
}
pictures.destroy({
where: {
id: req.params.pictureId
}
})
.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 = Pictures

92
middleware/Properties.js Normal file
View File

@ -0,0 +1,92 @@
const properties = require('../models').properties
class Properties {
static getAll (req, callback) {
properties.findAndCountAll({
order: [
['name', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No property found'), 204)
return false
}
callback(null, items)
})
.catch((e) => {
callback(e, null)
})
}
createOne (req, callback) {
properties.create(req.body)
.then(item => {
callback(null, item)
})
.catch(e => {
callback(e, null)
})
}
static getOne (req, callback) {
properties.findById(
req.params.propertyId
)
.then(item => {
if (!item) {
callback(new Error('Property not found'), 404)
return false
}
callback(null, item)
})
.catch((e) => {
callback(e, null)
})
}
patchOne (req, callback) {
Properties.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) {
Properties.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
properties.destroy({
where: {
id: req.params.propertyId
}
})
.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 = Properties

View File

@ -0,0 +1,94 @@
const Vegetables = require('./Vegetables')
const vegetableProperties = require('../models').vegetableProperties
class VegetableProperties {
createOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
req.body.vegetableId = req.params.vegetablesId
vegetableProperties.create(req.body)
.then(item => {
callback(null, item)
})
.catch(e => {
callback(e, null)
})
})
}
static getOne (req, callback) {
Vegetables.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
vegetableProperties.findById(
req.params.propertyId,
{
include: ['Vegetable']
})
.then(item => {
if (!item) {
callback(new Error('Item vegetable property not found'), 404)
return false
}
callback(null, item)
})
.catch((e) => {
callback(e, null)
})
})
}
patchOne (req, callback) {
VegetableProperties.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
delete req.body.vegetableId
item.update(req.body)
.then(animal => {
callback(null, animal)
})
.catch(e => {
callback(e, null)
})
})
}
deleteOne (req, callback) {
VegetableProperties.getOne(req, (err, item) => {
if (err) {
callback(err, item)
return false
}
vegetableProperties.destroy({
where: {
id: req.params.propertyId
}
})
.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 = VegetableProperties

View File

@ -0,0 +1,146 @@
const models = require('../models')
const vegetableTypes = models.vegetableTypes
class VegetableTypes {
static getAll (req, callback) {
vegetableTypes.findAndCountAll({
order: [
['name', 'ASC']
],
include: [{
model: models.vegetables,
as: 'Vegetables',
order: [
['name', 'ASC']
]
}]
})
.then(items => {
if (!items) {
callback(new Error('No vegetable type found'), 204)
return false
}
let res = []
for (let i = 0; i < items.rows.length; i += 1) {
let type = items.rows[i].toJSON()
let vegetables = []
for (let j = 0; j < type.Vegetables.length; j += 1) {
let k = 0
for (k = 0; k < vegetables.length; k += 1) {
if (type.Vegetables[j].name.localeCompare(vegetables[k].name) === -1) {
break
}
}
vegetables.splice(k, 0, type.Vegetables[j])
}
type.Vegetables = vegetables
res.push(type)
}
callback(null, { count: res.length, rows: res })
})
.catch((e) => {
console.log('ERR:', 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(
req.params.vegetableTypesId,
{
include: [{
model: models.vegetables,
as: 'Vegetables',
order: [
['name', 'ASC']
]
}]
})
.then(item => {
if (!item) {
callback(new Error('Item vegetable type not found'), 404)
return false
}
let type = item.toJSON()
let vegetables = []
for (let j = 0; j < type.Vegetables.length; j += 1) {
let k = 0
for (k = 0; k < vegetables.length; k += 1) {
if (type.Vegetables[j].name.localeCompare(vegetables[k].name) === -1) {
break
}
}
vegetables.splice(k, 0, type.Vegetables[j])
}
type.Vegetables = vegetables
callback(null, type)
})
.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

409
middleware/Vegetables.js Normal file
View File

@ -0,0 +1,409 @@
const vegetables = require('../models').vegetables
const models = require('../models')
const VegetableTypes = require('./VegetableTypes')
const uuid = require('uuid/v4')
const multer = require('multer')
const path = require('path')
const fs = require('fs')
const Resize = require('../libs/resize')
const Aws = require('../libs/aws')
const Op = models.Sequelize.Op
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 => {
models.properties
.findAndCountAll()
.then(properties => {
if (properties && properties.rows.length > 0) {
let saved = 0
const _callback = () => {
if (properties.count === saved) {
callback(null, item)
}
}
properties.rows.forEach(propperty => {
models.vegetableProperties
.create({
vegetableId: item.id,
propertyId: propperty.id
})
.then(() => {
saved += 1
_callback()
})
.catch((e) => {
console.log(e)
saved += 1
_callback()
})
})
} else {
callback(null, item)
}
})
.catch(e => {
item.destroy()
callback(e, 500)
})
})
.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) {
models.vegetablePictures
.destroy({
where: {
vegetableId: req.params.vegetablesId
}
})
.then(() => {
models.vegetableProperties
.destroy({
where: {
vegetableId: req.params.vegetablesId
}
})
.then(() => {
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, path.replace('_large.', '_thumb.')], callback)
}
static getAll (req, callback) {
vegetables.findAndCountAll({
where: {
vegetableTypeId: req.params.vegetableTypesId
},
include: ['Type'],
order: [
['name', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No vegetable found'), 204)
return false
}
callback(null, items)
})
.catch((e) => {
callback(e, null)
})
}
static searchAll (req, callback) {
if (!req.query.q || req.query.q.length < 3) {
callback(new Error('Minimum 3 letters'), 406)
return false
}
vegetables.findAndCountAll({
where: {
[Op.or]: {
name: {
[Op.like]: `%${req.query.q}%`
},
'$Properties.value$': {
[Op.like]: `%${req.query.q}%`
}
}
},
include: ['Type', 'Properties'],
order: [
['name', 'ASC']
]
})
.then(items => {
if (!items) {
callback(new Error('No vegetable found'), 204)
return false
}
let vegetables = []
for (let j = 0; j < items.rows.length; j += 1) {
const item = items.rows[j].toJSON()
let k = 0
for (k = 0; k < vegetables.length; k += 1) {
if (item.name.localeCompare(vegetables[k].name) === -1) {
break
}
}
vegetables.splice(k, 0, item)
}
callback(null, { count: vegetables.length, rows: vegetables })
})
.catch((e) => {
console.log('ERR:', 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 uploaded = 0
let aws = new Aws()
let thumb = new Resize()
let large = new Resize()
const key = uuid()
let _create = () => {
if (uploaded === 2) {
this._createItem(req, callback)
fs.unlink(req.file.path, () => { })
}
}
large.createLargeImage(req.file.path, (err, file) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: file.output,
filename: `main_${key}_large.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (!err) {
req.body.mainPicture = res.file
uploaded += 1
_create()
fs.unlink(file.output, () => { })
}
})
})
thumb.createThumbnail(req.file.path, (err, file) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: file.output,
filename: `main_${key}_thumb.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (!err) {
uploaded += 1
_create()
fs.unlink(file.output, () => { })
}
})
})
} else {
this._createItem(req, callback)
}
})
})
}
static getOne (req, callback) {
vegetables.find({
where: {
vegetableTypeId: req.params.vegetableTypesId,
id: req.params.vegetablesId
},
include: [
'Type',
'Pictures',
{
model: models.vegetableProperties,
as: 'Properties',
include: ['Property']
}
]
})
.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 uploaded = 0
let aws = new Aws()
let thumb = new Resize()
let large = new Resize()
const key = uuid()
if (item.mainPicture !== null && item.mainPicture !== '') {
this._deleteMedias(item.mainPicture)
}
let _patch = () => {
if (uploaded === 2) {
this._patchOne(item, values, callback)
fs.unlink(req.file.path, () => { })
}
}
large.createLargeImage(req.file.path, (err, file) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: file.output,
filename: `main_${key}_large.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (!err) {
values.mainPicture = res.file
uploaded += 1
_patch()
fs.unlink(file.output, () => { })
}
})
})
thumb.createThumbnail(req.file.path, (err, file) => {
if (err) {
callback(err, null)
return false
}
aws.upload({
path: file.output,
filename: `main_${key}_thumb.${req.file.originalname.split('.')[req.file.originalname.split('.').length - 1]}`
}, (err, res) => {
if (!err) {
uploaded += 1
_patch()
fs.unlink(file.output, () => { })
}
})
})
} 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 !== '') {
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

@ -0,0 +1,35 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users')
}
}

View File

@ -0,0 +1,26 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('vegetableTypes', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('vegetableTypes')
}
}

View File

@ -0,0 +1,42 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('vegetables', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
mainPicture: {
type: Sequelize.STRING
},
description: {
type: Sequelize.TEXT
},
lat: {
type: Sequelize.INTEGER
},
lng: {
type: Sequelize.INTEGER
},
vegetableTypeId: {
type: Sequelize.INTEGER,
references: { model: 'vegetableTypes', key: 'id' }
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('vegetables')
}
}

View File

@ -0,0 +1,33 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('vegetablePictures', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
url: {
type: Sequelize.STRING
},
order: {
type: Sequelize.INTEGER
},
vegetableId: {
type: Sequelize.INTEGER,
references: { model: 'vegetables', key: 'id' }
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('vegetablePictures')
}
}

View File

@ -0,0 +1,27 @@
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('properties', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('properties');
}
};

View File

@ -0,0 +1,32 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('vegetableProperties', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
vegetableId: {
type: Sequelize.INTEGER
},
propertyId: {
type: Sequelize.INTEGER
},
value: {
type: Sequelize.TEXT
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('vegetableProperties')
}
}

35
models/index.js Normal file
View File

@ -0,0 +1,35 @@
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const basename = path.basename(__filename)
const env = process.env.NODE_ENV || 'development'
const config = require(path.join(__dirname, '/../config/config.json'))[env]
const db = {}
let sequelize
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config)
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config)
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js')
})
.forEach(file => {
const model = sequelize['import'](path.join(__dirname, file))
db[model.name] = model
})
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db

9
models/properties.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = (sequelize, DataTypes) => {
const Properties = sequelize.define('properties', {
name: DataTypes.STRING
}, {})
Properties.associate = function (models) {
// associations can be defined here
}
return Properties
}

11
models/users.js Normal file
View File

@ -0,0 +1,11 @@
module.exports = (sequelize, DataTypes) => {
const Users = sequelize.define('Users', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING
}, {})
Users.associate = function (models) {
}
return Users
}

View File

@ -0,0 +1,27 @@
module.exports = (sequelize, DataTypes) => {
const vegetableProperties = sequelize.define('vegetableProperties', {
vegetableId: {
type: DataTypes.INTEGER,
references: 'vegetables',
referencesKey: 'id'
},
propertyId: {
type: DataTypes.INTEGER,
references: 'properties',
referencesKey: 'id'
},
value: DataTypes.TEXT
}, {})
vegetableProperties.associate = function (models) {
vegetableProperties.hasOne(models.vegetables, {
as: 'Vegetable',
foreignKey: 'id'
})
vegetableProperties.belongsTo(models.properties, {
as: 'Property',
foreignKey: 'propertyId',
targetKey: 'id'
})
}
return vegetableProperties
}

31
models/vegetables.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = (sequelize, DataTypes) => {
const vegetables = sequelize.define('vegetables', {
name: DataTypes.STRING,
mainPicture: DataTypes.STRING,
description: DataTypes.TEXT,
lat: DataTypes.INTEGER,
lng: DataTypes.INTEGER,
vegetableTypeId: {
type: DataTypes.INTEGER,
references: 'vegetableTypes',
referencesKey: 'id'
}
}, {})
vegetables.associate = function (models) {
vegetables.belongsTo(models.vegetableTypes, {
as: 'Type',
foreignKey: 'vegetableTypeId'
})
vegetables.hasMany(models.vegetablePictures, {
as: 'Pictures',
foreignKey: 'vegetableId',
onDelete: 'cascade'
})
vegetables.hasMany(models.vegetableProperties, {
as: 'Properties',
foreignKey: 'vegetableId',
onDelete: 'cascade'
})
}
return vegetables
}

View File

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

View File

@ -0,0 +1,13 @@
module.exports = (sequelize, DataTypes) => {
const vegetableTypes = sequelize.define('vegetableTypes', {
name: DataTypes.STRING
}, {})
vegetableTypes.associate = function (models) {
vegetableTypes.hasMany(models.vegetables, {
as: 'Vegetables',
onDelete: 'cascade',
foreignKey: 'vegetableTypeId'
})
}
return vegetableTypes
}

9172
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "cfa-nimes",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodejs ./bin/www",
"dev": "DEBUG=myapp:* nodemon"
},
"dependencies": {
"aws-sdk": "^2.311.0",
"bcrypt-nodejs": "0.0.3",
"cookie-parser": "~1.4.3",
"cors": "^2.8.4",
"debug": "~2.6.9",
"express": "~4.16.0",
"express-session": "^1.15.6",
"http-errors": "~1.6.2",
"imagemin": "^6.0.0",
"imagemin-jpegtran": "^5.0.2",
"imagemin-pngquant": "^6.0.0",
"morgan": "~1.9.0",
"multer": "^1.3.1",
"mysql2": "^1.6.1",
"passport": "^0.4.0",
"passport-http": "^0.3.0",
"pug": "2.0.0-beta11",
"resize-img": "^1.1.2",
"sequelize": "^4.38.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"eslint": "^5.5.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"gulp": "^4.0.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

75
routes/properties.js Normal file
View File

@ -0,0 +1,75 @@
const express = require('express')
const router = express.Router()
const Properties = require('../middleware/Properties')
module.exports = function (passport) {
const basePath = '/api/properties/'
const itemPath = basePath + ':propertyId'
router.route(basePath)
.get(
function (req, res) {
Properties.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 property = new Properties()
property.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(201).json(item)
}
})
}
)
router.route(itemPath)
.get(
function (req, res) {
Properties.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 property = new Properties()
property.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 property = new Properties()
property.deleteOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
return router
}

22
routes/search.js Normal file
View File

@ -0,0 +1,22 @@
const express = require('express')
const router = express.Router()
const Vegetables = require('../middleware/Vegetables')
module.exports = function () {
const basePath = '/api/search/vegetables'
router.route(basePath)
.get(
function (req, res) {
Vegetables.searchAll(req, function (err, items) {
if (err) {
res.status(items || 500).send(err.message)
} else {
res.status(200).json(items)
}
})
}
)
return router
}

22
routes/user.js Normal file
View File

@ -0,0 +1,22 @@
const express = require('express')
const router = express.Router()
module.exports = function (passport) {
router.route('/api/login/')
.post(
passport.authenticate(['basic-auth']),
function (req, res) {
res.status(200).send(req.user)
}
)
router.route('/api/me/')
.get(
passport.authenticate(['basic-auth']),
function (req, res) {
res.status(200).send(req.user)
}
)
return 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(201).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
}

204
routes/vegetables.js Normal file
View File

@ -0,0 +1,204 @@
const express = require('express')
const router = express.Router()
const Vegetables = require('../middleware/Vegetables')
const Pictures = require('../middleware/Pictures')
const Properties = require('../middleware/VegetableProperties')
module.exports = function (passport) {
const basePath = '/api/types/:vegetableTypesId/vegetables'
const itemPath = basePath + '/:vegetablesId'
const picturesPath = itemPath + '/pictures'
const picturePath = picturesPath + '/:pictureId'
const propertiesPath = itemPath + '/properties'
const propertyPath = propertiesPath + '/:propertyId'
/* Vegetables */
router.route(basePath)
.get(
function (req, res) {
Vegetables.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 vegetable = new Vegetables()
vegetable.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(201).json(item)
}
})
}
)
/* Vegetable */
router.route(itemPath)
.get(
function (req, res) {
Vegetables.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 vegetable = new Vegetables()
vegetable.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 vegetable = new Vegetables()
vegetable.deleteOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
/* Pictures */
router.route(picturesPath)
.get(
function (req, res) {
Pictures.getAll(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.post(
passport.authenticate(['basic-auth']),
function (req, res) {
const picture = new Pictures()
picture.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(201).json(item)
}
})
}
)
/* Picture */
router.route(picturePath)
.get(
function (req, res) {
Pictures.getOne(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 picture = new Pictures()
picture.deleteOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
/* Properties */
router.route(propertiesPath)
.get(
function (req, res) {
Properties.getAll(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(200).json(item)
}
})
}
)
.post(
passport.authenticate(['basic-auth']),
function (req, res) {
const property = new Properties()
property.createOne(req, function (err, item) {
if (err) {
res.status(item || 500).send(err.message)
} else {
res.status(201).json(item)
}
})
}
)
/* Property */
router.route(propertyPath)
.get(
function (req, res) {
Properties.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 property = new Properties()
property.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 property = new Properties()
property.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()
}
], {})
}
}

6
views/error.pug Normal file
View File

@ -0,0 +1,6 @@
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}

5
views/index.pug Normal file
View File

@ -0,0 +1,5 @@
extends layout
block content
h1= title
p Welcome to #{title}

7
views/layout.pug Normal file
View File

@ -0,0 +1,7 @@
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content