2020-08-03 12:04:07 +02:00
const path = require ( 'path' )
const { validationResult } = require ( 'express-validator' )
const bcrypt = require ( 'bcryptjs' )
const jwt = require ( 'jsonwebtoken' )
const ms = require ( 'ms' )
const uuid = require ( 'uuid' )
const Sequelize = require ( 'sequelize' )
const errorHandling = require ( '../assets/utils/errorHandling' )
const { serverError , generalError } = require ( '../assets/config/errors' )
2020-08-03 14:14:45 +02:00
const {
JWT _SECRET ,
FRONT _END _HOST ,
EMAIL _INFO ,
HOST ,
TOKEN _LIFE
} = require ( '../assets/config/config' )
2020-08-03 12:04:07 +02:00
const transporter = require ( '../assets/config/transporter' )
const { emailUserTemplate } = require ( '../assets/config/emails' )
const Users = require ( '../models/users' )
const Favorites = require ( '../models/favorites' )
const Functions = require ( '../models/functions' )
const Categories = require ( '../models/categories' )
const Comments = require ( '../models/comments' )
const Quotes = require ( '../models/quotes' )
const deleteFilesNameStartWith = require ( '../assets/utils/deleteFilesNameStartWith' )
const getPagesHelper = require ( '../assets/utils/getPagesHelper' )
2020-03-25 16:23:43 +01:00
2020-08-03 14:14:45 +02:00
async function handleEditUser (
res ,
{ name , email , biography , isPublicEmail } ,
userId ,
logoName
) {
2020-08-03 12:04:07 +02:00
const user = await Users . findOne ( { where : { id : userId } } )
user . name = name
if ( user . email !== email ) {
const tempToken = uuid . v4 ( )
user . email = email
user . isConfirmed = false
user . tempToken = tempToken
await transporter . sendMail ( {
from : ` "FunctionProject" < ${ EMAIL _INFO . auth . user } > ` ,
to : email ,
subject : "FunctionProject - Confirmer l'email" ,
2020-08-03 14:14:45 +02:00
html : emailUserTemplate (
"Veuillez confirmer l'email" ,
'Oui, je confirme.' ,
` ${ HOST } /users/confirm-email/ ${ tempToken } ` ,
'Si vous avez reçu ce message par erreur, il suffit de le supprimer. Votre email ne serez pas confirmé si vous ne cliquez pas sur le lien de confirmation ci-dessus.'
)
2020-08-03 12:04:07 +02:00
} )
}
if ( biography != null ) {
user . biography = biography
}
user . isPublicEmail = isPublicEmail
if ( logoName != null && ` /images/users/ ${ logoName } ` !== user . logo ) {
user . logo = ` /images/users/ ${ logoName } `
}
await user . save ( )
2020-08-03 14:14:45 +02:00
return res
. status ( 200 )
. json ( {
id : user . id ,
name : user . name ,
email : user . email ,
biography : user . biography ,
logo : user . logo ,
isPublicEmail : user . isPublicEmail ,
isAdmin : user . isAdmin ,
createdAt : user . createdAt
} )
2020-04-07 16:21:48 +02:00
}
2020-05-02 15:51:51 +02:00
exports . getUsers = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
let { search } = req . query
2020-08-03 14:14:45 +02:00
try {
search = search . toLowerCase ( )
} catch { }
2020-08-03 12:04:07 +02:00
const options = {
where : {
isConfirmed : true ,
// Recherche
2020-08-03 14:14:45 +02:00
... ( search != null && {
name : Sequelize . where (
Sequelize . fn ( 'LOWER' , Sequelize . col ( 'name' ) ) ,
'LIKE' ,
` % ${ search } % `
)
} )
2020-08-03 12:04:07 +02:00
} ,
attributes : {
2020-08-03 14:14:45 +02:00
exclude : [
'updatedAt' ,
'isAdmin' ,
'isConfirmed' ,
'password' ,
'tempToken' ,
'tempExpirationToken' ,
'isPublicEmail' ,
'email'
]
2020-08-03 12:04:07 +02:00
} ,
order : [ [ 'createdAt' , 'DESC' ] ]
}
return await getPagesHelper ( { req , res , next } , Users , options )
2020-05-02 15:51:51 +02:00
}
2020-04-15 13:55:07 +02:00
exports . putUser = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { name , email , biography , isPublicEmail } = req . body
const logo = req . files . logo
const errors = validationResult ( req )
if ( ! errors . isEmpty ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : errors . array ( ) [ 0 ] . msg ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
if ( logo != null ) {
2020-08-03 14:14:45 +02:00
if (
( ! logo || logo . truncated ) &&
( logo . mimetype !== 'image/png' ||
logo . mimetype !== 'image/jpg' ||
logo . mimetype !== 'image/jpeg' ||
logo . mimetype !== 'image/gif' )
) {
return errorHandling ( next , {
message :
'Le profil doit avoir une image valide (PNG, JPG, GIF) et moins de 5mo.' ,
statusCode : 400
} )
2020-04-07 16:21:48 +02:00
}
2020-08-03 12:04:07 +02:00
const splitedLogoName = logo . name . split ( '.' )
if ( splitedLogoName . length !== 2 ) return errorHandling ( next , serverError )
const logoName = name + req . userId + '.' + splitedLogoName [ 1 ]
// Supprime les anciens logo
try {
2020-08-03 14:14:45 +02:00
deleteFilesNameStartWith (
` ${ name + req . userId } ` ,
path . join ( _ _dirname , '..' , 'assets' , 'images' , 'users' ) ,
async ( ) => {
logo . mv (
path . join ( _ _dirname , '..' , 'assets' , 'images' , 'users' , logoName ) ,
async error => {
if ( error ) return errorHandling ( next , serverError )
return await handleEditUser (
res ,
{ name , email , biography , isPublicEmail } ,
req . userId ,
logoName
)
}
)
}
)
2020-08-03 12:04:07 +02:00
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
2020-03-25 16:23:43 +01:00
}
2020-08-03 12:04:07 +02:00
} else {
2020-03-25 16:23:43 +01:00
try {
2020-08-03 14:14:45 +02:00
return await handleEditUser (
res ,
{ name , email , biography , isPublicEmail } ,
req . userId ,
null
)
2020-03-25 16:23:43 +01:00
} catch ( error ) {
2020-08-03 12:04:07 +02:00
console . log ( error )
return errorHandling ( next , serverError )
2020-03-25 16:23:43 +01:00
}
2020-08-03 12:04:07 +02:00
}
}
exports . register = async ( req , res , next ) => {
const { name , email , password } = req . body
const errors = validationResult ( req )
if ( ! errors . isEmpty ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : errors . array ( ) [ 0 ] . msg ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
try {
const hashedPassword = await bcrypt . hash ( password , 12 )
const tempToken = uuid . v4 ( )
await Users . create ( { email , name , password : hashedPassword , tempToken } )
await transporter . sendMail ( {
from : ` "FunctionProject" < ${ EMAIL _INFO . auth . user } > ` ,
to : email ,
subject : "FunctionProject - Confirmer l'inscription" ,
2020-08-03 14:14:45 +02:00
html : emailUserTemplate (
"Veuillez confirmer l'inscription" ,
"Oui, je m'inscris." ,
` ${ HOST } /users/confirm-email/ ${ tempToken } ` ,
'Si vous avez reçu ce message par erreur, il suffit de le supprimer. Vous ne serez pas inscrit si vous ne cliquez pas sur le lien de confirmation ci-dessus.'
)
2020-08-03 12:04:07 +02:00
} )
2020-08-03 14:14:45 +02:00
return res
. status ( 201 )
. json ( {
result :
"Vous y êtes presque, veuillez vérifier vos emails pour confirmer l'inscription."
} )
2020-08-03 12:04:07 +02:00
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
2020-03-25 16:23:43 +01:00
}
exports . login = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { email , password } = req . body
const errors = validationResult ( req )
if ( ! errors . isEmpty ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : errors . array ( ) [ 0 ] . msg ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
try {
const user = await Users . findOne ( { where : { email } } )
if ( ! user ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : "Le mot de passe ou l'adresse email n'est pas valide." ,
statusCode : 400
} )
2020-04-06 16:46:03 +02:00
}
2020-08-03 12:04:07 +02:00
const isEqual = await bcrypt . compare ( password , user . password )
if ( ! isEqual ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : "Le mot de passe ou l'adresse email n'est pas valide." ,
statusCode : 400
} )
2020-03-25 16:23:43 +01:00
}
2020-08-03 12:04:07 +02:00
if ( ! user . isConfirmed ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message :
'Vous devez valider votre adresse email pour votre première connexion.' ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
2020-08-03 14:14:45 +02:00
const token = jwt . sign (
{
email : user . email ,
userId : user . id
} ,
JWT _SECRET ,
{ expiresIn : TOKEN _LIFE }
)
return res
. status ( 200 )
. json ( {
token ,
id : user . id ,
name : user . name ,
email : user . email ,
biography : user . biography ,
logo : user . logo ,
isPublicEmail : user . isPublicEmail ,
isAdmin : user . isAdmin ,
createdAt : user . createdAt ,
expiresIn : Math . round ( ms ( TOKEN _LIFE ) / 1000 )
} )
2020-08-03 12:04:07 +02:00
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
2020-03-25 16:23:43 +01:00
}
exports . confirmEmail = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { tempToken } = req . params
if ( ! tempToken ) {
return errorHandling ( next , generalError )
}
try {
2020-08-03 14:14:45 +02:00
const user = await Users . findOne ( {
where : { tempToken , isConfirmed : false }
} )
2020-08-03 12:04:07 +02:00
if ( ! user ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : "Le token n'est pas valide." ,
statusCode : 400
} )
2020-03-31 07:48:00 +02:00
}
2020-08-03 12:04:07 +02:00
user . tempToken = null
user . isConfirmed = true
await user . save ( )
return res . redirect ( ` ${ FRONT _END _HOST } /users/login?isConfirmed=true ` )
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
2020-03-31 07:48:00 +02:00
}
exports . resetPassword = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { email } = req . body
const errors = validationResult ( req )
if ( ! errors . isEmpty ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : errors . array ( ) [ 0 ] . msg ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
try {
const user = await Users . findOne ( { where : { email , tempToken : null } } )
if ( ! user ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message :
"L'adresse email n'existe pas ou une demande est déjà en cours." ,
statusCode : 400
} )
2020-03-31 07:48:00 +02:00
}
2020-08-03 12:04:07 +02:00
const tempToken = uuid . v4 ( )
user . tempExpirationToken = Date . now ( ) + 3600000 // 1 heure
user . tempToken = tempToken
await user . save ( )
await transporter . sendMail ( {
from : ` "FunctionProject" < ${ EMAIL _INFO . auth . user } > ` ,
to : email ,
subject : 'FunctionProject - Réinitialisation du mot de passe' ,
2020-08-03 14:14:45 +02:00
html : emailUserTemplate (
'Veuillez confirmer la réinitialisation du mot de passe' ,
'Oui, je change mon mot de passe.' ,
` ${ FRONT _END _HOST } /users/newPassword?token= ${ tempToken } ` ,
'Si vous avez reçu ce message par erreur, il suffit de le supprimer. Votre mot de passe ne sera pas réinitialiser si vous ne cliquez pas sur le lien ci-dessus. Par ailleurs, pour la sécurité de votre compte, la réinitialisation du mot de passe est disponible pendant un délai de 1 heure, passez ce temps, la réinitialisation ne sera plus valide.'
)
2020-08-03 12:04:07 +02:00
} )
2020-08-03 14:14:45 +02:00
return res
. status ( 200 )
. json ( {
result :
'Demande de réinitialisation du mot de passe réussi, veuillez vérifier vos emails!'
} )
2020-08-03 12:04:07 +02:00
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
2020-03-31 07:48:00 +02:00
}
exports . newPassword = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { tempToken , password } = req . body
const errors = validationResult ( req )
if ( ! errors . isEmpty ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : errors . array ( ) [ 0 ] . msg ,
statusCode : 400
} )
2020-08-03 12:04:07 +02:00
}
try {
const user = await Users . findOne ( { where : { tempToken } } )
if ( ! user && parseInt ( user . tempExpirationToken ) < Date . now ( ) ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : "Le token n'est pas valide." ,
statusCode : 400
} )
2020-03-25 16:23:43 +01:00
}
2020-08-03 12:04:07 +02:00
const hashedPassword = await bcrypt . hash ( password , 12 )
user . password = hashedPassword
user . tempToken = null
user . tempExpirationToken = null
await user . save ( )
2020-08-03 14:14:45 +02:00
return res
. status ( 200 )
. json ( { result : 'Le mot de passe a bien été modifié!' } )
2020-08-03 12:04:07 +02:00
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
2020-04-06 23:06:21 +02:00
}
exports . getUserInfo = async ( req , res , next ) => {
2020-08-03 12:04:07 +02:00
const { name } = req . params
try {
const user = await Users . findOne ( {
where : { name , isConfirmed : true } ,
attributes : {
2020-08-03 14:14:45 +02:00
exclude : [
'updatedAt' ,
'isAdmin' ,
'isConfirmed' ,
'password' ,
'tempToken' ,
'tempExpirationToken'
]
2020-08-03 12:04:07 +02:00
}
} )
if ( ! user ) {
2020-08-03 14:14:45 +02:00
return errorHandling ( next , {
message : "L'utilisateur n'existe pas." ,
statusCode : 404
} )
2020-08-03 12:04:07 +02:00
}
const favorites = await Favorites . findAll ( {
where : { userId : user . id } ,
include : [
2020-08-03 14:14:45 +02:00
{
model : Functions ,
attributes : {
exclude : [ 'updatedAt' , 'utilizationForm' , 'article' , 'isOnline' ]
} ,
include : { model : Categories , attributes : [ 'name' , 'color' ] }
}
2020-08-03 12:04:07 +02:00
] ,
order : [ [ 'createdAt' , 'DESC' ] ] ,
limit : 5
} )
2020-08-03 14:14:45 +02:00
const favoritesArray = favorites . map ( favorite => favorite . function )
2020-08-03 12:04:07 +02:00
const comments = await Comments . findAll ( {
where : { userId : user . id } ,
include : [
2020-08-03 14:14:45 +02:00
{
model : Functions ,
attributes : {
exclude : [ 'updatedAt' , 'utilizationForm' , 'article' , 'isOnline' ]
}
}
2020-08-03 12:04:07 +02:00
] ,
order : [ [ 'createdAt' , 'DESC' ] ] ,
limit : 5
} )
2020-08-03 14:14:45 +02:00
const commentsArray = comments . map ( commentObject => {
2020-08-03 12:04:07 +02:00
return {
id : commentObject . id ,
message : commentObject . message ,
createdAt : commentObject . createdAt ,
function : commentObject . function . dataValues
}
} )
const quotesArray = await Quotes . findAll ( {
2020-08-03 12:54:19 +02:00
where : { userId : user . id , isValidated : 1 } ,
2020-08-03 12:04:07 +02:00
attributes : {
exclude : [ 'updatedAt' , 'createdAt' , 'isValidated' , 'userId' , 'id' ]
} ,
order : [ [ 'createdAt' , 'DESC' ] ] ,
limit : 5
} )
const userObject = {
// Si Public Email
2020-08-03 14:14:45 +02:00
... ( user . isPublicEmail && { email : user . email } ) ,
2020-08-03 12:04:07 +02:00
isPublicEmail : user . isPublicEmail ,
name : user . name ,
biography : user . biography ,
logo : user . logo ,
createdAt : user . createdAt ,
favoritesArray ,
commentsArray ,
quotesArray
2020-04-06 23:06:21 +02:00
}
2020-08-03 12:04:07 +02:00
return res . status ( 200 ) . json ( userObject )
} catch ( error ) {
console . log ( error )
return errorHandling ( next , serverError )
}
}