Modification vue dernières publication + création nouvelle vue listant les tags.

This commit is contained in:
Fabrice PENHOËT 2020-10-29 12:57:00 +01:00
parent 8ce66d7981
commit be91d0eb30
8 changed files with 98 additions and 44 deletions

1
.gitignore vendored
View File

@ -20,6 +20,7 @@ nodemon.json
/front/public/JS/*/
/front/public/quiz/
/front/public/quizs/
/front/public/themes/
/front/public/index.html
/front/public/CGV-CGU.html
/front/public/mentions-legales.html

View File

@ -58,11 +58,13 @@ module.exports =
// Emplacement des fichiers HTML générés :
dirHTMLGroups : "front/public/quiz/gp",
dirHTMLQuestionnaires : "front/public/quiz",
dirHTMLTags : "front/public/quizs",
dirHTMLNews : "front/public/quizs",
dirHTMLTags : "front/public/themes",
// Idem mais pour urls :
dirWebGroups : "quiz/gp",
dirWebQuestionnaires : "quiz",
dirWebTags : "quizs/",
dirWebNews : "quizs/",
dirWebTags : "themes/",
// limite des résultat du moteur de recherche, quand demande de résultats au hasard :
nbRandomResults : 3,
/* Valeurs en fait définies dans instance.js donc à supprimer quand plus utilisées ailleurs : */

View File

@ -1,3 +1,4 @@
/*
// fichier à supprimer une fois tous les "require" ok
const questionnaires = require("./questionnaires");
@ -8,4 +9,4 @@ module.exports =
dirWebTags : questionnaires.dirWebTags,
nbTagsMin: questionnaires.nbTagsMin,
nbTagsMax: questionnaires.nbTagsMax
};
};*/

View File

@ -800,7 +800,7 @@ const creaNewQuestionnairesHTML = async (Questionnaires) =>
let questionnaires=[];
for(let i in Questionnaires)
questionnaires.push(await searchQuestionnaireById(Questionnaires[i].id));
let pageDatas=
let pageDatas =
{
config: config,
configTpl: configTpl,
@ -822,10 +822,9 @@ const creaNewQuestionnairesHTML = async (Questionnaires) =>
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();
pageDatas.linkCanonical=config.siteUrl+"/"+configQuestionnaires.dirWebNews;
html=await compiledFunction(pageDatas);
await toolFile.createHTML(configQuestionnaires.dirHTMLTags, "index", html);
await toolFile.createHTML(configQuestionnaires.dirHTMLNews, "index", html);
return true;
}

View File

