Compare commits

..

No commits in common. "develop" and "master" have entirely different histories.

43 changed files with 2 additions and 11427 deletions

View file

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

1
.gitignore vendored
View file

@ -1 +0,0 @@
/node_modules

View file

@ -1,76 +1,3 @@
# Projet WEB CFA Nimes # cfa-nimes
## Introduction Projet WEB
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
View file

@ -1,53 +0,0 @@
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
View file

@ -1,59 +0,0 @@
#!/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)
}

View file

@ -1,23 +0,0 @@
{
"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"
}
}

View file

@ -1,106 +0,0 @@
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

View file

@ -1,67 +0,0 @@
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

@ -1,64 +0,0 @@
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

View file

@ -1,229 +0,0 @@
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

View file

@ -1,92 +0,0 @@
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

@ -1,94 +0,0 @@
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

@ -1,146 +0,0 @@
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

View file

@ -1,409 +0,0 @@
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

@ -1,35 +0,0 @@
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

@ -1,26 +0,0 @@
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

@ -1,42 +0,0 @@
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

@ -1,33 +0,0 @@
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

@ -1,27 +0,0 @@
'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

@ -1,32 +0,0 @@
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')
}
}

View file

@ -1,35 +0,0 @@
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

View file

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

View file

@ -1,11 +0,0 @@
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

@ -1,27 +0,0 @@
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
}

View file

@ -1,31 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,13 +0,0 @@
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

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
{
"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.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View file

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

View file

@ -1,75 +0,0 @@
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
}

View file

@ -1,22 +0,0 @@
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
}

View file

@ -1,22 +0,0 @@
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
}

View file

@ -1,75 +0,0 @@
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
}

View file

@ -1,204 +0,0 @@
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
View file

@ -1,8 +0,0 @@
#! /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

@ -1,23 +0,0 @@
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()
}
], {})
}
}

View file

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

View file

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

View file

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