2020-08-07 12:23:59 +02:00
const bcrypt = require ( "bcrypt" ) ;
const jwt = require ( "jsonwebtoken" ) ;
const slugify = require ( 'slugify' ) ;
const { Op , QueryTypes } = require ( "sequelize" ) ; // pour certaines requêtes sql
const config = require ( "../config/main.js" ) ;
const configTpl = require ( "../views/" + config . theme + "/config/" + config . availableLangs [ 0 ] + ".js" ) ;
const tool = require ( "../tools/main" ) ;
const toolError = require ( "../tools/error" ) ;
const toolFile = require ( "../tools/file" ) ;
const toolMail = require ( "../tools/mail" ) ;
const txt = require ( "../lang/" + config . adminLang + "/user" ) ;
const txtGeneral = require ( "../lang/" + config . adminLang + "/general" ) ;
const answerCtrl = require ( "./answer" ) ;
const subscriptionCtrl = require ( "./subscription" ) ;
// Retourne certaines configurations utiles aux formulaires où vues
exports . checkEmailIsFree = async ( req , res , next ) =>
{
try
{
const user = await searchUserByEmail ( req . body . emailTest ) ;
const response = { } ;
if ( user )
{
response . free = false ;
if ( user . Subscription )
response . validated = true ;
else
response . validated = false ;
}
else
response . free = true ;
res . status ( 200 ) . json ( response ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . getGodfatherId = async ( req , res , next ) =>
{
try
{
const godfather = await searchIdGodfather ( req . body . codeTest ) ;
if ( godfather )
res . status ( 200 ) . json ( godfather . id ) ;
else
res . status ( 204 ) . json ( { errors : txt . godfatherNotFound } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// retourne toutes les infos utiles côté client pour un utilisateur
// revoir : placer dans un autre contrôler dédié à communication avec le front-end
exports . getConfig = ( req , res , next ) =>
{
try
{
//const configLinks = require("../config/links.js");
//const configIllustrations = require("../config/illustrations.js");
const configUsers =
{
// les routes :
siteUrl : config . siteUrl ,
apiUrl : config . apiUrl ,
// -- users
userRoutes : "/user" ,
subscribeRoute : "/signup" ,
getGodfatherRoute : "/getgodfatherid" ,
checkIfIsEmailfreeRoute : "/isemailfree" ,
checkSubscribeTokenRoute : "/validation/" ,
checkLoginRoute : "/checklogin/" ,
connectionRoute : "/login" ,
getLoginLinkRoute : "/getloginlink" ,
connectionWithLinkRoute : "/checkloginlink" ,
getUserInfos : "/get/" ,
createUserRoute : "/create" ,
validateUserRoute : "/validate/" ,
updateUserInfos : "/modify/" ,
searchUserRoute : "/search/" ,
getGodChilds : "/getgodchilds/" ,
checkNewLoginLinkRoute : "/confirmnewlogin/" ,
checkDeleteLinkRoute : "/confirmdelete/" ,
getPayments : "/payment/getforoneuser/" ,
unsubscribeRoute : "/subscription/stop/" ,
// -- questionnaires :
questionnaireRoutes : "/questionnaire" ,
getQuestionnaireRoutes : "/get" ,
previewQuestionnaireRoutes : "/preview" ,
publishedQuestionnaireRoutes : "/quiz/" ,
saveAnswersRoute : "/answer/" ,
getStatsQuestionnaires : "/stats/" ,
searchQuestionnairesRoute : "/search" ,
searchAdminQuestionnairesRoute : "/searchAdmin" ,
getListNextQuestionnaires : "/getListNextQuestionnaires/" ,
// -- tags :
tagsSearchRoute : "/tags/search/" ,
// -- links :
linksRoute : "/link/" ,
// -- illustrations :
illustrationsRoute : "/illustration/" ,
// -- questions & choices :
questionsRoute : "/question/" ,
// -- answers :
getQuestionnairesWithoutAnswer : "/withoutanswer/user/" ,
getPreviousAnswers : "/user/answers/" ,
getStatsAnswers : "/user/anwswers/stats/" ,
getAdminStats : "/getadminstats/" ,
// configuration des champs de saisie
// revoir : toutes ces données devraient venir de fichiers de configuration
// -- users :
name : { maxlength : 70 , required : true } ,
email : { maxlength : 255 , required : true } ,
password : { minlength : config . passwordMinLength , required : true } ,
newPassword : { minlength : config . passwordMinLength } ,
codeGodfather : { maxlength : 255 } ,
cguOk : { value : "true" , required : true } ,
timeDifferenceMin : - 720 ,
timeDifferenceMax : 840 ,
beginCodeGodfather : config . beginCodeGodfather ,
// -- questionnaires :
Questionnaire :
{
title : { maxlength : 255 , required : true } ,
slug : { maxlength : 150 } , // champ requis mais calculé à partir du titre qd vide
introduction : { required : true }
} ,
searchQuestionnaires : { minlength : config . minSearchQuestionnaires , required : true } ,
// -- links :
Link :
{
url : { maxlength : 255 , required : true } ,
anchor : { maxlength : 150 , required : true }
} ,
nbLinksMin : 1 ,
nbLinksMax : 1 ,
// -- illustrations :
Illustration :
{
alt : { maxlength : 255 } ,
title : { maxlength : 255 } ,
caption : { maxlength : 255 } ,
image : { required : true , accept : "'image/jpg', 'image/jpeg', 'image/png', 'image/gif', 'image/png'" } // si possibilité de sélectionner une image déjà chargée, required != true, mais oblige à revoir la suppression des fichiers image
} ,
nbIllustrationsMin : 0 ,
nbIllustrationsMax : 1 ,
// -- questions & choice :
Question :
{
text : { maxlength : 255 , required : true } ,
rank : { required : true , min : 1 , defaultValue : 1 }
} ,
Choice :
{
text : { maxlength : 255 , required : true }
} ,
nbQuestionsMin : config . nbQuestionsMin ,
nbQuestionsMax : config . nbQuestionsMax ,
nbChoicesMax : config . nbChoicesMax ,
// durée des token :
signupValidationTimeInHours : config . tokenSignupValidationTimeInHours ,
loginLinkTimeInHours : config . tokenLoginLinkTimeInHours ,
connexionMinTimeInHours : config . tokenConnexionMinTimeInHours ,
connexionMaxTimeInHours : config . tokenConnexionMaxTimeInDays ,
loginChangingTimeInHours : config . tokenLoginChangingTimeInHours ,
deleteUserTimeInHours : config . tokenDeleteUserTimeInHours ,
unsubscribeLinkTimeInDays : config . tokenUnsubscribeLinkTimeInDays
}
res . status ( 200 ) . json ( configUsers ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . signup = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
if ( req . body . cguOk !== "true" )
res . status ( 400 ) . json ( { errors : [ txt . needUGCOk ] } ) ;
else if ( req . body . password . length < config . passwordMinLength ) // si le champ est supprimé du formulaire d'inscription, générer un mot de passe ok ici
res . status ( 400 ) . json ( { errors : [ txt . needLongPassWord . replace ( "MIN_LENGTH" , config . passwordMinLength ) ] } ) ;
else
{
req . body . GodfatherId = null ;
if ( req . body . codeGodfather !== "" )
{
const godfather = await searchIdGodfather ( req . body . codeGodfather ) ;
if ( godfather )
req . body . GodfatherId = godfather . id ;
}
req . body . password = await bcrypt . hash ( req . body . password , config . bcryptSaltRounds ) ;
const user = await db [ "User" ] . create ( { ... req . body } , { fields : [ "name" , "email" , "password" , "newsletterOk" , "GodfatherId" , "timeDifference" ] } ) ;
req . body . UserId = user . id ;
2020-08-12 17:08:26 +02:00
// si l'utilisateur a répondu à un quiz avant de créer son compte, on enregistre son résultats.
2020-08-07 12:23:59 +02:00
if ( req . body . QuestionnaireId )
{
await Promise . all ( [
db [ "QuestionnaireAccess" ] . create ( { ... req . body } , { fields : [ "QuestionnaireId" , "UserId" ] } ) ,
db [ "Answer" ] . create ( { ... req . body } , { fields : [ "nbQuestions" , "nbCorrectAnswers" , "duration" , "QuestionnaireId" , "UserId" ] } )
2020-08-12 17:08:26 +02:00
] ) ; // pas nécessaire ici de créer le cache JSON, car il sera créé lors de la première connexion au compte.
2020-08-07 12:23:59 +02:00
}
await sendValidationLink ( user ) ;
res . status ( 201 ) . json ( { message : txt . mailValidationMessage } ) ;
next ( ) ;
}
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : returnAPI . messages } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
exports . signupValidation = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const datas = await checkTokenUser ( req . params . token ) ;
if ( datas )
{
if ( datas . Subscription )
res . status ( 200 ) . json ( { errors : [ txt . validationAlreadyMessage ] } ) ;
else
{
const now = new Date ( ) ;
await Promise . all ( [
db [ "Subscription" ] . create ( { numberOfDays : config . freeAccountTimingInDays , noticeOk : datas . User . newsletterOk , UserId : datas . User . id } ) ,
db [ "User" ] . update ( { connectedAt : now } , { where : { id : datas . User . id } , limit : 1 } )
] ) ;
creaUserJson ( datas . User . id ) ;
const mapMail =
{
USER _NAME : datas . User . name ,
NOM _SITE : config . siteName ,
EMAIL : config . senderEmail ,
LINK _URL : config . siteUrl + "/" + configTpl . connectionPage
} ;
2020-08-12 17:08:26 +02:00
const mailDatas =
2020-08-07 12:23:59 +02:00
{
mailSubject : txt . mailWelcomeSubject ,
mailPreheader : txt . mailWelcomeSubject ,
mailTitle : txt . mailWelcomeSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . connectionPage ,
mailHeaderLinkTxt : txt . mailWelcomeLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailWelcomeBodyHTML , mapMail ) ,
linksCTA : [ { url : config . siteUrl + "/" + configTpl . connectionPage , txt : txt . mailWelcomeLinkTxt } ] ,
mailRecipientAddress : datas . User . email
}
toolMail . sendMail ( 0 , datas . User . email , txt . mailWelcomeSubject , tool . replaceAll ( txt . mailWelcomeBodyTxt , mapMail ) , "" , mailDatas ) ;
if ( datas . User . GodfatherId !== null )
{
const godfather = await searchUserById ( datas . User . GodfatherId ) ;
if ( godfather )
{
mapMail . USER _NAME = godfather . User . name ;
mapMail . EMAIL = datas . User . email ;
const mailDatas2 =
{
mailSubject : txt . mailThankGodfatherSubject ,
mailPreheader : txt . mailThankGodfatherSubject ,
mailTitle : txt . mailThankGodfatherSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . connectionPage ,
mailHeaderLinkTxt : txt . mailThankGodfatherLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailThankGodfatherBodyHTML , mapMail ) ,
mailRecipientAddress : godfather . User . email
}
toolMail . sendMail ( godfather . User . smtp , godfather . User . email , txt . mailThankGodfatherSubject , tool . replaceAll ( txt . mailThankGodfatherBodyTxt , mapMail ) , "" , mailDatas2 ) ;
}
}
res . status ( 200 ) . json (
{
userId : datas . User . id ,
token : jwt . sign ( { userId : datas . User . id } , config . tokenPrivateKey , { expiresIn : config . tokenConnexionMinTimeInHours } )
} ) ;
}
}
else
res . status ( 401 ) . json ( { errors : txt . badLinkValidationMessage } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . checkToken = async ( req , res , next ) =>
{
try
{
const datas = await checkTokenUser ( req . params . token ) ;
if ( datas && datas . Subscription )
{
const beginSubTS = new Date ( datas . Subscription . createdAt ) . getTime ( ) ;
const nbDaysOk = datas . Subscription . numberOfDays - Math . round ( ( Date . now ( ) - beginSubTS ) / 1000 / 3600 / 24 ) ;
res . status ( 200 ) . json (
{
isValid : true ,
id : datas . User . id ,
name : datas . User . name ,
language : datas . User . language ,
timeDifference : datas . User . timeDifference ,
status : datas . User . status ,
nbDaysOk : nbDaysOk
} ) ;
}
else
res . status ( 200 ) . json ( { isValid : false } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
2020-08-12 18:51:25 +02:00
// Reçoit les données du formulaire de connexion avec mot de passe.
2020-08-07 12:23:59 +02:00
exports . login = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
2020-08-12 18:51:25 +02:00
// Est-ce qu'un compte existe pour l'adresse e-mail envoyée ?
2020-08-07 12:23:59 +02:00
const emailSend = tool . trimIfNotNull ( req . body . email ) ;
const user = await db [ "User" ] . findOne ( { attributes : [ "id" , "password" , "email" , "name" , "status" ] , where : { email : emailSend } } ) ;
if ( ! user )
res . status ( 404 ) . json ( { errors : [ txt . emailNotFound ] } ) ;
else
{
2020-08-12 18:51:25 +02:00
// Est-ce ce compte a déjà été validé par l'utilisateur ? Si non, on lui envoie un nouveau lien de validation.
2020-08-07 12:23:59 +02:00
const subscription = await db [ "Subscription" ] . findOne ( { attributes : [ "id" ] , where : { UserId : user . id } } ) ;
if ( ! subscription )
{
await sendValidationLink ( user ) ;
res . status ( 400 ) . json ( { errors : [ txt . needValidationToLogin ] } ) ;
}
else
{
const nowTS = new Date ( ) . getTime ( ) ;
2020-08-12 18:51:25 +02:00
// L'utilisateur n'a-t-il pas testé de se connecter de trop nombreuses fois sans succès ?
2020-08-07 12:23:59 +02:00
const countLogin = await toolFile . readJSON ( config . dirTmpLogin , slugify ( emailSend ) ) ;
2020-08-12 18:51:25 +02:00
if ( countLogin && countLogin . nb >= config . maxLoginFail && countLogin . lastTime > ( nowTS - config . loginFailTimeInMinutes * 60 * 1000 ) )
2020-08-07 12:23:59 +02:00
res . status ( 401 ) . json ( { errors : [ txt . tooManyLoginFails . replace ( "MINUTES" , config . loginFailTimeInMinutes ) ] } ) ;
else
{
2020-08-12 18:51:25 +02:00
// Le mot du passe envoyé est-il cohérent avec celui de la base de données après chiffrement ?
2020-08-07 12:23:59 +02:00
const valid = await bcrypt . compare ( req . body . password , user . password ) ;
if ( ! valid )
{
res . status ( 401 ) . json ( { errors : [ txt . badPassword ] } ) ;
2020-08-12 18:51:25 +02:00
// On comptabilise l'erreur :
2020-08-07 12:23:59 +02:00
let newCountLogin = { nb : 1 , lastTime : nowTS } ;
2020-08-12 18:51:25 +02:00
if ( countLogin . nb && countLogin . lastTime > ( nowTS - config . loginFailTimeInMinutes * 60 * 1000 ) )
2020-08-07 12:23:59 +02:00
newCountLogin . nb = countLogin . nb + 1 ;
await toolFile . createJSON ( config . dirTmpLogin , slugify ( emailSend ) , newCountLogin ) ;
}
else
{
2020-08-12 18:51:25 +02:00
// Si tout est ok, on enregistre la date de connexion + retourne un token de connexion.
2020-08-07 12:23:59 +02:00
const now = new Date ( ) ;
2020-08-12 18:51:25 +02:00
const timeDifference = req . body . timeDifference ;
2020-08-07 12:23:59 +02:00
db [ "User" ] . update ( { connectedAt : now , timeDifference : timeDifference } , { where : { id : user . id } , limit : 1 } ) ;
creaUserJson ( user . id ) ;
2020-08-12 18:51:25 +02:00
// Connexion à rallonge uniquement possible pour utilisateur de base :
2020-08-07 12:23:59 +02:00
let loginTime = config . tokenConnexionMinTimeInHours ;
if ( ( req . body . keepConnected === "true" ) && ( user . status === "user" ) )
loginTime = config . tokenConnexionMaxTimeInDays ;
2020-08-12 18:51:25 +02:00
// Si des données concernant un quiz ont été transmises, on les enregistre ici :
2020-08-07 12:23:59 +02:00
req . body . UserId = user . id ;
if ( req . body . QuestionnaireId )
{
const access = await subscriptionCtrl . checkQuestionnaireAccess ( user . id , req . body . QuestionnaireId ) ;
if ( ! access )
await db [ "QuestionnaireAccess" ] . create ( { ... req . body } , { fields : [ "QuestionnaireId" , "UserId" ] } ) ;
await db [ "Answer" ] . create ( { ... req . body } , { fields : [ "nbQuestions" , "nbCorrectAnswers" , "duration" , "QuestionnaireId" , "UserId" ] } ) ;
answerCtrl . creaUserAnswersJson ( req . body . UserId ) ;
answerCtrl . creaUserQuestionnairesWithoutAnswerJson ( req . body . UserId ) ;
answerCtrl . creaUserStatsAnwsersJson ( req . body . UserId ) ;
}
res . status ( 200 ) . json (
{
userId : user . id ,
status : user . status ,
connexionTime : loginTime ,
token : jwt . sign ( { userId : user . id } , config . tokenPrivateKey , { expiresIn : loginTime } )
} ) ;
}
}
}
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
2020-08-12 18:51:25 +02:00
// Reçoit les données du formulaire de connexion avec demande de recevoir un lien de connexion.
2020-08-07 12:23:59 +02:00
exports . getLoginLink = async ( req , res , next ) =>
{
try
{
2020-08-12 18:51:25 +02:00
// Est-ce qu'un compte existe pour l'adresse e-mail envoyée ?
2020-08-07 12:23:59 +02:00
const emailSend = tool . trimIfNotNull ( req . body . email ) ;
const userDatas = await searchUserByEmail ( emailSend ) ;
if ( ! userDatas )
res . status ( 404 ) . json ( { errors : [ txt . emailNotFound ] } ) ;
2020-08-12 18:51:25 +02:00
else if ( userDatas . User . status !== "user" ) // seuls les utilisateurs de base peuvent se connecter de cette façon.
2020-08-07 12:23:59 +02:00
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
2020-08-12 18:51:25 +02:00
// Est-ce ce compte a déjà été validé par l'utilisateur ? Si non, on lui envoie un nouveau lien de validation.
2020-08-07 12:23:59 +02:00
if ( ! userDatas . Subscription )
{
await sendValidationLink ( userDatas . User ) ;
res . status ( 401 ) . json ( { errors : [ txt . needValidationToLogin ] } ) ;
}
else
{
const token = jwt . sign ( { userId : userDatas . User . id , keepConnected : req . body . keepConnected } , config . tokenPrivateKey , { expiresIn : config . tokenLoginLinkTimeInHours } ) ;
const mapMail =
{
USER _NAME : userDatas . User . name ,
LINK _URL : config . siteUrl + "/" + configTpl . loginLinkPage + token
} ;
const mailDatas =
{
mailSubject : txt . mailLoginLinkSubject ,
mailPreheader : txt . mailLoginLinkSubject ,
mailTitle : txt . mailLoginLinkSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . loginLinkPage + token ,
mailHeaderLinkTxt : txt . mailLoginLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailLoginLinkBodyHTML , mapMail ) ,
linksCTA : [ { url : config . siteUrl + "/" + configTpl . loginLinkPage + token , txt : txt . mailLoginLinkTxt } ] ,
mailRecipientAddress : userDatas . User . email
}
await toolMail . sendMail ( userDatas . User . smtp , userDatas . User . email , txt . mailLoginLinkSubject , tool . replaceAll ( txt . mailLoginLinkBodyTxt , mapMail ) , "" , mailDatas ) ;
2020-08-12 18:51:25 +02:00
res . status ( 200 ) . json ( { message : txt . mailLoginLinkMessage . replace ( "*TIMING*" , config . tokenLoginLinkTimeInHours ) } ) ;
2020-08-07 12:23:59 +02:00
}
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . checkLoginLink = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const userDatas = await checkTokenUser ( req . body . t ) ;
if ( userDatas . User . status !== "user" )
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else if ( userDatas . Subscription )
{
const now = new Date ( ) ;
const timeDifference = req . body . timeDifference ;
db [ "User" ] . update ( { connectedAt : now , timeDifference : timeDifference } , { where : { id : userDatas . User . id } , limit : 1 } ) ;
creaUserJson ( userDatas . User . id ) ;
let loginTime = config . tokenConnexionMinTimeInHours ;
if ( userDatas . decodedToken . keepConnected === true )
loginTime = config . tokenConnexionMaxTimeInDays ;
// si des données concernant un quiz ont été transmises, je les enregistre ici :
if ( req . body . QuestionnaireId )
{
req . body . UserId = userDatas . User . id ;
const access = await subscriptionCtrl . checkQuestionnaireAccess ( userDatas . User . id , req . body . QuestionnaireId ) ;
if ( ! access )
await db [ "QuestionnaireAccess" ] . create ( { ... req . body } , { fields : [ "QuestionnaireId" , "UserId" ] } ) ;
await db [ "Answer" ] . create ( { ... req . body } , { fields : [ "nbQuestions" , "nbCorrectAnswers" , "duration" , "QuestionnaireId" , "UserId" ] } ) ;
answerCtrl . creaUserAnswersJson ( req . body . UserId ) ;
answerCtrl . creaUserStatsAnwsersJson ( req . body . UserId ) ;
answerCtrl . creaUserQuestionnairesWithoutAnswerJson ( req . body . UserId ) ;
}
res . status ( 200 ) . json (
{
userId : userDatas . User . id ,
connexionTime : loginTime ,
token : jwt . sign ( { userId : userDatas . User . id } , config . tokenPrivateKey , { expiresIn : loginTime } )
} ) ;
}
else // ne devrait pas être possible...
{
await sendValidationLink ( userDatas . User ) ;
res . status ( 401 ) . json ( { errors : [ txt . needValidationToLogin ] } ) ;
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . modify = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
if ( req . body . newPassword && req . body . newPassword . length < config . passwordMinLength )
res . status ( 400 ) . json ( { errors : txt . needLongPassWord . replace ( "MIN_LENGTH" , config . passwordMinLength ) } ) ;
else
{
if ( req . connectedUser . User . status === "user" )
{
await Promise . all ( [
db [ "User" ] . update ( { ... req . body } , { where : { id : req . connectedUser . User . id } , fields : [ "name" , "language" , "newsletterOk" , "timeDifference" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . connectedUser . User . id } , fields : [ "receiptDays" , "noticeOk" ] , limit : 1 } )
] ) ;
creaUserJson ( req . connectedUser . User . id ) ;
const messageRetour = [ txt . updatedOkMessage ] ;
if ( req . body . newPassword || ( req . body . email != req . connectedUser . User . email ) )
{
const newLogin = { userId : req . connectedUser . User . id } ;
req . body . email = tool . trimIfNotNull ( req . body . email ) ;
if ( req . body . email != req . connectedUser . User . email )
{
if ( ! /[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\.[A-Za-z]{2,6}/ . test ( req . body . email ) )
messageRetour . push ( txt . updatedNeedGoodEmail ) ;
else
{
const emailFree = await searchUserByEmail ( req . body . email ) ;
if ( emailFree !== false )
messageRetour . push ( txt . updatedNeedUniqueEmail . replace ( "NEW_EMAIL" , req . body . email ) ) ;
else
newLogin . email = req . body . email ;
}
}
if ( req . body . newPassword )
newLogin . password = await bcrypt . hash ( req . body . newPassword , config . bcryptSaltRounds ) ;
if ( newLogin . email || newLogin . password )
{
const token = jwt . sign ( newLogin , config . tokenPrivateKey , { expiresIn : config . tokenLoginChangingTimeInHours } ) ;
const mapMail =
{
USER _NAME : req . body . name ,
LINK _URL : config . siteUrl + "/" + configTpl . newLoginLinkPage + token
} ;
const mailDatas =
{
mailSubject : txt . mailUpdateLoginSubject ,
mailPreheader : txt . mailUpdateLoginSubject ,
mailTitle : txt . mailUpdateLoginSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . newLoginLinkPage + token ,
mailHeaderLinkTxt : txt . mailUpdateLoginLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailUpdateLoginBodyHTML , mapMail ) ,
linksCTA : [ { url : config . siteUrl + "/" + configTpl . newLoginLinkPage + token , txt : txt . mailUpdateLoginLinkTxt } ] ,
mailRecipientAddress : req . body . email
}
await toolMail . sendMail ( req . connectedUser . User . smtp , req . body . email , txt . mailUpdateLoginSubject , tool . replaceAll ( txt . mailUpdateLoginBodyTxt , mapMail ) , "" , mailDatas ) ;
messageRetour . push ( txt . mailUpdateLoginLinkMessage . replace ( "NEW_EMAIL" , req . body . email ) ) ;
}
}
res . status ( 200 ) . json ( { message : messageRetour } ) ;
}
else
{
let userToUpdating = await searchUserById ( req . params . id ) ;
if ( ! userToUpdating || ! userToUpdating . Subscription )
res . status ( 400 ) . json ( { errors : [ txt . updatedNeedValidatedUser ] } ) ;
else
{
const messageRetour = [ txtGeneral . updateOkMessage ] ;
if ( req . body . newPassword )
req . body . password = await bcrypt . hash ( req . body . newPassword , config . bcryptSaltRounds ) ;
if ( tool . isEmpty ( req . body . newGodfatherId ) )
req . body . GodfatherId = null ;
else if ( req . body . newGodfatherId && req . body . newGodfatherId !== req . params . id && await searchUserById ( req . body . newGodfatherId ) )
req . body . GodfatherId = req . body . newGodfatherId ;
else
messageRetour . push ( txt . updatedNeedGoodGodfather ) ;
switch ( req . connectedUser . User . status )
{
case "admin" :
await Promise . all ( [
db [ "User" ] . update ( { ... req . body } , { where : { id : req . params . id } , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . params . id } , limit : 1 } )
] ) ;
break ;
case "manager" :
await Promise . all ( [
db [ "User" ] . update ( { ... req . body } , { where : { id : req . params . id } , fields : [ "name" , "email" , "password" , "language" , "adminComments" , "smtp" , "newsletterOk" , "GodfatherId" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . params . id } , fields : [ "numberOfDays" , "receiptDays" , "noticeOk" ] , limit : 1 } )
] ) ;
break ;
case "creator" :
await Promise . all ( [
db [ "User" ] . update ( { ... req . body } , { where : { id : req . params . id } , fields : [ "name" , "email" , "password" , "language" , "adminComments" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . params . id } , fields : [ "numberOfDays" , "receiptDays" ] , limit : 1 } )
] ) ;
break ;
default :
throw { message : txtGeneral . serverError } ;
}
await creaUserJson ( req . params . id ) ; // besoin d'attendre car utiliser pour rafraîchir l'affichage
res . status ( 200 ) . json ( { message : messageRetour } ) ;
}
}
}
next ( ) ;
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : returnAPI . messages } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
exports . checkNewLoginLink = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const userDatas = await checkTokenUser ( req . params . token ) ;
if ( userDatas )
{
if ( userDatas . User . id !== req . connectedUser . User . id )
res . status ( 401 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
await db [ "User" ] . update ( { ... userDatas . decodedToken } , { where : { id : userDatas . User . id } , fields : [ "email" , "password" ] , limit : 1 } ) ;
creaUserJson ( userDatas . User . id ) ;
res . status ( 200 ) . json ( { message : txt . mailUpdateLoginOkMessage } ) ;
}
}
else
res . status ( 404 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . create = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const connectedUser = req . connectedUser ;
if ( connectedUser . User . status === "user" )
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
if ( ! tool . isEmpty ( req . body . GodfatherId ) && ! await searchUserById ( req . body . GodfatherId ) )
res . status ( 400 ) . json ( { errors : [ txt . updatedFailedGodfatherNotFound ] } ) ;
else
{
req . body . password = await bcrypt . hash ( req . body . password , config . bcryptSaltRounds ) ;
if ( req . body . GodfatherId === "" )
req . body . GodfatherId = null ;
let user ;
switch ( connectedUser . User . status )
{
case "admin" :
user = await db [ "User" ] . create ( { ... req . body } ) ;
req . body . UserId = user . id ;
await db [ "Subscription" ] . create ( { ... req . body } ) ;
break ;
case "manager" :
user = await db [ "User" ] . create ( { ... req . body } , { fields : [ "name" , "email" , "password" , "language" , "adminComments" , "smtp" , "newsletterOk" , "GodfatherId" ] } ) ;
req . body . UserId = user . id ;
await db [ "Subscription" ] . create ( { ... req . body } , { fields : [ "numberOfDays" , "receiptDays" , "noticeOk" , "UserId" ] } ) ;
break ;
case "creator" :
user = await db [ "User" ] . create ( { ... req . body } , { fields : [ "name" , "email" , "password" , "language" , "adminComments" ] } ) ;
req . body . UserId = user . id ;
await db [ "Subscription" ] . create ( { ... req . body } , { fields : [ "numberOfDays" , "receiptDays" , "UserId" ] } ) ;
break ;
default :
throw { message : [ txtGeneral . serverError ] } ;
}
creaUserJson ( req . body . UserId ) ;
res . status ( 201 ) . json ( { message : [ txt . creationOkMessage ] , id : req . body . UserId } ) ;
}
}
next ( ) ;
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : [ returnAPI . messages ] } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
exports . validate = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const connectedUser = req . connectedUser ;
if ( [ "admin" , "manager" ] . indexOf ( connectedUser . User . status ) === - 1 )
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
const userToValidating = await searchUserById ( req . params . id ) ;
if ( ! userToValidating )
res . status ( 404 ) . json ( { errors : [ txt . notFound ] } ) ;
else if ( userToValidating . Subscription )
res . status ( 400 ) . json ( { errors : [ txt . validationAlreadyMessageAdmin ] } ) ;
else
{
await db [ "Subscription" ] . create ( { numberOfDays : config . freeAccountTimingInDays , UserId : req . params . id } ) ;
creaUserJson ( req . params . id ) ;
res . status ( 200 ) . json ( { message : [ txt . validationMessageAdmin ] } ) ;
}
}
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : returnAPI . messages } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
exports . delete = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const connectedUser = req . connectedUser ;
if ( connectedUser . User . status === "user" )
{
const userDatas = await searchUserById ( connectedUser . User . id ) ;
const token = jwt . sign ( { userId : connectedUser . User . id } , config . tokenPrivateKey , { expiresIn : config . tokenDeleteUserTimeInHours } ) ;
const mapMail =
{
USER _NAME : userDatas . User . name ,
LINK _URL : config . siteUrl + "/" + configTpl . deleteLinkPage + token
} ;
const mailDatas =
{
mailSubject : txt . mailDeleteSubject ,
mailPreheader : txt . mailDeleteSubject ,
mailTitle : txt . mailDeleteSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . deleteLinkPage + token ,
mailHeaderLinkTxt : txt . mailDeleteLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailDeleteBodyHTML , mapMail ) ,
linksCTA : [ { url : config . siteUrl + "/" + configTpl . deleteLinkPage + token , txt : txt . mailDeleteLinkTxt } ] ,
mailRecipientAddress : connectedUser . User . email
}
await toolMail . sendMail ( connectedUser . User . smtp , connectedUser . User . email , txt . mailDeleteSubject , tool . replaceAll ( txt . mailDeleteBodyTxt , mapMail ) , "" , mailDatas ) ;
res . status ( 200 ) . json ( { message : txt . mailDeleteLinkMessage } ) ;
}
else if ( [ "admin" , "manager" , "creator" ] . indexOf ( connectedUser . User . status ) !== - 1 )
{
const userDeleted = await searchUserById ( req . params . id ) ;
if ( ! userDeleted )
throw { message : txt . notFound } ;
const nb = await db [ "User" ] . destroy ( { where : { id : req . params . id } , limit : 1 } ) ;
if ( nb === 1 )
{
await toolFile . deleteJSON ( config . dirCacheUsers , req . params . id ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/without" , req . params . id ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/answers" , req . params . id ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/answers" , "stats" + req . params . id ) ;
let now = new Date ( ) , wasValided = false , wasPremium = false ;
if ( userDeleted . Subscription )
{
wasValided = true ;
if ( userDeleted . Subscription . numberOfDay > config . freeAccountTimingInDays )
wasPremium = true ;
}
db [ "UserDeleted" ] . create ( { createdAt : userDeleted . User . createdAt , deletedAt : now , wasValided : wasValided , wasPremium : wasPremium } ) ;
res . status ( 200 ) . json ( { message : [ txt . deleteOkMessage ] } ) ;
}
else
{
res . status ( 400 ) . json ( { errors : txtGeneral . serverError } ) ;
throw { message : txt . deleteFailMessage + req . params . id } ;
}
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . checkDeleteLink = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const connectedUser = req . connectedUser ;
const userDatas = await checkTokenUser ( req . params . token ) ;
if ( userDatas )
{
if ( connectedUser . User . id != userDatas . User . id )
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
const nb = await db [ "User" ] . destroy ( { where : { id : connectedUser . User . id } , limit : 1 } ) ;
if ( nb === 1 )
{
await toolFile . deleteJSON ( config . dirCacheUsers , connectedUser . User . id ) ;
res . status ( 200 ) . json ( { message : txt . mailDeleteLinkOkMessage } ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/without" , connectedUser . User . id ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/answers" , connectedUser . User . id ) ;
toolFile . deleteJSON ( config . dirCacheUsersQuestionnaires + "/answers" , "stats" + connectedUser . User . id ) ;
const now = new Date ( ) ; wasPremium = false ;
if ( userDatas . Subscription . numberOfDay > config . freeAccountTimingInDays )
wasPremium = true ;
db [ "UserDeleted" ] . create ( { createdAt : userDatas . User . createdAt , deletedAt : now , wasValided : true , wasPremium : wasPremium } ) ;
}
else
res . status ( 400 ) . json ( { errors : [ txt . mailDeleteLinkAlreadyMessage ] } ) ;
}
}
else
res . status ( 400 ) . json ( { errors : [ txt . mailDeleteLinkFailMessage ] } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . getOneUserById = async ( req , res , next ) =>
{
try
{
const connectedUser = req . connectedUser ;
if ( connectedUser . User . status === "user" )
{
if ( connectedUser . User . id != req . params . id )
res . status ( 403 ) . json ( { errors : txtGeneral . notAllowed } ) ;
else
{
const datas = await searchUserById ( connectedUser . User . id ) ;
if ( datas )
res . status ( 200 ) . json ( datas ) ;
else
res . status ( 404 ) . json ( { message : txt . notFound } ) ;
}
}
else if ( [ "admin" , "manager" , "creator" ] . indexOf ( connectedUser . User . status ) !== - 1 )
{ // dans le cas des "creator" il faudra peut-être limité l'accès à "ses" utilisateurs ?
const datas = await searchUserById ( req . params . id ) ;
if ( datas )
res . status ( 200 ) . json ( datas ) ;
else
res . status ( 404 ) . json ( { message : txt . notFound } ) ;
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . getOneUserGodChilds = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const connectedUser = req . connectedUser ;
let godchilds ;
if ( [ "admin" , "manager" , "creator" ] . indexOf ( connectedUser . User . status ) === - 1 )
godchilds = await db [ "User" ] . findAll ( { where : { GodfatherId : connectedUser . User . id } , attributes : [ "id" , "name" , "email" ] } ) ;
else
godchilds = await db [ "User" ] . findAll ( { where : { GodfatherId : req . params . id } , attributes : [ "id" , "name" , "email" ] } ) ;
res . status ( 200 ) . json ( godchilds ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . searchUsers = async ( req , res , next ) =>
{
try
{
const connectedUser = req . connectedUser ;
if ( [ "admin" , "manager" , "creator" ] . indexOf ( connectedUser . User . status ) === - 1 )
res . status ( 403 ) . json ( { errors : [ txtGeneral . notAllowed ] } ) ;
else
{
const db = require ( "../models/index" ) ;
const Users = await db . sequelize . query ( "SELECT `id`,`name`,`email` FROM `Users` WHERE `name` LIKE :search OR `adminComments` LIKE :search OR `email` LIKE :search OR `id` = :id" , { replacements : { search : "%" + req . body . search + "%" , id : req . body . search } , type : QueryTypes . SELECT } ) ;
res . status ( 200 ) . json ( Users ) ;
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Retourne des statistiques concernant les utilisateurs
// Utile tableau de bord gestionnaires
exports . getStats = async ( req , res , next ) =>
{
try
{
let stats = await getStatsUsers ( ) ;
stats . Answers = await answerCtrl . getStatsAnswers ( ) ;
stats . Subscriptions = await subscriptionCtrl . getStatsSubscriptions ( ) ;
res . status ( 200 ) . json ( stats ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// CRONS
exports . deleteLoginFail = async ( req , res , next ) =>
{
try
{
const fileExpiration = new Date ( ) . getTime ( ) - config . loginFailTimeInMinutes * 60 * 1000 ;
const deleteFiles = await toolFile . deleteOldFilesInDirectory ( config . dirTmpLogin , fileExpiration ) ;
res . status ( 200 ) . json ( deleteFiles ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . deleteJsonFiles = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const users = await db [ "User" ] . findAll ( { attributes : [ "id" ] } ) ;
let saveFiles = [ ] ;
for ( let i in users )
saveFiles . push ( users [ i ] . id + ".json" ) ;
const deleteFiles = await Promise . all ( [
toolFile . deleteFilesInDirectory ( config . dirCacheUsers , saveFiles ) ,
toolFile . deleteFilesInDirectory ( config . dirCacheUsersQuestionnaires , saveFiles )
] ) ;
res . status ( 200 ) . json ( deleteFiles ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . deleteUnvalided = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const nowTS = Date . now ( ) ;
const timeExpiration = nowTS - parseInt ( config . tokenSignupValidationTimeInHours , 10 ) * 3600 * 1000 ;
const userUnvalided = await db . sequelize . query ( "SELECT createdAt FROM `Users` WHERE UNIX_TIMESTAMP(createdAt) < " + timeExpiration + " AND `id` NOT IN (SELECT `UserId` FROM `Subscriptions`)" , { type : QueryTypes . SELECT } ) ;
if ( userUnvalided . length !== 0 )
{
const [ results , metadata ] = await db . sequelize . query ( "DELETE FROM `Users` WHERE UNIX_TIMESTAMP(createdAt) < " + timeExpiration + " AND `id` NOT IN (SELECT `UserId` FROM `Subscriptions`)" ) ;
const now = new Date ( ) ;
for ( i in userUnvalided )
await db [ "UserDeleted" ] . create ( { createdAt : userUnvalided [ i ] . createdAt , deletedAt : now , wasValided : false } ) ;
res . message = metadata . affectedRows + txt . cronDeleteUnvalidedUsersMessage ;
}
res . status ( 200 ) . json ( true ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . deleteInactiveAccounts = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
// compte inactif = abonnement expiré + non connecté depuis un certains nombres de jours
const usersInactive = await db . sequelize . query ( "SELECT createdAt FROM `Users` WHERE status='user' and ADDDATE(`connectedAt`, " + config . inactiveAccountTimeToDeleteInDays + ") < NOW() AND `id` IN (SELECT `UserId` FROM `Subscriptions` WHERE ADDDATE(`createdAt`, `numberOfDays`)< NOW())" , { type : QueryTypes . SELECT } ) ;
if ( usersInactive . length !== 0 )
{
const [ results , metadata ] = await db . sequelize . query ( "DELETE FROM `Users` WHERE ADDDATE(`connectedAt`, " + config . inactiveAccountTimeToDeleteInDays + ") < NOW() AND `id` IN (SELECT `UserId` FROM `Subscriptions` WHERE ADDDATE(`createdAt`, `numberOfDays`)< NOW())" ) ;
if ( metadata . affectedRows !== 0 )
res . message = metadata . affectedRows + txt . deleteInactiveUsersMessage ;
const now = new Date ( ) ;
for ( i in usersInactive )
await db [ "UserDeleted" ] . create ( { createdAt : usersInactive [ i ] . createdAt , deletedAt : now , wasValided : true } ) ;
}
res . status ( 200 ) . json ( true ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// FONCTIONS UTILITAIRES
// Création du fichier des données de l'utilisateur + son abonnement et ses pauses
const creaUserJson = async ( id ) =>
{
id = tool . trimIfNotNull ( id ) ;
if ( id === null )
return false ;
const db = require ( "../models/index" ) ;
const User = await db [ "User" ] . findByPk ( id , { attributes : { exclude : [ 'password' ] } } ) ;
if ( User )
{
let datas = { User } ;
const Subscription = await db [ "Subscription" ] . findOne ( { where : { UserId : id } } ) ;
if ( Subscription ) // pas de cache pour utilisateurs non validés
{
datas . Subscription = Subscription ;
const Pauses = await db [ "Pause" ] . findAll ( { where : { SubscriptionId : Subscription . id } } ) ;
if ( Pauses )
datas . Pauses = Pauses ;
await toolFile . createJSON ( config . dirCacheUsers , id , datas ) ;
}
return datas ;
}
else
return false ;
}
exports . creaUserJson = creaUserJson ;
const searchUserById = async ( id ) =>
{
id = tool . trimIfNotNull ( id ) ;
if ( id === null )
return false ;
const user = await toolFile . readJSON ( config . dirCacheUsers , id ) ;
if ( user )
return user ;
else
return await creaUserJson ( id ) ;
}
exports . searchUserById = searchUserById ;
const searchUserByEmail = async ( email ) =>
{
const db = require ( "../models/index" ) ;
const emailSend = tool . trimIfNotNull ( email ) ;
const userEmail = await db [ "User" ] . findOne ( { attributes : [ "id" ] , where : { email : emailSend } } ) ;
if ( userEmail )
return await searchUserById ( userEmail . id ) ; // permet de récupérer les autres infos (Subscription, etc.)
else
return false ;
}
// Recherche le parrain dont le "code" fourni peut être l'identifiant préfixé ou bien l'adresse e-mail
const searchIdGodfather = async ( code ) =>
{
let godfatherInfos = "" ;
code = tool . trimIfNotNull ( code ) ;
if ( code === null )
return false ;
else if ( code . indexOf ( "@" ) !== - 1 ) // tester en premier, car une adresse peut débuter par le préfixe de l'appli...
godfatherInfos = await searchUserByEmail ( code ) ;
else if ( code . startsWith ( config . beginCodeGodfather ) )
godfatherInfos = await searchUserById ( code . substring ( config . beginCodeGodfather . length ) ) ;
if ( godfatherInfos . Subscription && godfatherInfos . User . status === "user" ) // le parrain doit avoir validé son compte et doit être un simple "user"
return godfatherInfos . User ;
else
return null ;
}
// Envoi le lien permettant au nouvel utilisateur de valider son compte
const sendValidationLink = async ( user ) =>
{
const token = jwt . sign ( { userId : user . id } , config . tokenPrivateKey , { expiresIn : config . tokenSignupValidationTimeInHours } ) ;
const mapMail =
{
USER _NAME : user . name ,
LINK _URL : config . siteUrl + "/" + configTpl . validationLinkPage + token ,
} ;
const mailDatas =
{
mailSubject : txt . mailValidationLinkSubject ,
mailPreheader : txt . mailValidationLinkSubject ,
mailTitle : txt . mailValidationLinkSubject ,
mailHeaderLinkUrl : config . siteUrl + "/" + configTpl . validationLinkPage + token ,
mailHeaderLinkTxt : txt . mailValidationLinkTxt ,
mailMainContent : tool . replaceAll ( txt . mailValidationLinkSBodyHTML , mapMail ) ,
linksCTA : [ { url : config . siteUrl + "/" + configTpl . validationLinkPage + token , txt : txt . mailValidationLinkTxt } ] ,
mailRecipientAddress : user . email
}
await toolMail . sendMail ( 0 , user . email , txt . mailValidationLinkSubject , tool . replaceAll ( txt . mailValidationLinkSBodyTxt , mapMail ) , "" , mailDatas ) ;
return true ;
}
// Permet de vérifier un token de connexion : est-il valide et est-ce qu'il correspond à un utilisateur ?
// Si oui, on peut aussi enregistrer une nouvelle connexion pour l'utilisateur (une fois / jour)
const checkTokenUser = async ( token ) =>
{
const db = require ( "../models/index" ) ;
const decodedToken = jwt . verify ( token , config . tokenPrivateKey ) ;
const userId = decodedToken . userId ;
const datas = await searchUserById ( userId ) ;
if ( datas . User )
{
const now = new Date ( ) ;
const nowTS = Date . now ( )
const lastConnection = Date . parse ( datas . User . connectedAt ) ;
if ( lastConnection + 24 * 3600 * 1000 < nowTS ) // une fois par jour suffit.
{
await db [ "User" ] . update ( { connectedAt : now } , { where : { id : userId } , limit : 1 } ) ;
creaUserJson ( userId ) ;
}
datas . decodedToken = decodedToken ;
return datas ;
}
else
return false ;
}
exports . checkTokenUser = checkTokenUser ;
// Stats sur les créations de compte, suppression.. durant les dernières 24H ou depuis le début
const getStatsUsers = async ( ) =>
{
const db = require ( "../models/index" ) ;
const getNewUsers24H = await db . sequelize . query ( "SELECT `id` FROM `Users` WHERE `createdAt` > ADDDATE(NOW(), -1)" , { type : QueryTypes . SELECT } ) ;
const getNewUsersTot = await db . sequelize . query ( "SELECT `id` FROM `Users`" , { type : QueryTypes . SELECT } ) ;
const getDeletedUsers24H = await db . sequelize . query ( "SELECT `id` FROM `UserDeleteds` WHERE `deletedAt` > ADDDATE(NOW(), -1)" , { type : QueryTypes . SELECT } ) ;
const getDeletedUsersTot = await db . sequelize . query ( "SELECT `id` FROM `UserDeleteds`" , { type : QueryTypes . SELECT } ) ;
const getDeletedUsersWasValided = await db . sequelize . query ( "SELECT `id` FROM `UserDeleteds` WHERE `wasValided`= 1" , { type : QueryTypes . SELECT } ) ;
const getDeletedUsersTotWasPremium = await db . sequelize . query ( "SELECT `id` FROM `UserDeleteds` WHERE `wasPremium`= 1" , { type : QueryTypes . SELECT } ) ;
if ( getNewUsers24H && getNewUsersTot && getDeletedUsers24H && getDeletedUsersWasValided && getDeletedUsersTotWasPremium && getDeletedUsersTot )
{
const stats =
{
nbNewUsers24H : getNewUsers24H . length ,
nbNewUsersTot : getNewUsersTot . length ,
nbDeletedUsers24H : getDeletedUsers24H . length ,
nbDeletedUsersTot : getDeletedUsersTot . length ,
nbDeletedUsersWasValided : getDeletedUsersWasValided . length ,
nbDeletedUsersTotWasPremium : getDeletedUsersTotWasPremium . length
}
return stats ;
}
else
return false ;
}
exports . getStatsUsers = getStatsUsers ;