@ -254,6 +254,7 @@ exports.addNewQuestionnaireUsers = async(req, res, next) =>
// Il y a déjà eu au moins un envoi et le dernier envoi était un des éléments d'un quiz groupé :
if(lastSended.length !==0 && lastSended[0].dateSended == subscriptionsOk[i].lastProcessingAt)
{
console.log(subscriptionsOk[i].email+" a reçu un article hier.")
const lastSendedGroup = await groupCtrl.searchGroupById(lastSended[0].GroupId);
if(!tool.isEmpty(lastSendedGroup))
{
@ -261,6 +262,7 @@ exports.addNewQuestionnaireUsers = async(req, res, next) =>
// Si le dernier élément envoyé était le dernier de son groupe, on envoie le lien du quiz reprenant toutes les questions du groupe :
if(!tool.isEmpty(lastSendedGroupNbElements) && lastSendedGroup.Questionnaires[(lastSendedGroupNbElements-1)].id == lastSended[0].QuestionnaireId)
{
console.log(subscriptionsOk[i].email+" va recevoir le quiz du groupe.")
// Il faut que le quiz soi publié... Sinon on va envoyer un ancien quiz en attendant (cf + bas)
if(lastSendedGroup.Group.isPublishable)
elementToSend = lastSendedGroup.Group;
@ -268,6 +270,7 @@ exports.addNewQuestionnaireUsers = async(req, res, next) =>
// Sinon l'élément suivant du groupe :
else
{
console.log(subscriptionsOk[i].email+" va recevoir le nouvel article du même groupe.")
for(let j in lastSendedGroup.Questionnaires)
if(lastSendedGroup.Questionnaires[j].id == lastSended[0].QuestionnaireId)
elementToSend = await questionnaireCtrl.searchQuestionnaireById(lastSendedGroup.Questionnaires[(parseInt(j)+1)].id);
@ -276,6 +279,7 @@ exports.addNewQuestionnaireUsers = async(req, res, next) =>
}
else
{
console.log(subscriptionsOk[i].email+" devrait recevoir le premier article du groupe suivant, si il existe.")
// Soit il s'agit du premier envoi d'un abonnement, soit le dernier envoi était le quiz d'un groupe.
// Dans ces deux cas, on va envoyer le premier élément non encore envoyé à cet abonné (le groupe peut ne pas être lui-même encore publié) :
const getElementToSend = await db.sequelize.query("SELECT `Questionnaires`.`id` FROM `Questionnaires` INNER JOIN `Groups` ON `Questionnaires`.`GroupId`=`Groups`.`id` WHERE `Questionnaires`.`isPublished`=1 AND `Groups`.`language`='"+subscriptionsOk[i].language+"' AND `Questionnaires`.`id` NOT IN (SELECT `QuestionnaireId` FROM `QuestionnaireAccesses` where `UserId`="+subscriptionsOk[i].UserId+") ORDER BY `Groups`.`publishingAt`,`rankInGroup` ASC", { type: QueryTypes.SELECT });

View File

@ -1,21 +1,21 @@
const { Op, QueryTypes } = require("sequelize");// pour certaines requêtes sql
const pug = require("pug");
var striptags = require("striptags");
const striptags = require("striptags");
const config = require("../config/main.js");
const configTags = require("../config/tags.js");
const configQuestionnaire = require("../config/questionnaires.js");
const ctrlQuestionnaire = require("./questionnaire");
const tool = require("../tools/main");
const toolError = require("../tools/error");
const toolFile = require("../tools/file");
const questionnaireCtrl = require("./questionnaire");
const txt = require("../lang/"+config.adminLang+"/tag");
const txtGeneral = require("../lang/"+config.adminLang+"/general");
const txtQuestionnaire = require("../lang/"+config.adminLang+"/questionnaire");
const txtIllustration = require("../lang/"+config.adminLang+"/illustration");
const txtQuestionnaire = require("../lang/"+config.adminLang+"/questionnaire");
const txtTag = require("../lang/"+config.adminLang+"/tag");
// Actualise le classement d'un questionnaire suivant les tags envoyés
exports.checkTags = async (req, res, next) =>
@ -23,10 +23,10 @@ exports.checkTags = async (req, res, next) =>
try
{
if(req.body.QuestionnaireId==undefined)
throw { message: txt.neededParams };
throw { message: txtTag.neededParams };
const tagsCurrent=await getUsedTagsQuestionnaire(req.body.QuestionnaireId);
if(tagsCurrent===false)
throw { message: txt.tagsForQuestionnaireNotFound };
throw { message: txtTag.tagsForQuestionnaireNotFound };
const tagsReceived=req.body.classification.split(",");// ! peut être vide si pas/plus de classement souhaité
for(i in tagsReceived)
tagsReceived[i]=tagsReceived[i].trim().toLowerCase();// ! gestion de la casse différente pour JS, pas pour Mysql
@ -57,7 +57,7 @@ exports.checkTags = async (req, res, next) =>
}
findTag=false;
}
await questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId);// attendre avant de répondre pour que cela pris en compte au réaffichage
await ctrlQuestionnaire.creaQuestionnaireJson(req.body.QuestionnaireId);// attendre avant de répondre pour que cela soit pris en compte au réaffichage.
if(req.method=="PUT")
res.status(200).json({ message: txtGeneral.updateOkMessage });
else if(req.method=="POST")
@ -82,13 +82,13 @@ exports.getTagsBeginningBy = async (req, res, next) =>
{
try
{
let tags=await getAllTags(), tagsOk=[], search=req.body.search.trim().toLowerCase(), item;
let tags=await getAllTags(), tagsOk=[], search=req.body.search.trim().toLowerCase();
if(search.length >= 2)
{
for(i in tags)
for(let i in tags)
{
item=tags[i].name.toLowerCase();// restera le problème des accents
let item=tags[i].name.toLowerCase();// il reste le problème des accents
if(item.startsWith(search))
tagsOk.push(tags[i]);
}
@ -129,14 +129,14 @@ const creaAllTagsJson = async () =>
{
const db = require("../models/index");
const tags=await db["Tag"].findAll();
await toolFile.createJSON(configTags.dirCacheTags, "all", tags);
await toolFile.createJSON(configQuestionnaire.dirCacheTags, "all", tags);
return tags;
}
// Retourne la liste de tous les tags
const getAllTags = async () =>
{
const tags=await toolFile.readJSON(configTags.dirCacheTags, "all");
const tags=await toolFile.readJSON(configQuestionnaire.dirCacheTags, "all");
if(tags)
return tags;
else
@ -144,19 +144,45 @@ const getAllTags = async () =>
}
// Créer la liste de tous tags utilisés pour classer au moins un quiz publié
/// Ajouter l'actualisation de la page "parcourir" du site
const creaUsedTagsJson = async () =>
{
const db = require("../models/index");
const tags = await db.sequelize.query("SELECT DISTINCT `Tags`.`id`,`Tags`.`name`,`Tags`.`slug` FROM `Tags` INNER JOIN `QuestionnaireClassifications` INNER JOIN `Questionnaires` WHERE `Tags`.`id`=`QuestionnaireClassifications`.`TagId` AND `QuestionnaireClassifications`.`QuestionnaireId`=`Questionnaires`.`id` AND `Questionnaires`.`isPublished`=true ORDER BY `name` ASC", { type: QueryTypes.SELECT , model: db["Tag"], mapToModel: true });
await toolFile.createJSON(configTags.dirCacheTags, "used", tags);
await toolFile.createJSON(configQuestionnaire.dirCacheTags, "used", tags);
if(tags.length !== 0)
creaUsedTagsHTML(tags);
return tags;
}
exports.creaUsedTagsJson = creaUsedTagsJson;// utile pour actualiser en cas de publication/dépublication d'un quiz
// Créer la page HTML listant tous les tags
const creaUsedTagsHTML = async (tags) =>
{
// + la page listant les X derniers quizs + liste des tags
const compiledFunction=pug.compileFile("./views/"+config.theme+"/tagsList.pug");
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
let pageDatas =
{
config: config,
configTpl: configTpl,
tool: tool,
pageLang: config.adminLang,
metaDescription: configTpl.tagListMetaDesc,
pageTitle: configTpl.tagListTitle,
contentTitle: config.siteName,
tags: tags,
linkCanonical: config.siteUrl+"/"+configQuestionnaire.dirWebTags
}
html=await compiledFunction(pageDatas);
await toolFile.createHTML(configQuestionnaire.dirHTMLTags, "index", html);
return true;
}
// Retourne la liste des tags utilisés
const getUsedTags = async () =>
{
const tags=await toolFile.readJSON(configTags.dirCacheTags, "used");
const tags=await toolFile.readJSON(configQuestionnaire.dirCacheTags, "used");
if(tags)
return tags;
else
@ -168,20 +194,20 @@ exports.getUsedTags = getUsedTags;
const getUsedTagsQuestionnaire = async (id) =>
{
id=tool.trimIfNotNull(id);
if(id===null)
if(id === null)
return false;
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(id);
const questionnaire=await ctrlQuestionnaire.searchQuestionnaireById(id);
if(!questionnaire)
throw { message: txtQuestionnaire.notFound };
else
{
const allTags=await getAllTags();
let tagsQuestionnaire=[];
for(i in questionnaire.Tags)
for(let i in questionnaire.Tags)
{
for(j in allTags)
{
if(allTags[j].id===questionnaire.Tags[i].TagId)
if(allTags[j].id === questionnaire.Tags[i].TagId)
{
tagsQuestionnaire.push(allTags[j]);
break;
@ -197,11 +223,11 @@ exports.getTagsQuestionnaire = getUsedTagsQuestionnaire;
const creaQuestionnairesTagJson = async (id) =>
{
id=tool.trimIfNotNull(id);
if(id===null)
if(id === null)
return false;
const db = require("../models/index");
const questionnaires = await db.sequelize.query("SELECT id FROM `Questionnaires` INNER JOIN `QuestionnaireClassifications` ON `Questionnaires`.`id`=`QuestionnaireClassifications`.`QuestionnaireId` AND `Questionnaires`.`isPublished`=1 AND `QuestionnaireClassifications`.`TagId`=:id ORDER BY "+config.fieldNewQuestionnaires+" DESC", { replacements: { id: id }, type: QueryTypes.SELECT , model: db["Questionnaire"], mapToModel: true });
await toolFile.createJSON(configTags.dirCacheTags, "liste-"+id, questionnaires);// le supprimer si liste vide ?
await toolFile.createJSON(configQuestionnaire.dirCacheTags, "liste-"+id, questionnaires);// le supprimer si liste vide ?
creaUsedTagsJson();
creaQuestionnairesTagHTML(id, questionnaires);// pas await, car potentiellement long !
return questionnaires;
@ -211,18 +237,18 @@ exports.creaQuestionnairesTagJson = creaQuestionnairesTagJson;
const creaQuestionnairesTagHTML = async (id, Questionnaires) =>
{
id=tool.trimIfNotNull(id);
if(id===null || Questionnaires===null)
if(id === null || Questionnaires === null)
return false;
const tag=await searchTagById(id);
if(Questionnaires.length===0)
if(Questionnaires.length === 0)
{ // plus aucun quiz classé ici. Il faudrait idéalement envoyer des erreurs 404/410, etc.
// revoir aussi l'intérêt ou non de supprimer les pages suivantes, sachant qu'elles ne sont pas indexables ? ou les rendre dynamiques ?
await toolFile.deleteFile(configTags.dirHTMLTags, tag.slug+".html");
await toolFile.deleteFile(configQuestionnaire.dirHTMLTags, tag.slug+".html");
return true;
}
const compiledFunction = pug.compileFile("./views/"+config.theme+"/tag.pug");
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
const pageDatas=
const pageDatas =
{
config: config,
configTpl: configTpl,
@ -232,33 +258,32 @@ const creaQuestionnairesTagHTML = async (id, Questionnaires) =>
txtQuestionnaire: txtQuestionnaire,
txtIllustration: txtIllustration,
pageLang: config.adminLang,
metaDescription: config.siteName+" : "+txt.tagMetaDescription+tag.name,
metaDescription: config.siteName+" : "+txtTag.tagMetaDescription+tag.name,
pageTitle: config.siteName+" - "+tag.name,
contentTitle: config.siteName+" - "+tag.name,
tagInfos: tag,
linkCanonical: config.siteUrl+"/"+configTags.dirWebTags+"/"+tag.slug+".html"
linkCanonical: config.siteUrl+"/"+configQuestionnaire.dirWebTags+"/"+tag.slug+".html"
}
const nbPages=Math.ceil(Questionnaires.length / configTpl.maxQuestionnairesByPage);
pageDatas.nbPages=nbPages;
let debut=0, fin, questionnairesPage, questionnairesInfos=[], html, url;
let debut=0;
for (let i = 1; i <= nbPages; i++)
{
let questionnairesPage = Questionnaires.slice(debut, debut+configTpl.maxQuestionnairesByPage);
const questionnairesPage = Questionnaires.slice(debut, debut+configTpl.maxQuestionnairesByPage), questionnairesInfos=[];
for(let j in questionnairesPage)
questionnairesInfos.push(await questionnaireCtrl.searchQuestionnaireById(questionnairesPage[j].id));
questionnairesInfos.push(await ctrlQuestionnaire.searchQuestionnaireById(questionnairesPage[j].id));
pageDatas.questionnaires=questionnairesInfos;
pageDatas.page=i;
url=tag.slug;
let url=tag.slug;
if(i!==1)
{
url=url+"-"+i;
pageDatas.metaRobots="noindex,follow";
pageDatas.linkCanonical=null;
}
html=await compiledFunction(pageDatas);
await toolFile.createHTML(configTags.dirHTMLTags, url, html);
const html=await compiledFunction(pageDatas);
await toolFile.createHTML(configQuestionnaire.dirHTMLTags, url, html);
debut+=configTpl.maxQuestionnairesByPage;
questionnairesInfos=[];
}
return true;
}
@ -307,7 +332,7 @@ const linkTagQuestionnaire = async (tagName, questionnaireId) =>
const db = require("../models/index");
// ce tag est-il nouveau ?
let tagLinked=await searchTagByName(tagName);
if(tagLinked===false)
if(tagLinked === false)
{
tagLinked=await db["Tag"].create({ name: tagName, slug: null }, { fields: ["name", "slug"] });// "slug : null" pour laisser le modèle le générer
creaAllTagsJson();

View File

@ -50,7 +50,11 @@ module.exports =
/* Page dernières publications... */
newQuestionnairesTitle: "Culture générale - apprenez de nouvelles choses avec WikiLerni",
newQuestionnairesIntro: "WikiLerni : testez vos connaissances et apprenez de nouvelles choses avec les quizs WikiLerni.",
newsListTitle: "<h3>1 article Wikipédia + 1 quiz = 1 WikiLerni</h3><p>WikiLerni, ce sont plusieurs quizs publiés chaque semaine, chacun associé à un article Wikipédia.<br>Sans publicité, ni commerce de vos données, <b>vous apprenez de nouvelles choses en toute liberté</b>.</p><blockquote>Aristote: «Lhomme a naturellement la passion de connaître…»</blockquote>",
newsListTitle: "<h3>Avec WikiLerni, vous apprenez chaque jour quelque chose de nouveau</h3><p>Si dessous les dernières publications du site. Vous pouvez aussi <a href='/themes/'>parcourir le site par thèmes/mots-clés</a>.</p><blockquote>Aristote: «Lhomme a naturellement la passion de connaître…»</blockquote>",
/* Plan du site, liste des tags */
tagListTitle: "Culture générale - des articles et quizs sur de nombreux thèmes !",
tagListMetaDesc: "WikiLerni : découvrir les différents thèmes abordés par WikiLerni. Inxex du site.",
tagListIntro: "<h3>Avec WikiLerni, apprenez quelque chose de nouveau chaque jour</h3><blockquote>Aristote: «Lhomme a naturellement la passion de connaître…»</blockquote>",
/* Page quizs */
quizElementLinksIntro: "Source(s)",
quizElementSubcriptionFormTitle: "Recevez les prochains WikiLerni",

View File

@ -0,0 +1,18 @@
extends layout.pug
block append scripts
script(src="/JS/polyfill.app.js" defer)
script(src="/JS/index.app.js" defer)
block content
div(id="prompt" class="cardboard")
p
img(id="logo" src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni")
h1(class="cardboard") #{configTpl.siteSlogan}
div#listsIntro !{configTpl.tagListIntro}
nav(id="tagsList")
for tag in tags
div
a(href="/quizs/"+tag.slug+".html" class="button") #{tag.name}