2020-08-07 12:23:59 +02:00
const { Op , QueryTypes } = require ( "sequelize" ) ;
const pug = require ( "pug" ) ;
const striptags = require ( "striptags" ) ;
const config = require ( "../config/main.js" ) ;
const configQuestionnaires = require ( "../config/questionnaires.js" ) ;
const configTags = require ( "../config/tags.js" ) ;
const configLinks = require ( "../config/links.js" ) ;
const configIllustrations = require ( "../config/illustrations.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 questionCtrl = require ( "./question" ) ;
const illustrationCtrl = require ( "./illustration" ) ;
const tagCtrl = require ( "./tag" ) ;
const userCtrl = require ( "./user" ) ;
const txtGeneral = require ( "../lang/" + config . adminLang + "/general" ) ;
const txtQuestionnaire = require ( "../lang/" + config . adminLang + "/questionnaire" ) ;
const txtQuestionnaireAccess = require ( "../lang/" + config . adminLang + "/questionnaireaccess" ) ;
const txtIllustration = require ( "../lang/" + config . adminLang + "/illustration" ) ;
exports . create = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
req . body . CreatorId = req . connectedUser . User . id ;
const questionnaire = await db [ "Questionnaire" ] . create ( { ... req . body } , { fields : [ "title" , "slug" , "introduction" , "keywords" , "publishingAt" , "language" , "estimatedTime" , "CreatorId" ] } ) ;
creaStatsQuestionnairesJson ( ) ;
//utile au middleware suivant (classement tags) qui s'occupe aussi de retourner une réponse si ok :
req . body . QuestionnaireId = questionnaire . id ;
next ( ) ;
}
catch ( e )
{
const returnAPI = toolError . returnSequelize ( e ) ;
if ( returnAPI . messages )
{
res . status ( returnAPI . status ) . json ( { errors : returnAPI . messages } ) ;
next ( ) ;
}
else
next ( e ) ;
}
}
exports . modify = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
const questionnaire = await searchQuestionnaireById ( req . params . id ) ;
if ( ! questionnaire )
{
const Err = new Error ;
error . status = 404 ;
error . message = txtQuestionnaire . notFound + " (" + req . params . id + ")" ;
throw Err ;
}
else if ( req . connectedUser . User . status === "creator" && req . connectedUser . User . id !== questionnaire . CreatorId )
res . status ( 401 ) . json ( { errors : txtGeneral . notAllowed } ) ;
else
{
await db [ "Questionnaire" ] . update ( { ... req . body } , { where : { id : req . params . id } , fields : [ "title" , "slug" , "introduction" , "keywords" , "publishingAt" , "language" , "estimatedTime" ] , limit : 1 } ) ; // voir si admin aura le droit de changer le créateur ? et ajouter une gestion des redirection si slug change ?
creaStatsQuestionnairesJson ( ) ; // le nombre de quizs publiés peut avoir changé
}
//utile au middleware suivant (classement tags) qui s'occupe aussi de retourner une réponse si ok :
req . body . QuestionnaireId = req . params . id ;
next ( ) ;
}
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 questionnaire = await searchQuestionnaireById ( req . params . id ) ;
if ( ! questionnaire )
{
const Err = new Error ;
error . status = 404 ;
error . message = txtQuestionnaire . notFound + " (" + req . params . id + ")" ;
throw Err ;
}
else if ( req . connectedUser . User . status === "creator" && req . connectedUser . User . id !== questionnaire . CreatorId )
res . status ( 401 ) . json ( { errors : txtGeneral . notAllowed } ) ;
else
{
// Permet de supprimer les fichiers associés en plus du sql. Inutile pour link qui n'a pas de fichier.
// À faire avant la suppression SQL du questionnaire entraînant la suppression en cascade du reste.
for ( i in questionnaire . Questions )
await questionCtrl . deleteQuestionById ( questionnaire . Questions [ i ] . id ) ;
for ( i in questionnaire . Illustrations )
await illustrationCtrl . deleteIllustrationById ( questionnaire . Illustrations [ i ] . id ) ;
const nb = await db [ "Questionnaire" ] . destroy ( { where : { id : req . params . id } , limit : 1 } ) ;
if ( nb === 1 )
{
await toolFile . deleteJSON ( config . dirCacheQuestionnaires , req . params . id ) ;
res . status ( 200 ) . json ( { message : txtGeneral . deleteOkMessage } ) ;
// actualisation de liste des questionnaires pour les tags concernés.
// Ici au contraire, les enregistrements doivent être supprimés avant.
for ( let i in questionnaire . Tags )
tagCtrl . creaQuestionnairesTagJson ( questionnaire . Tags [ i ] . TagId ) ;
// La suppression peut éventuellement concerner un des derniers questionnaires, donc :
creaNewQuestionnairesJson ( ) ;
creaStatsQuestionnairesJson ( ) ;
// Éventuellement regénérer les caches listant les réponses/quizs des users ayant accès à ce questionnaire ?
// ++ HTML
}
else
{
const Err = new Error ;
error . status = 404 ;
error . message = txtQuestionnaire . notFound + " (" + req . params . id + ")" ;
throw Err ;
}
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . getOneQuestionnaireById = async ( req , res , next ) =>
{
try
{
const datas = await searchQuestionnaireById ( req . params . id , true ) ;
if ( datas )
res . status ( 200 ) . json ( datas ) ;
else
res . status ( 404 ) . json ( { errors : txtQuestionnaire . notFound } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
exports . showOneQuestionnaireById = async ( req , res , next ) =>
{
try
{
// Seuls certains utilisateurs peuvent avoir accès à cette page
const connectedUser = await userCtrl . checkTokenUser ( req . params . token ) ;
if ( connectedUser === false )
res . status ( 403 ) . json ( { errors : txtGeneral . failAuthToken } ) ;
else
{
if ( [ "admin" , "manager" , "creator" ] . indexOf ( connectedUser . User . status ) === - 1 )
res . status ( 403 ) . json ( { errors : txtGeneral . notAllowed } ) ;
else
{
const HTML = await creaQuestionnaireHTML ( req . params . id , true ) ;
if ( HTML )
{
res . setHeader ( "Content-Type" , "text/html" ) ;
res . send ( HTML ) ;
}
else
res . status ( 404 ) . json ( { errors : txtQuestionnaire . notFound } ) ;
}
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Recherche par mots-clés parmis tous les questionnaires publiés en filtrant parmi ceux auxquels l'abonné a déjà répondu ou pas
// Seul un certain nombre de résultats est renvoyé (pagination)
exports . searchQuestionnaires = async ( req , res , next ) =>
{
try
{
let search = tool . trimIfNotNull ( req . body . searchQuestionnaires ) ;
if ( search === null || search === "" || search . length < config . minSearchQuestionnaires )
res . status ( 400 ) . json ( txtQuestionnaireAccess . searchIsNotLongEnough ) ;
else
{
const db = require ( "../models/index" ) ;
let getQuestionnaires ;
if ( ! tool . isEmpty ( req . body . onlyAnswers ) && ! tool . isEmpty ( req . connectedUser . User . id ) )
2020-09-09 16:02:35 +02:00
getQuestionnaires = await db . sequelize . query ( "SELECT DISTINCT `Questionnaires`.`id` FROM `Questionnaires` INNER JOIN `Answers` WHERE `Answers`.`QuestionnaireId`=`Questionnaires`.`id` AND `Answers`.`UserId`=:id AND (`title` LIKE :search OR `keywords` LIKE :search) AND `isPublished` = 1" , { replacements : { id : req . connectedUser . User . id , search : "%" + search + "%" } , type : QueryTypes . SELECT } ) ;
2020-08-07 12:23:59 +02:00
else
2020-09-09 16:02:35 +02:00
getQuestionnaires = await db . sequelize . query ( "SELECT `id` FROM `Questionnaires` WHERE (`title` LIKE :search OR `keywords` LIKE :search) AND `isPublished` = 1" , { replacements : { search : "%" + search + "%" } , type : QueryTypes . SELECT } ) ;
2020-08-07 12:23:59 +02:00
let begin = 0 , end , output = "" ;
if ( ! tool . isEmpty ( req . body . begin ) )
begin = parseInt ( req . body . begin , 10 ) ;
end = begin + configTpl . nbQuestionnairesUserHomePage - 1 ; // tableau commence à 0 !
if ( req . body . output !== undefined )
output = req . body . output ;
datas = await getListingsQuestionnairesOuput ( getQuestionnaires , begin , end , output ) ;
res . status ( 200 ) . json ( datas ) ;
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Recherche aléatoire parmi tous les questionnaires publiés
// De nouveau on peut filtrer ou non ceux auxquels l'utilisateur a répondu
// Par contre, ici pas de pagination car on maîtrise le nombre de résultats envoyés
exports . getRandomQuestionnaires = async ( req , res , next ) =>
{
try
{
const db = require ( "../models/index" ) ;
let getQuestionnaires ;
if ( ! tool . isEmpty ( req . body . onlyAnswers ) && ! tool . isEmpty ( req . connectedUser . User . id ) )
getQuestionnaires = await db . sequelize . query ( "SELECT DISTINCT `Questionnaires`.`id` FROM `Questionnaires` INNER JOIN `Answers` WHERE `Answers`.`QuestionnaireId`=`Questionnaires`.`id` AND `Answers`.`UserId`=:id AND `isPublished` = 1 ORDER BY RAND() LIMIT " + configQuestionnaires . nbRandomResults , { replacements : { id : req . connectedUser . User . id } , type : QueryTypes . SELECT } ) ;
else
getQuestionnaires = await db . sequelize . query ( "SELECT `id` FROM `Questionnaires` WHERE `isPublished` = 1 ORDER BY RAND() LIMIT " + configQuestionnaires . nbRandomResults , { type : QueryTypes . SELECT } ) ;
let begin = 0 , end ;
end = begin + configTpl . nbQuestionnairesUserHomePage - 1 ;
datas = await getListingsQuestionnairesOuput ( getQuestionnaires , begin , end , "html" ) ;
res . status ( 200 ) . json ( datas ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Recherche par mots-clés parmis tous les questionnaires, y compris ceux non publiés
exports . searchAdminQuestionnaires = async ( req , res , next ) =>
{
try
{
let search = tool . trimIfNotNull ( req . body . searchQuestionnaires ) ;
if ( search === null || search === "" || search . length < config . minSearchQuestionnaires )
res . status ( 400 ) . json ( txtQuestionnaireAccess . searchIsNotLongEnough ) ;
else
{
const db = require ( "../models/index" ) ;
const getQuestionnaires = await db . sequelize . query ( "SELECT `id`,`title` FROM `Questionnaires` WHERE (`title` LIKE :search OR `introduction` LIKE :search OR `keywords` LIKE :search) ORDER BY `title` ASC" , { replacements : { search : "%" + search + "%" } , type : QueryTypes . SELECT } ) ;
res . status ( 200 ) . json ( getQuestionnaires ) ;
}
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Retourne les statistiques concernant les questionnaires
exports . getStats = async ( req , res , next ) =>
{
try
{
const stats = await getStatsQuestionnaires ( ) ;
res . status ( 200 ) . json ( stats ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// Liste des prochains questionnaires devant être publiés.
// On vérifie à chaque fois si ils ont ce qu'il faut pour être publiables
// On en profite pour chercher la prochaine date sans questionnaire programmé
exports . getListNextQuestionnaires = async ( req , res , next ) =>
{
try
{
let questionnaires = await getNextQuestionnaires ( ) ;
2020-08-30 18:23:21 +02:00
const dayWithoutPublication = [ 0 , 6 ] ; // à déclarer dans config + gérer cas où aucun jour n'est obligatoire
let dateNeeded = "" , questionnairesDatas , dateQuestionnaireTS , previousDayNeededTS , previousDayTS ;
2020-08-07 12:23:59 +02:00
for ( let i in questionnaires )
{
questionnairesDatas = await searchQuestionnaireById ( questionnaires [ i ] . id ) ;
questionnaires [ i ] . isPublishable = checkQuestionnaireIsPublishable ( questionnairesDatas , false ) ; // le questionnaire est-il complet ?
2020-08-30 18:23:21 +02:00
dateQuestionnaireTS = new Date ( questionnaires [ i ] . datePublishing ) . getTime ( ) ;
if ( dateNeeded === "" )
2020-08-07 12:23:59 +02:00
{
2020-08-30 18:23:21 +02:00
// je commence par chercher le jour précédent pour lequel je dois avoir publié quelque chose :
previousDayTS = new Date ( new Date ( dateQuestionnaireTS - 3600 * 1000 * 24 ) ) ;
previousDayNeededTS = 0 ;
while ( previousDayNeededTS === 0 )
{
if ( dayWithoutPublication . indexOf ( previousDayTS . getDay ( ) ) === - 1 )
previousDayNeededTS = previousDayTS ;
else
previousDayTS = new Date ( previousDayTS . getTime ( ) - 3600 * 1000 * 24 ) ;
}
// si il n'y a pas de quiz précédent, cette date est celle que je cherche
if ( ! questionnaires [ i - 1 ] )
{
if ( previousDayNeededTS >= Date . now ( ) )
dateNeeded = previousDayNeededTS ;
}
2020-08-07 12:23:59 +02:00
else
2020-08-30 18:23:21 +02:00
{ // sinon je compare la date du précédent quiz à celle pour laquelle j'ai besoin d'un quiz
if ( new Date ( questionnaires [ i - 1 ] . datePublishing ) . getTime ( ) < previousDayNeededTS )
dateNeeded = previousDayNeededTS ;
}
2020-08-07 12:23:59 +02:00
}
}
if ( questionnaires . length > 0 && dateNeeded === "" )
2020-08-30 18:23:21 +02:00
dateNeeded = new Date ( dateQuestionnaireTS + 3600 * 1000 * 24 ) ; // le jour suivant celui du dernier questionnaire
2020-08-07 12:23:59 +02:00
else
2020-08-30 18:23:21 +02:00
dateNeeded = new Date ( Date . now ( ) + 3600 * 1000 * 24 ) ; // mais il est possible que rien n'ai été publié ce jour, le quiz du jour étant absent de la liste traitée
2020-08-07 12:23:59 +02:00
res . status ( 200 ) . json ( { questionnaires : questionnaires , dateNeeded : dateNeeded } ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// test si des questionnaires doivent être publiés
// puis (re)génère tous les fichiers HTML des questionnaires + les pages accueil + news
// la requête est ensuite passé aux tags qui font la même chose
exports . HTMLRegenerate = async ( req , res , next ) =>
{
try
{
await checkQuestionnairesNeedToBePublished ( ) ;
const nb = await checkQuestionnairesPublishedHaveHTML ( true ) ;
creaNewQuestionnairesJson ( ) ; // provoque mise à jour du HTLM, RSS, etc.
res . messageToNext = txtQuestionnaire . haveBeenRegenerated . replace ( "#NB1" , nb ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// CRONS
exports . deleteJsonFiles = async ( req , res , next ) =>
{
// ajouter le suppression des fichiers HTML ? -> plutôt le faire manuellement lors de la suppression du questionnaire
try
{
const db = require ( "../models/index" ) ;
const questionnaires = await db [ "Questionnaire" ] . findAll ( { attributes : [ "id" ] } ) ;
let saveFiles = [ ] ;
for ( let i in questionnaires )
saveFiles . push ( questionnaires [ i ] . id + ".json" ) ;
const deleteFiles = await toolFile . deleteFilesInDirectory ( config . dirCacheQuestionnaires , saveFiles ) ;
res . status ( 200 ) . json ( deleteFiles ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// test si des questionnaires doivent être publiés
// + si des questionnaires publiés n'ont pas fichier html
// si fichier html créé il faut aussi actualiser la page d'accueil & co
exports . checkQuestionnairesNeedToBePublished = async ( req , res , next ) =>
{
try
{
await checkQuestionnairesNeedToBePublished ( ) ;
const nb = await checkQuestionnairesPublishedHaveHTML ( ) ;
if ( nb > 0 )
creaNewQuestionnairesJson ( ) ; // provoque mise à jour du HTLM, RSS, etc.
res . status ( 200 ) . json ( txtQuestionnaire . haveBeenPublished . replace ( ":NB" , nb ) ) ;
next ( ) ;
}
catch ( e )
{
next ( e ) ;
}
}
// FONCTIONS UTILITAIRES
const creaQuestionnaireJson = async ( id ) =>
{
const db = require ( "../models/index" ) ;
const Questionnaire = await db [ "Questionnaire" ] . findByPk ( id ) ;
if ( Questionnaire )
{
let datas = { Questionnaire } ;
const Tags = await db [ "QuestionnaireClassification" ] . findAll ( { where : { QuestionnaireId : Questionnaire . id } , attributes : [ "TagId" ] } ) ;
if ( Tags )
datas . Tags = Tags ;
const Illustrations = await db [ "Illustration" ] . findAll ( { where : { QuestionnaireId : Questionnaire . id } } ) ;
if ( Illustrations )
datas . Illustrations = Illustrations ;
const Links = await db [ "Link" ] . findAll ( { where : { QuestionnaireId : Questionnaire . id } } ) ;
if ( Links )
datas . Links = Links ;
const Questions = await db [ "Question" ] . findAll ( { where : { QuestionnaireId : Questionnaire . id } , order : [ [ "rank" , "ASC" ] , [ "createdAt" , "ASC" ] ] , attributes : [ "id" ] } ) ;
if ( Questions )
datas . Questions = Questions ;
const wasPublished = datas . Questionnaire . isPublished ;
datas . Questionnaire . isPublished = checkQuestionnaireIsPublishable ( datas ) ;
// important d'écrire le fichier ici, car il est nécessaire aux autres fonctions appelées ci-dessous
await toolFile . createJSON ( config . dirCacheQuestionnaires , id , datas ) ;
if ( datas . Questionnaire . isPublished !== wasPublished )
{
await db [ "Questionnaire" ] . update ( { isPublished : datas . Questionnaire . isPublished } , { where : { id : id } , fields : [ "isPublished" ] , limit : 1 } ) ;
// + liste des tags utilisés :
tagCtrl . creaUsedTagsJson ( ) ;
// si le quiz était publié jusqu'ici, il me faut supprimer son fichier HTML (revenir pour réactiver)
2020-08-08 17:17:02 +02:00
if ( wasPublished )
toolFile . deleteFile ( config . dirHTMLQuestionnaire , Questionnaire . slug + ".html" ) ;
2020-08-07 12:23:59 +02:00
}
// peut impacter la liste des derniers si des informations affichées ont changé
creaNewQuestionnairesJson ( ) ; // peut avoir été impacté
// + les listes de quizs / tags :
for ( let i in Tags )
tagCtrl . creaQuestionnairesTagJson ( Tags [ i ] . TagId ) // ! Json + HTML, donc potentiellement long.
if ( datas . Questionnaire . isPublished )
await creaQuestionnaireHTML ( id ) ;
return datas ;
}
else
return false ;
}
exports . creaQuestionnaireJson = creaQuestionnaireJson ;
const checkQuestionnaireIsPublishable = ( datas , checkDate = true ) =>
{
if ( checkDate )
{
if ( datas . Questionnaire . publishingAt === null )
return false ;
else
{
const today = new Date ( ) ;
today . setHours ( 0 , 0 , 0 , 0 ) ; // !! attention au décalage horaire du fait de l'enregistrement en UTC dans mysql
const publishingAt = new Date ( datas . Questionnaire . publishingAt ) ;
if ( publishingAt . getTime ( ) > today . getTime ( ) )
return false ;
}
}
if ( datas . Questions == undefined || datas . Questions . length < config . nbQuestionsMin ) // le nombre de réponses mini étant contrôlé au moment de l'enregistrement de la question
return false ;
if ( datas . Tags == undefined || datas . Tags . length < configTags . nbTagsMin )
return false ;
if ( datas . Links == undefined || datas . Links . length < configLinks . nbLinksMin )
return false ;
if ( datas . Illustrations == undefined || datas . Illustrations . length < configIllustrations . nbIllustrationsMin )
return false ;
return true ;
}
const creaQuestionnaireHTML = async ( id , preview = false ) =>
{
// besoin de toutes les infos concernant le questionnaire pour les transmettre à la vue
// à terme : séparer la création de la partie body pouvant être retournée pour recharger page, de la génération complète pour créer le fichier html
const questionnaire = await searchQuestionnaireById ( id , true ) ;
if ( ! questionnaire )
return false ;
if ( questionnaire . Questionnaire . isPublished === false && preview === false )
return false ;
const compiledFunction = pug . compileFile ( "./views/" + config . theme + "/quiz.pug" ) ;
const configTpl = require ( "../views/" + config . theme + "/config/" + config . availableLangs [ 0 ] + ".js" ) ;
const pageDatas =
{
config : config ,
configTpl : configTpl ,
tool : tool ,
txtGeneral : txtGeneral ,
txtQuestionnaire : txtQuestionnaire ,
txtIllustration : txtIllustration ,
pageLang : questionnaire . Questionnaire . language ,
metaDescription : tool . shortenIfLongerThan ( config . siteName + " : " + striptags ( questionnaire . Questionnaire . introduction . replace ( "<br>" , " " ) . replace ( "</p>" , " " ) ) , 200 ) ,
author : questionnaire . Questionnaire . CreatorName ,
pageTitle : questionnaire . Questionnaire . title + " (" + txtQuestionnaire . questionnairesName + ")" ,
contentTitle : questionnaire . Questionnaire . title ,
questionnaire : questionnaire ,
2020-08-18 12:14:20 +02:00
linkCanonical : config . siteUrl + "/" + config . dirWebQuestionnaire + "/" + questionnaire . Questionnaire . slug + ".html"
}
2020-08-07 12:23:59 +02:00
const html = await compiledFunction ( pageDatas ) ;
if ( preview === false )
{
await toolFile . createHTML ( config . dirHTMLQuestionnaire , questionnaire . Questionnaire . slug , html ) ;
return true ;
}
else
return html ;
}
const searchQuestionnaireById = async ( id , reassemble = false ) =>
{
let questionnaire = await toolFile . readJSON ( config . dirCacheQuestionnaires , id ) ;
if ( ! questionnaire )
questionnaire = await creaQuestionnaireJson ( id ) ;
if ( ! questionnaire )
return false ;
if ( reassemble )
{
let question ; Questions = [ ] ;
const author = await userCtrl . searchUserById ( questionnaire . Questionnaire . CreatorId ) ;
if ( author )
questionnaire . Questionnaire . CreatorName = author . User . name ;
for ( i in questionnaire . Questions )
{
question = await questionCtrl . searchQuestionById ( questionnaire . Questions [ i ] . id ) ;
if ( question )
Questions . push ( question ) ;
}
questionnaire . Questions = Questions ;
const tags = await tagCtrl . getTagsQuestionnaire ( id ) ;
if ( tags )
questionnaire . Tags = tags ;
}
return questionnaire ;
}
exports . searchQuestionnaireById = searchQuestionnaireById ;
// Cherche si il y a des questionnaires dont la date de publication est passée mais qui ne sont pas notés comme publiés
// Vérifie si ils sont publiables et si oui change leur statut et réactualise le cache json
const checkQuestionnairesNeedToBePublished = async ( ) =>
{
const db = require ( "../models/index" ) ;
const questionnaires = await db . sequelize . query ( "SELECT `id` FROM `Questionnaires` WHERE `publishingAt` < NOW() AND `isPublished` = false" , { type : QueryTypes . SELECT } ) ;
let questionnaireDatas ;
for ( let i in questionnaires )
{
questionnaireDatas = await searchQuestionnaireById ( questionnaires [ i ] . id , true ) ;
if ( checkQuestionnaireIsPublishable ( questionnaireDatas ) )
{
await db [ "Questionnaire" ] . update ( { isPublished : true } , { where : { id : questionnaires [ i ] . id } , fields : [ "isPublished" ] , limit : 1 } ) ;
creaQuestionnaireJson ( questionnaires [ i ] . id ) ; // provoque normalement la création du HTML
}
}
}
// Contrôle si tous les fichiers devant être publiés ont bien leur fichier HTML, sinon le génère
// Si regenerate true, tous les fichiers sont générés, même si ils existent déjà (évolution template...)
// Retourne le nombre de fichiers ayant été régénérés
const checkQuestionnairesPublishedHaveHTML = async ( regenerate = false ) =>
{
const db = require ( "../models/index" ) ;
const questionnaires = await db . sequelize . query ( "SELECT `id`,`slug` FROM `Questionnaires` WHERE `isPublished` = true" , { type : QueryTypes . SELECT } ) ;
let nb = 0 ;
for ( let i in questionnaires )
{
if ( regenerate )
{
await creaQuestionnaireHTML ( questionnaires [ i ] . id ) ;
nb ++ ;
}
else if ( await toolFile . checkIfFileExist ( config . dirHTMLQuestionnaire , questionnaires [ i ] . slug + ".html" ) === false )
{
await creaQuestionnaireHTML ( questionnaires [ i ] . id ) ;
nb ++ ;
}
}
return nb ;
}
// Liste des derniers questionnaires publiés (utile pour page d'accueil, flux rss, etc.)
const creaNewQuestionnairesJson = async ( ) =>
{
const db = require ( "../models/index" ) ;
2020-09-07 18:38:13 +02:00
const Questionnaires = await db [ "Questionnaire" ] . findAll ( { where : { isPublished : true } , order : [ [ config . fieldNewQuestionnaires , "DESC" ] , [ "id" , "DESC" ] ] , attributes : [ "id" ] , limit : config . nbNewQuestionnaires } ) ;
2020-08-07 12:23:59 +02:00
if ( Questionnaires )
{
await toolFile . createJSON ( config . dirCacheQuestionnaires , "last" , Questionnaires ) ;
creaNewQuestionnairesHTML ( Questionnaires ) ;
return Questionnaires ;
}
else
return false ;
}
exports . creaNewQuestionnairesJson = creaNewQuestionnairesJson ;
// Se limite à compter le nombre total de questionnaires et à le stocker pour éviter de lancer une requête sql à chaque fois
const creaStatsQuestionnairesJson = async ( ) =>
{
const db = require ( "../models/index" ) ;
const Questionnaires = await db [ "Questionnaire" ] . findAll ( { attributes : [ "id" ] } ) ;
const QuestionnairesPublished = await db [ "Questionnaire" ] . findAll ( { where : { isPublished : true } , attributes : [ "id" ] } ) ;
if ( Questionnaires && QuestionnairesPublished )
{
const stats =
{
nbTot : Questionnaires . length ,
nbPublished : QuestionnairesPublished . length
}
await toolFile . createJSON ( config . dirCacheQuestionnaires , "stats" , stats ) ;
return stats ;
}
else
return false ;
}
exports . creaStatsQuestionnairesJson = creaStatsQuestionnairesJson ;
// Retourne les données créées par la fonction précédente
const getStatsQuestionnaires = async ( ) =>
{
let stats = await toolFile . readJSON ( config . dirCacheQuestionnaires , "stats" ) ;
if ( ! stats )
stats = await creaStatsQuestionnairesJson ( ) ;
if ( ! stats )
return false ;
else
return stats ;
}
exports . getStatsQuestionnaires = getStatsQuestionnaires ;
// Quelle est la prochaine date pour laquelle aucun questionnaire n'a été publié ?
const getDateNewQuestionnaireNeeded = async ( maxDays ) =>
{
const db = require ( "../models/index" ) ;
let dateNeed = "" , checkDate , addMin = 0 , addMax = 1 ;
while ( dateNeed === "" )
{
checkDate = await db . sequelize . query ( "SELECT ADDDATE(CURDATE(), :addMin) as `dateNeeded` FROM `Questionnaires` WHERE `isPublished`=1 AND `publishingAt` > ADDDATE(CURDATE(), :addMin) AND `publishingAt`< ADDDATE(CURDATE(), :addMax) ORDER BY `publishingAt` LIMIT 1" , { replacements : { addMin : addMin , addMax : addMax } , type : QueryTypes . SELECT } ) ;
if ( checkDate && getSubscriptions24H . length > 0 )
dateNeed = checkDate . dateNeeded ;
else
{
addMin ++ ;
addMax ++ ;
}
if ( addMin > maxDays )
return false ;
}
return dateNeed ;
}
exports . getDateNewQuestionnaireNeeded = getDateNewQuestionnaireNeeded ;
// Les prochains questionnaires devant être publiés (permet aux gestionnaires de voir les dates vides)
const getNextQuestionnaires = async ( ) =>
{
const db = require ( "../models/index" ) ;
const questionnaires = await db . sequelize . query ( "SELECT `id`,`title`, `publishingAt` as `datePublishing` FROM `Questionnaires` WHERE `publishingAt` > NOW() order by `publishingAt`" , { type : QueryTypes . SELECT } ) ;
return questionnaires ;
}
exports . getNextQuestionnaires = getNextQuestionnaires ;
const creaNewQuestionnairesHTML = async ( Questionnaires ) =>
{
// On regénère la page d'accueil avec le(s) dernier(s) questionnaire(s) mis en avant :
let compiledFunction = pug . compileFile ( "./views/" + config . theme + "/home.pug" ) ;
const configTpl = require ( "../views/" + config . theme + "/config/" + config . availableLangs [ 0 ] + ".js" ) ;
let questionnaires = [ ] ;
for ( let i in Questionnaires )
questionnaires . push ( await searchQuestionnaireById ( Questionnaires [ i ] . id ) ) ;
let pageDatas =
{
config : config ,
configTpl : configTpl ,
tool : tool ,
striptags : striptags ,
txtGeneral : txtGeneral ,
txtQuestionnaire : txtQuestionnaire ,
txtIllustration : txtIllustration ,
pageLang : config . adminLang ,
metaDescription : txtGeneral . siteMetaDescription ,
pageTitle : txtGeneral . siteHTMLTitle ,
contentTitle : config . siteName ,
questionnaires : questionnaires ,
linkCanonical : config . siteUrl
}
let html = await compiledFunction ( pageDatas ) ;
await toolFile . createHTML ( config . dirHTML , "index" , html ) ;
// + la page listant les X derniers quizs + liste des tags
compiledFunction = pug . compileFile ( "./views/" + config . theme + "/newQuestionnaires.pug" ) ;
pageDatas . metaDescription = configTpl . newQuestionnairesIntro ;
pageDatas . pageTitle = configTpl . newQuestionnairesTitle ;
pageDatas . linkCanonical = config . siteUrl + "/" + configQuestionnaires . dirWebTags ;
pageDatas . tags = await tagCtrl . getUsedTags ( ) ;
html = await compiledFunction ( pageDatas ) ;
await toolFile . createHTML ( configQuestionnaires . dirHTMLTags , "index" , html ) ;
return true ;
}
// À partir d'une liste d'id questionnaires fournis, retourne la liste complète ou partielle (pagination) avec les infos de chaque questionnaire
// Retour en html ou json suivant les cas
const getListingsQuestionnairesOuput = async ( Questionnaires , begin = 0 , end = null , output = "" ) =>
{
const datas = { nbTot : Questionnaires . length , questionnaires : [ ] , html : "" } ;
if ( datas . nbTot !== 0 )
{
if ( end === null )
end = datas . nbTot ;
for ( let i = begin ; i <= end ; i ++ )
{
if ( Questionnaires [ i ] === undefined )
break ;
else
datas . questionnaires . push ( await searchQuestionnaireById ( Questionnaires [ i ] . id ) ) ;
}
// Utiles pour savoir où j'en suis rendu dans le front :
datas . begin = begin ;
datas . end = end ;
if ( output === "html" )
{
const compiledFunction = pug . compileFile ( "./views/" + config . theme + "/includes/listing-questionnaires.pug" ) ;
const pageDatas =
{
tool : tool ,
striptags : striptags ,
txtGeneral : txtGeneral ,
txtIllustration : txtIllustration ,
questionnaires : datas . questionnaires ,
nbQuestionnairesList : configTpl . nbQuestionnairesUserHomePage
}
datas . html = await compiledFunction ( pageDatas ) ;
datas . questionnaires = null ; // allège un peu le contenu retourné...
}
}
return datas ;
}
exports . getListingsQuestionnairesOuput = getListingsQuestionnairesOuput ;