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" ) ;
2020-09-22 17:54:23 +02:00
const configUsers = require ( "../config/users.js" ) ;
2020-08-07 12:23:59 +02:00
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 ) ;
}
}
2020-10-20 16:41:34 +02:00
// Contrôleur traitant les données envoyées pour une inscription
2020-10-22 17:47:05 +02:00
// Les CGU doivent être acceptées et une adresse e-mail envoyée.
2020-11-30 16:10:53 +01:00
// Un champ email2 invisible ne devrait être envoyé que par des bots
2020-10-22 17:47:05 +02:00
// Le reste peut être adapté sur la page de validation de l'inscription.
2020-08-07 12:23:59 +02:00
exports . signup = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
if ( req . body . cguOk !== "true" )
res . status ( 400 ) . json ( { errors : [ txt . needUGCOk ] } ) ;
2020-10-20 16:41:34 +02:00
else if ( tool . isEmpty ( req . body . email ) )
res . status ( 400 ) . json ( { errors : [ txt . needEmail ] } ) ;
2020-11-30 16:10:53 +01:00
else if ( ! tool . isEmpty ( req . body . email2 ) )
{
res . status ( 400 ) . json ( { errors : [ txt . failBotTest ] } ) ;
console . log ( txt . failBotTestLog + req . body . email2 ) ;
}
2020-08-07 12:23:59 +02:00
else
{
2020-10-21 16:45:34 +02:00
// Un mot de passe temporaire et non communiqué est généré :
req . body . passwordTemp = tool . getPassword ( 8 , 12 ) ;
req . body . password = await bcrypt . hash ( req . body . passwordTemp , config . bcryptSaltRounds ) ;
// Un pseudo temporaire est créé en utilisant la partie de l'e-mail précédant le "@" :
const lastIndex = req . body . email . indexOf ( "@" ) ;
if ( lastIndex === - 1 ) // possible car validité de l'e-mail testé par le modèle lors de l'enregistrement
lastIndex = 1 ;
req . body . name = req . body . email . substring ( 0 , lastIndex ) ;
const user = await db [ "User" ] . create ( { ... req . body } , { fields : [ "name" , "email" , "password" , "timeDifference" ] } ) ;
req . body . UserId = user . id ;
2020-10-22 17:47:05 +02:00
// Si l'utilisateur a répondu à un quiz (ou groupe de quizs) avant de créer son compte, on enregistre son résultat :
2020-08-07 12:23:59 +02:00
if ( req . body . QuestionnaireId )
2020-10-22 17:47:05 +02:00
await answerCtrl . saveAnswerToQuestionnaire ( req . body ) ;
else if ( req . body . GroupId )
await answerCtrl . saveAnswerToGroup ( req . body ) ;
2020-08-07 12:23:59 +02:00
await sendValidationLink ( user ) ;
2020-11-30 16:10:53 +01:00
res . status ( 201 ) . json ( { message : txt . mailValidationMessage . replace ( "#EMAIL" , req . body . email ) } ) ;
2020-08-07 12:23:59 +02:00
next ( ) ;
}
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : returnAPI . messages } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
2020-10-21 16:45:34 +02:00
// Contrôleur testant le lien de validation du compte et envoyant un message de bienvenue si tout est ok
2020-08-07 12:23:59 +02:00
exports . signupValidation = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const datas = await checkTokenUser ( req . params . token ) ;
if ( datas )
{
if ( datas . Subscription )
2020-10-21 13:08:56 +02:00
res . status ( 200 ) . json ( { errors : [ txt . validationAlreadyMessage . replace ( "#URL" , configTpl . connectionPage ) ] } ) ;
2020-08-07 12:23:59 +02:00
else
{
const now = new Date ( ) ;
await Promise . all ( [
2020-11-10 16:26:44 +01:00
db [ "Subscription" ] . create ( { numberOfDays : config . freeAccountTimingInDays , receiptDays : config . defaultReceiptDays , UserId : datas . User . id } ) ,
2020-08-07 12:23:59 +02:00
db [ "User" ] . update ( { connectedAt : now } , { where : { id : datas . User . id } , limit : 1 } )
] ) ;
2020-10-21 13:08:56 +02:00
const newUser = await creaUserJson ( datas . User . id ) ;
2020-08-07 12:23:59 +02:00
const mapMail =
{
USER _NAME : datas . User . name ,
NOM _SITE : config . siteName ,
2020-11-10 16:26:44 +01:00
EMAIL : config . senderEmail ,
LINK _URL : config . siteUrl + "/" + configTpl . connectionPage
2020-08-07 12:23:59 +02:00
} ;
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 ) ;
res . status ( 200 ) . json (
{
2020-10-21 13:08:56 +02:00
newUser : newUser ,
2020-08-07 12:23:59 +02:00
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 ) ;
}
}
2020-10-21 13:08:56 +02:00
// Contrôleur recevant les données envoyées par l'utilisateur lorsqu'il lui est demandé de complèter ses informations, juste après avoir validé son abonnement
// Il peut fournir ici un pseudo et un mot de passe de son choix ou encore un code parrain
// Il peut asussi choisir les jours de réception de son abonnement au site
exports . signUpCompletion = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
if ( ! tool . isEmpty ( req . body . newPassword ) && req . body . newPassword . length < config . passwordMinLength )
res . status ( 400 ) . json ( { errors : txt . needLongPassWord . replace ( "MIN_LENGTH" , config . passwordMinLength ) } ) ;
else
{
2020-10-21 16:45:34 +02:00
if ( ! tool . isEmpty ( req . body . newPassword ) ) // dans ce cas, l'utilisateur n'a pas choisi de mot de passe, mais pourra se connecter via les tokens de connexion
2020-10-21 13:08:56 +02:00
req . body . password = await bcrypt . hash ( req . body . newPassword , config . bcryptSaltRounds ) ;
req . body . GodfatherId = null ;
if ( req . body . codeGodfather !== "" )
{
const godfather = await searchIdGodfather ( req . body . codeGodfather ) ;
2020-11-10 16:47:08 +01:00
if ( godfather && godfather . id !== req . connectedUser . User . id ) // des fois qu'il se serait désigné lui-même comme "parrain" :)
2020-10-21 13:08:56 +02:00
req . body . GodfatherId = godfather . id ;
}
await Promise . all ( [
db [ "User" ] . update ( { ... req . body } , { where : { id : req . connectedUser . User . id } , fields : [ "name" , "password" , "GodfatherId" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . connectedUser . User . id } , fields : [ "receiptDays" ] , limit : 1 } )
] ) ;
const user = await creaUserJson ( req . connectedUser . User . id ) ;
2020-10-21 16:45:34 +02:00
// Si un parrain a été désigné, on prévient l'heureux élu :) :
2020-10-21 13:08:56 +02:00
if ( user !== false && req . body . GodfatherId !== null )
{
const godfather = await searchUserById ( req . body . GodfatherId ) ;
if ( godfather )
{
const mapMail =
{
USER _NAME : godfather . User . name ,
NOM _SITE : config . siteName ,
EMAIL : user . User . email ,
LINK _URL : config . siteUrl + "/" + configTpl . connectionPage
} ;
const mailDatas =
{
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 ) , "" , mailDatas ) ;
}
}
const messageRetour = [ txt . updatedOkMessage ] ;
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 ) ;
}
}
2020-08-07 12:23:59 +02:00
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 ( ) ;
2020-12-07 16:42:39 +01:00
// Si abonnement illimité, pas besoin de calculer le nbre de jours restants
const nbDaysOk = ( datas . Subscription . numberOfDays === 0 ) ? 1 : datas . Subscription . numberOfDays - Math . round ( ( Date . now ( ) - beginSubTS ) / 1000 / 3600 / 24 ) ;
2020-08-07 12:23:59 +02:00
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 } ) ;
2020-10-22 17:47:05 +02:00
await 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 ;
2020-10-22 17:47:05 +02:00
if ( ( req . body . keepConnected === "true" ) && ( user . status === "user" ) )
2020-08-07 12:23:59 +02:00
loginTime = config . tokenConnexionMaxTimeInDays ;
2020-10-22 17:47:05 +02:00
// Si l'utilisateur a répondu à un quiz (ou groupe de quizs) avant de se connecter, on enregistre son résultat.
// Uniquement pour les utilisateurs de base.
2020-08-07 12:23:59 +02:00
req . body . UserId = user . id ;
2020-10-22 17:47:05 +02:00
if ( req . body . QuestionnaireId && user . status === "user" )
await answerCtrl . saveAnswerToQuestionnaire ( req . body ) ;
else if ( req . body . GroupId && user . status === "user" )
await answerCtrl . saveAnswerToGroup ( req . body ) ;
2020-08-07 12:23:59 +02:00
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" ) ;
2020-10-22 17:47:05 +02:00
const userDatas = await checkTokenUser ( req . body . t ) ;
if ( userDatas . User . status !== "user" )
2020-08-07 12:23:59 +02:00
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 ;
2020-10-22 17:47:05 +02:00
// Si l'utilisateur a répondu à un quiz (ou groupe de quizs) avant de se connecter, on enregistre son résultat :
req . body . UserId = userDatas . User . id ;
2020-08-07 12:23:59 +02:00
if ( req . body . QuestionnaireId )
2020-10-22 17:47:05 +02:00
await answerCtrl . saveAnswerToQuestionnaire ( req . body ) ;
else if ( req . body . GroupId )
await answerCtrl . saveAnswerToGroup ( req . body ) ;
2020-08-07 12:23:59 +02:00
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 ( [
2020-10-21 17:41:16 +02:00
db [ "User" ] . update ( { ... req . body } , { where : { id : req . connectedUser . User . id } , fields : [ "name" , "language" , "timeDifference" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . connectedUser . User . id } , fields : [ "receiptDays" ] , limit : 1 } )
2020-08-07 12:23:59 +02:00
] ) ;
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 ) ;
2020-09-10 11:26:08 +02:00
if ( req . body . newGodfatherId != undefined )
{
const godFather = searchIdGodfather ( req . body . newGodfatherId ) ;
if ( empty ( godFather ) )
messageRetour . push ( txt . updatedNeedGoodGodfather ) ;
else
req . body . GodfatherId = godFather . id ;
}
2020-08-07 12:23:59 +02:00
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 ( [
2020-10-21 17:41:16 +02:00
db [ "User" ] . update ( { ... req . body } , { where : { id : req . params . id } , fields : [ "name" , "email" , "password" , "language" , "adminComments" , "smtp" , "GodfatherId" ] , limit : 1 } ) ,
db [ "Subscription" ] . update ( { ... req . body } , { where : { UserId : req . params . id } , fields : [ "numberOfDays" , "receiptDays" ] , limit : 1 } )
2020-08-07 12:23:59 +02:00
] ) ;
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" :
2020-10-21 17:41:16 +02:00
user = await db [ "User" ] . create ( { ... req . body } , { fields : [ "name" , "email" , "password" , "language" , "adminComments" , "smtp" , "GodfatherId" ] } ) ;
2020-08-07 12:23:59 +02:00
req . body . UserId = user . id ;
2020-10-21 17:41:16 +02:00
await db [ "Subscription" ] . create ( { ... req . body } , { fields : [ "numberOfDays" , "receiptDays" , "UserId" ] } ) ;
2020-08-07 12:23:59 +02:00
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
2020-09-22 17:54:23 +02:00
// Supprime les fichiers stockant les erreurs de connexion ayant expirés
2020-08-07 12:23:59 +02:00
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 ) ;
}
}
2020-09-22 17:54:23 +02:00
// Suppression des fichiers pour des utilisateurs n'existant plus
2020-08-07 12:23:59 +02:00
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 )
2020-09-22 17:54:23 +02:00
{
2020-08-07 12:23:59 +02:00
saveFiles . push ( users [ i ] . id + ".json" ) ;
2020-09-22 17:54:23 +02:00
saveFiles . push ( "stats" + users [ i ] . id + ".json" ) ;
}
2020-08-07 12:23:59 +02:00
const deleteFiles = await Promise . all ( [
2020-09-22 17:54:23 +02:00
toolFile . deleteFilesInDirectory ( configUsers . dirCacheUsers , saveFiles ) ,
toolFile . deleteFilesInDirectory ( configUsers . dirCacheUsersWithoutAnswers , saveFiles ) ,
toolFile . deleteFilesInDirectory ( configUsers . dirCacheUsersAnswers , saveFiles )
2020-08-07 12:23:59 +02:00
] ) ;
res . status ( 200 ) . json ( deleteFiles ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
2020-09-22 17:54:23 +02:00
// Suppression des comptes n'ayant pas été validé passé un certain délai
2020-08-07 12:23:59 +02:00
exports . deleteUnvalided = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const nowTS = Date . now ( ) ;
2020-11-30 16:41:18 +01:00
const timeExpiration = ( nowTS - parseInt ( config . tokenSignupValidationTimeInHours , 10 ) * 3600 * 1000 ) / 1000 ;
2020-08-07 12:23:59 +02:00
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 )
{
2020-11-30 16:41:18 +01:00
2020-08-07 12:23:59 +02:00
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 ( ) ;
2020-09-22 17:54:23 +02:00
for ( let i in userUnvalided )
2020-08-07 12:23:59 +02:00
await db [ "UserDeleted" ] . create ( { createdAt : userUnvalided [ i ] . createdAt , deletedAt : now , wasValided : false } ) ;
2020-11-30 16:41:18 +01:00
console . log ( metadata . affectedRows + txt . cronDeleteUnvalidedUsersMessage ) ;
2020-08-07 12:23:59 +02:00
}
res . status ( 200 ) . json ( true ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
2020-09-22 17:54:23 +02:00
// Suppression des comptes dont l'abonnement a expiré et ne s'étant pas connecté depuis à certains temps
2020-08-07 12:23:59 +02:00
exports . deleteInactiveAccounts = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
2020-09-22 17:54:23 +02:00
const usersInactive = await db . sequelize . query ( "SELECT createdAt FROM `Users` WHERE status='user' AND (ADDDATE(`connectedAt`, " + config . inactiveAccountTimeToDeleteInDays + ") < NOW() OR `connectedAt` IS NULL) AND `id` IN (SELECT `UserId` FROM `Subscriptions` WHERE ADDDATE(`createdAt`, `numberOfDays`)< NOW())" , { type : QueryTypes . SELECT } ) ;
2020-08-07 12:23:59 +02:00
if ( usersInactive . length !== 0 )
{
2020-09-22 17:54:23 +02:00
const [ results , metadata ] = await db . sequelize . query ( "DELETE FROM `Users` WHERE (ADDDATE(`connectedAt`, " + config . inactiveAccountTimeToDeleteInDays + ") < NOW() OR `connectedAt` IS NULL) AND status='user' AND `id` IN (SELECT `UserId` FROM `Subscriptions` WHERE ADDDATE(`createdAt`, `numberOfDays`)< NOW())" ) ;
2020-08-07 12:23:59 +02:00
if ( metadata . affectedRows !== 0 )
res . message = metadata . affectedRows + txt . deleteInactiveUsersMessage ;
const now = new Date ( ) ;
2020-09-22 17:54:23 +02:00
for ( let i in usersInactive )
2020-08-07 12:23:59 +02:00
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 ;
}
2020-10-21 17:41:16 +02:00
exports . getStatsUsers = getStatsUsers ;