Initial commit for publishing on gitlab
This commit is contained in:
commit
85aef66e35
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# BACKEND :
|
||||
|
||||
datas/
|
||||
logs/
|
||||
temp/
|
||||
node_modules/
|
||||
nodemon.json
|
||||
*.env
|
||||
!example.env
|
||||
/config/instance.*
|
||||
!/config/instance-example.js
|
||||
|
||||
# FRONT END :
|
||||
|
||||
/front/node_modules/
|
||||
/front/webpack.config-*.js
|
||||
!/front/webpack.config.js
|
||||
/front/public/img/quizs/
|
||||
/front/public/JS/*/
|
||||
/front/public/quiz/
|
||||
/front/public/quizs/
|
||||
/front/public/index.html
|
||||
/front/public/CGV-CGU.html
|
||||
/front/public/mentions-legales.html
|
||||
/front/public/robots-*.txt
|
||||
/front/public/WikiLerni-pub.asc
|
5
.sequelizerc
Normal file
5
.sequelizerc
Normal file
@ -0,0 +1,5 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
'config': path.resolve('config', 'database.js')
|
||||
};
|
107
app.js
Normal file
107
app.js
Normal file
@ -0,0 +1,107 @@
|
||||
require("dotenv").config();
|
||||
|
||||
const express = require("express");
|
||||
const bodyParser = require("body-parser");
|
||||
const path = require("path");
|
||||
const log4js = require("log4js");
|
||||
|
||||
const timeInitialise = require("./middleware/initialise");
|
||||
const cronRoutes = require("./routes/cron");
|
||||
const userRoutes = require("./routes/user");
|
||||
const userPausesRoutes = require("./routes/pause");
|
||||
const userPaymentsRoutes = require("./routes/payment");
|
||||
const questionnairesRoutes = require("./routes/questionnaire");
|
||||
const questionsRoutes = require("./routes/question");
|
||||
const choicesRoutes = require("./routes/choice");
|
||||
const illustrationRoutes = require("./routes/illustration");
|
||||
const linkRoutes = require("./routes/link");
|
||||
const tagRoutes = require("./routes/tag");
|
||||
|
||||
const config = require("./config/main");
|
||||
const confLog4js=require("./config/log4js");
|
||||
const txt = require("./lang/"+config.adminLang+"/general");
|
||||
const tool = require("./tools/main");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(timeInitialise);
|
||||
app.use((req, res, next) =>
|
||||
{
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content, Accept, Content-Type, Authorization");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
|
||||
next();
|
||||
});
|
||||
|
||||
//app.use(express.static(path.join(__dirname, "front/public")));
|
||||
app.use(bodyParser.json());
|
||||
app.use("/api/user", userRoutes);
|
||||
app.use("/api/pause", userPausesRoutes);
|
||||
app.use("/api/payment", userPaymentsRoutes);
|
||||
app.use("/api/questionnaire", questionnairesRoutes);
|
||||
app.use("/api/questionnaire", tagRoutes);
|
||||
app.use("/api/question", questionsRoutes);
|
||||
app.use("/api/question", choicesRoutes);
|
||||
app.use("/api/illustration", illustrationRoutes);
|
||||
app.use("/api/link", linkRoutes);
|
||||
app.use("/api/cron", cronRoutes);
|
||||
|
||||
// Évalue de la durée de la réponse (!= durée script, car fonctions asynchrones continuent). Mettre next() après réponse des contrôleurs... à contrôler !
|
||||
// Capture aussi les url inconnues en retournant une erreur 404.
|
||||
// Je peux aussi recevoir des messages à afficher dans les logs venant des "cron".
|
||||
app.use((req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if(res.headersSent)
|
||||
{
|
||||
log4js.configure(confLog4js);// ici, car pas pris en compte si je le fais avant le middleware (?).
|
||||
const myLogs = log4js.getLogger(config.env);
|
||||
let timeEnd=Date.now(), maxTime=config.responseTimingAlertInSeconde;
|
||||
if(req.url.startsWith("/api/cron"))
|
||||
maxTime=config.cronTimingAlertInSeconde;
|
||||
const mapMessage =
|
||||
{
|
||||
SCRIPT_TIMING: timeEnd-req.timeBegin,
|
||||
SCRIPT_URL: req.url
|
||||
};
|
||||
if(config.env === "development")
|
||||
{
|
||||
myLogs.info(tool.replaceAll(txt.scriptTimingInfo, mapMessage));
|
||||
if(res.alerte)
|
||||
myLogs.warn(res.alerte);
|
||||
}
|
||||
else if((timeEnd-req.timeBegin) > maxTime*1000)
|
||||
{
|
||||
myLogs.warn(tool.replaceAll(txt.scriptTimingAlert, mapMessage));
|
||||
if(res.message)
|
||||
myLogs.info(res.message);
|
||||
}
|
||||
next();
|
||||
}
|
||||
else
|
||||
{
|
||||
const err = new Error(txt.badUrl);
|
||||
err.status=404;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
|
||||
// Capture et traitement des erreurs
|
||||
app.use((err, req, res, next) =>
|
||||
{
|
||||
const status = (err.status) ? err.status : 500;
|
||||
if(!res.headersSent)
|
||||
res.status(status).json({ errors: txt.serverError });
|
||||
log4js.configure(confLog4js);// même remarque que + haut
|
||||
const myLogs = log4js.getLogger(config.env);
|
||||
myLogs.error(txt.serverErrorAdmin, { message : err.message, url: req.url });
|
||||
});
|
||||
log4js.shutdown();
|
||||
|
||||
module.exports = app;
|
29
config/database.js
Normal file
29
config/database.js
Normal file
@ -0,0 +1,29 @@
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports =
|
||||
{
|
||||
"development":
|
||||
{
|
||||
"username": process.env.DB_USER,
|
||||
"password": process.env.DB_PASS,
|
||||
"database": process.env.DB_NAME,
|
||||
"host": process.env.DB_HOST,
|
||||
"dialect": "mysql"
|
||||
},
|
||||
"test":
|
||||
{
|
||||
"username": process.env.DB_USER,
|
||||
"password": process.env.DB_PASS,
|
||||
"database": process.env.DB_NAME,
|
||||
"host": process.env.DB_HOST,
|
||||
"dialect": "mysql"
|
||||
},
|
||||
"production":
|
||||
{
|
||||
"username": process.env.DB_USER,
|
||||
"password": process.env.DB_PASS,
|
||||
"database": process.env.DB_NAME,
|
||||
"host": process.env.DB_HOST,
|
||||
"dialect": "mysql"
|
||||
}
|
||||
};
|
18
config/illustrations.js
Normal file
18
config/illustrations.js
Normal file
@ -0,0 +1,18 @@
|
||||
const instance = require("./instance");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
// API'routes (after "apiUrl" defined in instance.js)
|
||||
illustrationsRoute: "/illustration/",
|
||||
// forms : à compléter avec valeurs par défaut, etc. cf modèle
|
||||
Illustration :
|
||||
{
|
||||
alt: { maxlength: 255 },
|
||||
title: { maxlength: 255 },
|
||||
caption: { maxlength: 255 },
|
||||
image: { required: true, accept: instance.mimeTypesForIllustration.join(",") }
|
||||
},
|
||||
// files upload tempory dir
|
||||
dirIllustrationsTmp : "temp",
|
||||
dirIllustrations: "front/public/img/quizs"
|
||||
};
|
63
config/instance-demo.js
Normal file
63
config/instance-demo.js
Normal file
@ -0,0 +1,63 @@
|
||||
const users = require("./users");
|
||||
const questionnaires = require("./questionnaires");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
apiUrl: "https://apitest.wikilerni.com/api",
|
||||
siteUrl: "https://test.wikilerni.com",
|
||||
adminName: "Fabrice",
|
||||
adminEmail: "dev@wikilerni.com",
|
||||
senderName: "WikiLerni (démo)",
|
||||
senderEmail: "bonjour@wikilerni.com",
|
||||
adminLang: "fr",
|
||||
theme: "wikilerni", // le thème utilisé (dans /views) pour générer les pages HTML. Contient ses propres fichiers de configuration.
|
||||
availableLangs: ["fr"],// Languages in which the site is available. The first one is the default one.
|
||||
siteName: "WikiLerni (démo)",
|
||||
beginCodeGodfather: "WL", // case-sensitive and can't contain "@" !
|
||||
cronTimingAlertInSeconde: 120, // for logs
|
||||
responseTimingAlertInSeconde: 3, // idem
|
||||
tokenSignupValidationTimeInHours: "48h", // https://github.com/zeit/ms
|
||||
tokenLoginLinkTimeInHours: "1h",
|
||||
tokenConnexionMinTimeInHours: "24h",
|
||||
tokenConnexionMaxTimeInDays: "180 days",
|
||||
tokenLoginChangingTimeInHours: "1h",// for email & password changing
|
||||
tokenDeleteUserTimeInHours: "1h",
|
||||
tokenUnsubscribeLinkTimeInDays: "7 days", // token send with subscription's emails
|
||||
freeAccountTimingInDays: 15,
|
||||
freeAccountExpirationNotificationInDays: 2,
|
||||
accountExpirationFirstNotificationInDays: 15,
|
||||
accountExpirationSecondNotificationInDays: 3,
|
||||
inactiveAccountTimeToDeleteInDays: 180,
|
||||
// Questionnaires:
|
||||
nbQuestionsMin: 1, // minimum number of questions for the questionnaire to be publishable
|
||||
nbQuestionsMax: 0, // if 0 = not maximum
|
||||
nbChoicesMax: 10,
|
||||
nbNewQuestionnaires: 10,// for RSS, etc.
|
||||
hourGiveNewQuestionnaireBegin: 3, // in user local time
|
||||
hourGiveNewQuestionnaireEnd: 8, // idem
|
||||
numberNewQuestionnaireAtSameTime: 50, // for mass mailing
|
||||
minSearchQuestionnaires: 3,
|
||||
// Illustrations:
|
||||
nbIllustrationsMin: 0,
|
||||
nbIllustrationsMax: 1,
|
||||
maxIllustrationSizeinOctet: 1000000,// pas contrôlé pour l'instant. À revoir.
|
||||
mimeTypesForIllustration: [ "image/jpg", "image/jpeg", "image/png", "image/gif", "image/png" ],
|
||||
// -- Upload and resize:
|
||||
illustrationsWidthMaxInPx: 400,
|
||||
illustrationsMiniaturesWidthMaxInPx: 200,
|
||||
// Links:
|
||||
nbLinksMin: 1,
|
||||
nbLinksMax: 1,
|
||||
// à supprimer quand tous les "require" à jour:
|
||||
nbQuestionsMin: questionnaires.nbQuestionsMin,
|
||||
nbQuestionsMax: questionnaires.nbQuestionsMax,
|
||||
nbChoicesMax: questionnaires.nbChoicesMax,
|
||||
passwordMinLength: users.password.minlength,
|
||||
dirCacheUsers: users.dirCacheUsers,
|
||||
dirCacheUsersAnswers: users.dirCacheUsersAnswers,
|
||||
dirCacheQuestionnaires: questionnaires.dirCacheQuestionnaires,
|
||||
dirCacheQuestions: questionnaires.dirCacheQuestions,
|
||||
dirCacheUsersQuestionnaires: questionnaires.dirCacheUsersQuestionnaires,
|
||||
dirHTMLQuestionnaire: questionnaires.dirHTMLQuestionnaire,
|
||||
dirWebQuestionnaire: questionnaires.dirWebQuestionnaire
|
||||
};
|
65
config/instance-example.js
Normal file
65
config/instance-example.js
Normal file
@ -0,0 +1,65 @@
|
||||
/// À ADAPTER ET RENOMMER : instance.js.
|
||||
|
||||
const users = require("./users");
|
||||
const questionnaires = require("./questionnaires");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
apiUrl: "https://...",
|
||||
siteUrl: "https://...",
|
||||
adminName: "bob",
|
||||
adminEmail: "bob@example.tld",
|
||||
senderName: "bob",
|
||||
senderEmail: "bob@example.tld",
|
||||
adminLang: "fr",
|
||||
theme: "wikilerni", // le thème utilisé (dans /views) pour générer les pages HTML. Contient ses propres fichiers de configuration.
|
||||
availableLangs: ["fr"],// Languages in which the site is available. The first one is the default one.
|
||||
siteName: "WikiLerni",
|
||||
beginCodeGodfather: "WL", // case-sensitive and can't contain "@" !
|
||||
cronTimingAlertInSeconde: 120, // for logs
|
||||
responseTimingAlertInSeconde: 3, // idem
|
||||
tokenSignupValidationTimeInHours: "48h", // see : https://github.com/zeit/ms
|
||||
tokenLoginLinkTimeInHours: "1h",
|
||||
tokenConnexionMinTimeInHours: "24h",
|
||||
tokenConnexionMaxTimeInDays: "180 days",
|
||||
tokenLoginChangingTimeInHours: "1h",// for email & password changing
|
||||
tokenDeleteUserTimeInHours: "1h",
|
||||
tokenUnsubscribeLinkTimeInDays: "7 days", // token send with subscription's emails
|
||||
freeAccountTimingInDays: 15,
|
||||
freeAccountExpirationNotificationInDays: 3,
|
||||
accountExpirationFirstNotificationInDays: 10,
|
||||
accountExpirationSecondNotificationInDays: 3,
|
||||
inactiveAccountTimeToDeleteInDays: 180,
|
||||
// Questionnaires:
|
||||
nbQuestionsMin: 1, // minimum number of questions for the questionnaire to be publishable
|
||||
nbQuestionsMax: 0, // if 0 = not maximum
|
||||
nbChoicesMax: 10,
|
||||
nbNewQuestionnaires: 10, // for RSS, etc.
|
||||
hourGiveNewQuestionnaireBegin: 3, // in user local time
|
||||
hourGiveNewQuestionnaireEnd: 8, // idem
|
||||
numberNewQuestionnaireAtSameTime: 50, // for mass mailing sending new quiz
|
||||
minSearchQuestionnaires: 3,
|
||||
// Illustrations:
|
||||
nbIllustrationsMin: 0,
|
||||
nbIllustrationsMax: 1,
|
||||
maxIllustrationSizeinOctet: 1000000,// Not checked yet. To be continued.
|
||||
mimeTypesForIllustration: [ "image/jpg", "image/jpeg", "image/png", "image/gif", "image/png" ],
|
||||
// -- Upload and resize:
|
||||
illustrationsWidthMaxInPx: 400,
|
||||
illustrationsMiniaturesWidthMaxInPx: 200,
|
||||
// Links:
|
||||
nbLinksMin: 1,
|
||||
nbLinksMax: 1,
|
||||
// à supprimer quand tous les "require" à jour:
|
||||
nbQuestionsMin: questionnaires.nbQuestionsMin,
|
||||
nbQuestionsMax: questionnaires.nbQuestionsMax,
|
||||
nbChoicesMax: questionnaires.nbChoicesMax,
|
||||
passwordMinLength: users.password.minlength,
|
||||
dirCacheUsers: users.dirCacheUsers,
|
||||
dirCacheUsersAnswers: users.dirCacheUsersAnswers,
|
||||
dirCacheQuestionnaires: questionnaires.dirCacheQuestionnaires,
|
||||
dirCacheQuestions: questionnaires.dirCacheQuestions,
|
||||
dirCacheUsersQuestionnaires: questionnaires.dirCacheUsersQuestionnaires,
|
||||
dirHTMLQuestionnaire: questionnaires.dirHTMLQuestionnaire,
|
||||
dirWebQuestionnaire: questionnaires.dirWebQuestionnaire
|
||||
};
|
63
config/instance-prod.js
Normal file
63
config/instance-prod.js
Normal file
@ -0,0 +1,63 @@
|
||||
const users = require("./users");
|
||||
const questionnaires = require("./questionnaires");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
apiUrl: "https://api.wikilerni.com/api",
|
||||
siteUrl: "https://www.wikilerni.com",
|
||||
adminName: "Fab",
|
||||
adminEmail: "dev@wikilerni.com",
|
||||
senderName: "WikiLerni",
|
||||
senderEmail: "bonjour@wikilerni.com",
|
||||
adminLang: "fr",
|
||||
theme: "wikilerni", // le thème utilisé (dans /views) pour générer les pages HTML. Contient ses propres fichiers de configuration.
|
||||
availableLangs: ["fr"],// Languages in which the site is available. The first one is the default one.
|
||||
siteName: "WikiLerni",
|
||||
beginCodeGodfather: "WL", // case-sensitive and can't contain "@" !
|
||||
cronTimingAlertInSeconde: 120, // for logs
|
||||
responseTimingAlertInSeconde: 3, // idem
|
||||
tokenSignupValidationTimeInHours: "48h", // https://github.com/zeit/ms
|
||||
tokenLoginLinkTimeInHours: "1h",
|
||||
tokenConnexionMinTimeInHours: "24h",
|
||||
tokenConnexionMaxTimeInDays: "180 days",
|
||||
tokenLoginChangingTimeInHours: "1h",// for email & password changing
|
||||
tokenDeleteUserTimeInHours: "1h",
|
||||
tokenUnsubscribeLinkTimeInDays: "7 days", // token send with subscription's emails
|
||||
freeAccountTimingInDays: 15,
|
||||
freeAccountExpirationNotificationInDays: 3,
|
||||
accountExpirationFirstNotificationInDays: 10,
|
||||
accountExpirationSecondNotificationInDays: 3,
|
||||
inactiveAccountTimeToDeleteInDays: 180,
|
||||
// Questionnaires:
|
||||
nbQuestionsMin: 1, // minimum number of questions for the questionnaire to be publishable
|
||||
nbQuestionsMax: 0, // if 0 = not maximum
|
||||
nbChoicesMax: 10,
|
||||
nbNewQuestionnaires: 10,// for RSS, etc.
|
||||
hourGiveNewQuestionnaireBegin: 3, // in user local time
|
||||
hourGiveNewQuestionnaireEnd: 8, // idem
|
||||
numberNewQuestionnaireAtSameTime: 50, // for mass mailing
|
||||
minSearchQuestionnaires: 3,
|
||||
// Illustrations:
|
||||
nbIllustrationsMin: 0,
|
||||
nbIllustrationsMax: 1,
|
||||
maxIllustrationSizeinOctet: 1000000,// pas contrôlé pour l'instant. À revoir.
|
||||
mimeTypesForIllustration: [ "image/jpg", "image/jpeg", "image/png", "image/gif", "image/png" ],
|
||||
// -- Upload and resize:
|
||||
illustrationsWidthMaxInPx: 400,
|
||||
illustrationsMiniaturesWidthMaxInPx: 200,
|
||||
// Links:
|
||||
nbLinksMin: 1,
|
||||
nbLinksMax: 1,
|
||||
// à supprimer quand tous les "require" à jour:
|
||||
nbQuestionsMin: questionnaires.nbQuestionsMin,
|
||||
nbQuestionsMax: questionnaires.nbQuestionsMax,
|
||||
nbChoicesMax: questionnaires.nbChoicesMax,
|
||||
passwordMinLength: users.password.minlength,
|
||||
dirCacheUsers: users.dirCacheUsers,
|
||||
dirCacheUsersAnswers: users.dirCacheUsersAnswers,
|
||||
dirCacheQuestionnaires: questionnaires.dirCacheQuestionnaires,
|
||||
dirCacheQuestions: questionnaires.dirCacheQuestions,
|
||||
dirCacheUsersQuestionnaires: questionnaires.dirCacheUsersQuestionnaires,
|
||||
dirHTMLQuestionnaire: questionnaires.dirHTMLQuestionnaire,
|
||||
dirWebQuestionnaire: questionnaires.dirWebQuestionnaire
|
||||
};
|
11
config/links.js
Normal file
11
config/links.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports =
|
||||
{
|
||||
// API'routes (after "apiUrl" defined in instance.js)
|
||||
linksRoute: "/link/",
|
||||
// forms : à compléter avec valeurs par défaut, etc. cf modèle
|
||||
Link :
|
||||
{
|
||||
url: { maxlength: 255, required: true },
|
||||
anchor: { maxlength: 150, required: true }
|
||||
}
|
||||
};
|
20
config/log4js.js
Normal file
20
config/log4js.js
Normal file
@ -0,0 +1,20 @@
|
||||
module.exports =
|
||||
{
|
||||
"appenders":
|
||||
{
|
||||
"fileLogs":
|
||||
{
|
||||
"type": "dateFile",
|
||||
"filename": "logs/day.log",
|
||||
"alwaysIncludePattern" : true,
|
||||
"numBackups": 7,
|
||||
"keepFileExt": true
|
||||
},
|
||||
"console": { "type": "console" }
|
||||
},
|
||||
"categories":
|
||||
{
|
||||
"production": { "appenders": ["fileLogs"], "level": "trace" },
|
||||
"default": { "appenders": [ "console" ], "level": "trace" }
|
||||
}
|
||||
}
|
20
config/mail.js
Normal file
20
config/mail.js
Normal file
@ -0,0 +1,20 @@
|
||||
require('dotenv').config();
|
||||
const instance = require("./instance");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
"SMTP" :
|
||||
{
|
||||
"names": process.env.SMTP_NAMES.split(","),
|
||||
"hosts": process.env.SMTP_HOSTS.split(","),
|
||||
"ports": process.env.SMTP_PORTS.split(","),
|
||||
"secures" : process.env.SMTP_SECURES.split(","),
|
||||
"logins" : process.env.SMTP_LOGINS.split(","),
|
||||
"passwords" : process.env.SMTP_PASSWORDS.split(",")
|
||||
},
|
||||
"SENDER" :
|
||||
{
|
||||
"name" : instance.senderName,
|
||||
"email" : instance.senderEmail
|
||||
}
|
||||
};
|
16
config/main.js
Normal file
16
config/main.js
Normal file
@ -0,0 +1,16 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const instance = require("./instance");
|
||||
|
||||
instance.env=process.env.NODE_ENV;
|
||||
instance.bcryptSaltRounds=parseInt(process.env.BCRYPT_SALT_ROUNDS,10);
|
||||
instance.cronToken=process.env.CRON_TOKEN;
|
||||
instance.tokenPrivateKey=process.env.TOKEN_PRIVATE_KEY;
|
||||
instance.maxLoginFail=parseInt(process.env.MAX_LOGIN_FAILS,10);
|
||||
instance.loginFailTimeInMinutes=parseInt(process.env.LOGIN_FAIL_TIME_IN_MINUTES,10);
|
||||
instance.dirCache="datas";
|
||||
instance.dirHTML="front/public";
|
||||
instance.dirTmp="datas/tmp";
|
||||
instance.dirTmpLogin="datas/tmp/logins";
|
||||
|
||||
module.exports = instance;
|
56
config/questionnaires.js
Normal file
56
config/questionnaires.js
Normal file
@ -0,0 +1,56 @@
|
||||
module.exports =
|
||||
{
|
||||
// API'routes (after "apiUrl" defined in instance.js)
|
||||
questionnaireRoutes: "/questionnaire",
|
||||
getQuestionnaireRoutes: "/get",
|
||||
previewQuestionnaireRoutes: "/preview",
|
||||
publishedQuestionnaireRoutes: "/quiz/",
|
||||
saveAnswersRoute: "/answer/",
|
||||
getStatsQuestionnaires : "/stats/",
|
||||
searchQuestionnairesRoute : "/search",
|
||||
getRandomQuestionnairesRoute : "/getrandom",
|
||||
searchAdminQuestionnairesRoute : "/searchadmin",
|
||||
getListNextQuestionnaires: "/getlistnextquestionnaires/",
|
||||
regenerateHTML: "/htmlregenerated",
|
||||
// -- questions & choices :
|
||||
questionsRoute: "/question/",
|
||||
// -- tags :
|
||||
tagsSearchRoute: "/tags/search/",
|
||||
// -- answers :
|
||||
getQuestionnairesWithoutAnswer: "/withoutanswer/user/",
|
||||
getPreviousAnswers: "/user/answers/",
|
||||
getStatsAnswers : "/user/anwswers/stats/",
|
||||
getAdminStats: "/getadminstats/",
|
||||
// forms : à compléter avec valeurs par défaut, etc. cf modèle
|
||||
Questionnaire :
|
||||
{
|
||||
title: { maxlength: 255, required: true },
|
||||
slug: { maxlength: 150 }, // champ requis mais calculé à partir du titre qd vide
|
||||
introduction: { required: true }
|
||||
},
|
||||
searchQuestionnaires : { minlength: 3, required: true },
|
||||
Question :
|
||||
{
|
||||
text: { maxlength: 255, required: true },
|
||||
rank: { required: true, min:1, defaultValue:1 }
|
||||
},
|
||||
Choice :
|
||||
{
|
||||
text: { maxlength: 255, required: true }
|
||||
},
|
||||
nbQuestionsMin: 1,
|
||||
nbQuestionsMax: 0,
|
||||
nbChoicesMax: 10,
|
||||
nbTagsMin: 0,
|
||||
nbTagsMax: 0, // 0 = not max
|
||||
// JSON and HTML dir
|
||||
dirCacheQuestionnaires : "datas/questionnaires",
|
||||
dirCacheQuestions : "datas/questionnaires/questions",
|
||||
dirCacheUsersQuestionnaires : "datas/users/questionnaires",
|
||||
dirCacheTags : "datas/questionnaires/tags",
|
||||
dirHTMLQuestionnaire : "front/public/quiz",
|
||||
dirHTMLTags : "front/public/quizs",
|
||||
dirWebQuestionnaire : "quiz",//pour url page
|
||||
dirWebTags : "quizs",// idem
|
||||
nbRandomResults : 3// limite les résultat du moteur de recherche quand demande de résultats au hasard
|
||||
};
|
11
config/tags.js
Normal file
11
config/tags.js
Normal file
@ -0,0 +1,11 @@
|
||||
// fichier à supprimer une fois tous les "require" ok
|
||||
const questionnaires = require("./questionnaires");
|
||||
|
||||
module.exports =
|
||||
{
|
||||
dirCacheTags : questionnaires.dirCacheTags,
|
||||
dirHTMLTags : questionnaires.dirHTMLTags,
|
||||
dirWebTags : questionnaires.dirWebTags,
|
||||
nbTagsMin: questionnaires.nbTagsMin,
|
||||
nbTagsMax: questionnaires.nbTagsMax
|
||||
};
|
36
config/users.js
Normal file
36
config/users.js
Normal file
@ -0,0 +1,36 @@
|
||||
module.exports =
|
||||
{
|
||||
// API'routes (after "apiUrl" defined in instance.js)
|
||||
userRoutes: "/user",
|
||||
subscribeRoute: "/signup",
|
||||
getGodfatherRoute: "/getgodfatherid",
|
||||
checkIfIsEmailfreeRoute: "/isemailfree",
|
||||
checkSubscribeTokenRoute: "/validation/",
|
||||
checkLoginRoute: "/checklogin/",
|
||||
connectionRoute: "/login",
|
||||
getLoginLinkRoute: "/getloginlink",
|
||||
connectionWithLinkRoute: "/checkloginlink",
|
||||
getUserInfos: "/get/",
|
||||
createUserRoute: "/create",
|
||||
validateUserRoute: "/validate/",
|
||||
updateUserInfos: "/modify/",
|
||||
searchUserRoute: "/search/",
|
||||
getGodChilds: "/getgodchilds/",
|
||||
checkNewLoginLinkRoute: "/confirmnewlogin/",
|
||||
checkDeleteLinkRoute: "/confirmdelete/",
|
||||
getPayments: "/payment/getforoneuser/",
|
||||
unsubscribeRoute: "/subscription/stop/",
|
||||
getAdminStats: "/getadminstats/",
|
||||
// forms : à compléter avec valeurs par défaut, etc. cf modèle
|
||||
name: { maxlength: 70, required: true },
|
||||
email: { maxlength: 255, required: true },
|
||||
password: { minlength: 8, maxlength:72, required: true }, // https://www.npmjs.com/package/bcrypt#security-issues-and-concerns
|
||||
newPassword: { minlength: 8, maxlength:72 },
|
||||
codeGodfather: { maxlength: 255 },
|
||||
cguOk: { value: "true", required: true },
|
||||
timeDifferenceMin: -720,
|
||||
timeDifferenceMax:840,
|
||||
// JSON dir
|
||||
dirCacheUsers : "datas/users",
|
||||
dirCacheUsersAnswers : "datas/users/questionnaires/answers"
|
||||
};
|
273
controllers/answer.js
Normal file
273
controllers/answer.js
Normal file
@ -0,0 +1,273 @@
|
||||
const { QueryTypes } = require("sequelize");
|
||||
|
||||
const config = require("../config/main.js");
|
||||
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolFile = require("../tools/file");
|
||||
|
||||
const subscriptionCtrl = require("./subscription");
|
||||
const questionnaireCtrl = require("./questionnaire");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/answer");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
// Enregistrement d'une réponse à un questionnaire
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const checkQuestionnaireAccess=await subscriptionCtrl.checkQuestionnaireAccess(req.connectedUser.User.id, req.body.QuestionnaireId);
|
||||
req.body.UserId=req.connectedUser.User.id;
|
||||
if(checkQuestionnaireAccess) // l'utilisateur a déjà accès à ce questionnaire
|
||||
await db["Answer"].create({ ...req.body }, { fields: ["nbQuestions", "nbCorrectAnswers", "duration", "QuestionnaireId", "UserId"] });
|
||||
else
|
||||
{
|
||||
await Promise.all([
|
||||
db["QuestionnaireAccess"].create({ ...req.body }, { fields: ["QuestionnaireId", "UserId"] }),
|
||||
db["Answer"].create({ ...req.body }, { fields: ["nbQuestions", "nbCorrectAnswers", "duration", "QuestionnaireId", "UserId"] })
|
||||
]);
|
||||
}
|
||||
// j'en profite pour remettre les pendules à l'heure !
|
||||
db["User"].update({ timeDifference: req.body.timeDifference }, { where: { id : req.connectedUser.User.id }, limit:1 });
|
||||
creaUserStatsAnwsersJson(req.body.UserId);
|
||||
creaUserQuestionnairesWithoutAnswerJson(req.body.UserId);
|
||||
creaUserAnswersJson(req.body.UserId);
|
||||
res.status(201).json({ message: txt.responseSavedMessage });
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{ // à priori, l'utilisateur ne peut pas avoir envoyé de données incorrectes, donc erreur application pour admin
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne les réponses d'un utilisateur pour un questionnaire donné
|
||||
// Si fichier réponses devient trop gros, passer par sql ?
|
||||
exports.getAnswersByQuestionnaire = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const answers=await getUserAnswersByQuestionnaire(req.params.userId, req.params.questionnaireId);
|
||||
res.status(200).json(answers);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne les statistiques de l'utilisateur
|
||||
exports.getStatsByUser = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const stats=await getUserStatsAnswers(req.params.userId);
|
||||
// J'ajoute les stats générales des questionnaires pour comparaison :
|
||||
stats.general=await questionnaireCtrl.getStatsQuestionnaires();
|
||||
res.status(200).json(stats);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne la liste des questionnaires auxquels un utilisateur a accès, mais n'a pas répondu
|
||||
// Ils sont listés par ordre de fraîcheur, les + récents étant en début de liste
|
||||
// Un questionnaire de début et un nombre de questionnaires à retourner doivent être fournis (pagination).
|
||||
exports.getQuestionnairesWithouAnswerByUser = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
let datas;
|
||||
if(req.params.id===undefined || req.params.begin===undefined || req.params.nb===undefined)
|
||||
{
|
||||
const err=new Error;
|
||||
err.message=txtGeneral.neededParams;
|
||||
throw err;
|
||||
}
|
||||
else
|
||||
datas=await getUserQuestionnairesWithoutAnswer(req.params.id, req.params.begin, req.params.nb);
|
||||
if(datas!==false)
|
||||
{
|
||||
if(req.params.output!==undefined && req.params.output=="html")
|
||||
{
|
||||
if(datas.questionnaires.length!=0)
|
||||
{
|
||||
const pug = require("pug");
|
||||
const striptags = require("striptags");
|
||||
const txtIllustration= require("../lang/"+config.adminLang+"/illustration");
|
||||
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);
|
||||
}
|
||||
else
|
||||
datas.html="";
|
||||
res.status(200).json(datas);
|
||||
}
|
||||
else
|
||||
res.status(200).json(datas);
|
||||
}
|
||||
else
|
||||
res.status(404).json(txtQuestionnaire.notFound);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
// Créer la liste des réponses d'un utilisateur
|
||||
const creaUserAnswersJson = async (UserId) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const userAnswers=await db.sequelize.query("SELECT `QuestionnaireId`,`nbQuestions`,`nbCorrectAnswers`,`duration`,`createdAt` FROM `Answers` WHERE `UserId`=:id ORDER BY `QuestionnaireId` DESC, `createdAt` DESC", { replacements: { id: UserId }, type: QueryTypes.SELECT });
|
||||
if(userAnswers)
|
||||
{
|
||||
await toolFile.createJSON(config.dirCacheUsersAnswers, UserId, userAnswers);// à surveiller car fichier pouvant devenir gros ! mais utile pour SVG côté client
|
||||
return userAnswers;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.creaUserAnswersJson = creaUserAnswersJson;
|
||||
|
||||
// Retourne les réponses d'un utilisateurs à un questionnaire
|
||||
const getUserAnswersByQuestionnaire = async (UserId, QuestionnaireId) =>
|
||||
{
|
||||
let userAnswers=await toolFile.readJSON(config.dirCacheUsersAnswers, UserId);
|
||||
if(!userAnswers)
|
||||
userAnswers=await creaUserAnswersJson(UserId);
|
||||
if(!userAnswers)
|
||||
return false;
|
||||
const answers=[];
|
||||
for(let i in userAnswers)
|
||||
{
|
||||
if(userAnswers[i].QuestionnaireId==QuestionnaireId)// pas "===" car type de données pouvant être différents
|
||||
answers.push(userAnswers[i]);
|
||||
else if(answers.length!==0)// les réponses étant classées par QuestionnaireId, je peux sortir de la boucle
|
||||
break;
|
||||
}
|
||||
return answers;
|
||||
}
|
||||
|
||||
// À combien de questionnaire l'utilisateur a-t'il répondu, quelle est son résultat moyen ?
|
||||
const creaUserStatsAnwsersJson = async (UserId) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const getUserAnswers = await db["Answer"].findAll({ where: { UserId : UserId }, attributes: ["id"] });
|
||||
const getUserQuestionnaires = await db["Answer"].findAll({ attributes: [[db.sequelize.fn('DISTINCT', db.sequelize.col('QuestionnaireId')), 'id']], where: { UserId : UserId }});
|
||||
const getUserStats = await db.sequelize.query("SELECT ROUND(AVG(nbCorrectAnswers/nbQuestions) *100) as avgCorrectAnswers, ROUND(AVG(duration)) as avgDuration FROM Answers GROUP BY UserId HAVING UserId=:id", { replacements: { id: UserId }, type: QueryTypes.SELECT });
|
||||
if(getUserAnswers && getUserQuestionnaires)
|
||||
{
|
||||
const stats =
|
||||
{
|
||||
nbAnswers : getUserAnswers.length,
|
||||
nbQuestionnaires : getUserQuestionnaires.length
|
||||
}
|
||||
if(getUserStats && getUserAnswers.length!=0)
|
||||
{
|
||||
stats.avgCorrectAnswers=getUserStats[0].avgCorrectAnswers;
|
||||
stats.avgDuration=getUserStats[0].avgDuration;
|
||||
}
|
||||
await toolFile.createJSON(config.dirCacheUsersAnswers, "stats"+UserId, stats);
|
||||
return stats;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.creaUserStatsAnwsersJson = creaUserStatsAnwsersJson;
|
||||
|
||||
// Retourne les données créées par la fonction précédente
|
||||
const getUserStatsAnswers = async (UserId) =>
|
||||
{
|
||||
let userStats=await toolFile.readJSON(config.dirCacheUsersAnswers, "stats"+UserId);
|
||||
if(!userStats)
|
||||
userStats=await creaUserStatsAnwsersJson(UserId);
|
||||
if(!userStats)
|
||||
return false;
|
||||
else
|
||||
return userStats;
|
||||
}
|
||||
|
||||
// À combien de questionnaire les utilisateurs ont-ils répondu ces dernières 24 ? depuis le début ?
|
||||
const getStatsAnswers = async () =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const getAnswers24H = await db.sequelize.query("SELECT `id` FROM `Answers` WHERE `createdAt` > ADDDATE(NOW(), -1)", { type: QueryTypes.SELECT });
|
||||
const getAnswersTot = await db.sequelize.query("SELECT `id` FROM `Answers`", { type: QueryTypes.SELECT });
|
||||
if(getAnswers24H && getAnswersTot)
|
||||
{
|
||||
const stats =
|
||||
{
|
||||
nbAnswers24H : getAnswers24H.length,
|
||||
nbAnswersTot : getAnswersTot.length
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.getStatsAnswers = getStatsAnswers;
|
||||
|
||||
// Créer la liste des questionnaires proposés à l'utilisateur, mais auxquels il n'a pas encore répondu
|
||||
const creaUserQuestionnairesWithoutAnswerJson = async (UserId) =>
|
||||
{
|
||||
UserId=tool.trimIfNotNull(UserId);
|
||||
if(UserId===null)
|
||||
return false;
|
||||
const db = require("../models/index");
|
||||
const userQuestionnaires=await db.sequelize.query("SELECT `QuestionnaireId` FROM `QuestionnaireAccesses` WHERE `UserId`=:id AND `QuestionnaireId` NOT IN (SELECT DISTINCT `QuestionnaireId` FROM Answers WHERE `UserId`=:id) ORDER BY `createdAt` DESC ", { replacements: { id: UserId }, type: QueryTypes.SELECT });
|
||||
if(userQuestionnaires)
|
||||
{
|
||||
const questionnairesId=[];// les ids suffisent et allègent le fichier
|
||||
for(i in userQuestionnaires)
|
||||
questionnairesId.push(userQuestionnaires[i].QuestionnaireId);
|
||||
await toolFile.createJSON(config.dirCacheUsersQuestionnaires+"/without", UserId, { ids: questionnairesId });
|
||||
return { ids: questionnairesId };
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.creaUserQuestionnairesWithoutAnswerJson = creaUserQuestionnairesWithoutAnswerJson;
|
||||
|
||||
// Retourne les données créées par la fonction précédente
|
||||
const getUserQuestionnairesWithoutAnswer = async (UserId, begin=0, nb=10) =>
|
||||
{
|
||||
UserId=tool.trimIfNotNull(UserId);
|
||||
if(UserId===null)
|
||||
return false;
|
||||
let userQuestionnaires=await toolFile.readJSON(config.dirCacheUsersQuestionnaires+"/without", UserId);
|
||||
if(!userQuestionnaires)
|
||||
userQuestionnaires=await creaUserQuestionnairesWithoutAnswerJson(UserId);
|
||||
if(!userQuestionnaires)
|
||||
return false;
|
||||
let questionnaire, Questionnaires=[], i=begin;
|
||||
const nbTot=userQuestionnaires.ids.length;
|
||||
if(nb===0)
|
||||
nb=nbTot;// peut être = 0 si l'utilisateur est à jour
|
||||
while(i<nb && userQuestionnaires.ids[i])
|
||||
{
|
||||
questionnaire=await questionnaireCtrl.searchQuestionnaireById(userQuestionnaires.ids[i]);
|
||||
if(questionnaire)
|
||||
Questionnaires.push(questionnaire);
|
||||
i++;
|
||||
}
|
||||
return { nbTot: nbTot, questionnaires: Questionnaires };
|
||||
}
|
||||
exports.getUserQuestionnairesWithoutAnswer = getUserQuestionnairesWithoutAnswer;
|
142
controllers/choice.js
Normal file
142
controllers/choice.js
Normal file
@ -0,0 +1,142 @@
|
||||
const config = require("../config/main.js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolError = require("../tools/error");
|
||||
|
||||
const questionCtrl = require("./question");
|
||||
const questionnaireCtrl = require("./questionnaire");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/choice");
|
||||
const txtQuestion = require("../lang/"+config.adminLang+"/question");
|
||||
|
||||
// J'arrive aux deux contrôleurs suivants après être passé par les contrôleurs de "question" qui leur passe la main via next()
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
let question=await questionCtrl.searchQuestionById(req.body.QuestionId);
|
||||
if(!question)
|
||||
throw { message: txt.needQuestionForChoices+req.body.QuestionId };
|
||||
let choices=[], i=0, oneIsCorrect=false;
|
||||
while(!tool.isEmpty(req.body["choiceText"+i]))
|
||||
{
|
||||
if(req.body["choiceIsCorrect"+i]=="true")
|
||||
{
|
||||
isCorrect=true;
|
||||
oneIsCorrect=true;
|
||||
}
|
||||
else
|
||||
isCorrect=false;
|
||||
choices.push({ text:req.body["choiceText"+i], isCorrect:isCorrect, QuestionId:req.body.QuestionId });
|
||||
i++;
|
||||
}
|
||||
if(!oneIsCorrect)
|
||||
{
|
||||
questionCtrl.deleteQuestionById(req.body.QuestionId);
|
||||
res.status(400).json({ errors: [txt.needOneGoodChoice] });
|
||||
}
|
||||
else if(choices.length < 2)
|
||||
{
|
||||
questionCtrl.deleteQuestionById(req.body.QuestionId);
|
||||
res.status(400).json({ errors: [txt.needMinChoicesForQuestion] });
|
||||
}
|
||||
else if(config.nbChoicesMax!==0 && choices.length>config.nbChoicesMax)
|
||||
{
|
||||
questionCtrl.deleteQuestionById(req.body.QuestionId);
|
||||
res.status(400).json({ errors: [txt.needMaxChoicesForQuestion+config.nbChoicesMax] });
|
||||
}
|
||||
else
|
||||
{
|
||||
for(let i in choices)
|
||||
await db["Choice"].create(choices[i], { fields: ["text", "isCorrect", "QuestionId"] });
|
||||
question=await questionCtrl.creaQuestionJson(req.body.QuestionId);// besoin de ces données pour la réponse
|
||||
await questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId,true);// pour le cache + HTML
|
||||
questionnaire=await questionnaireCtrl.searchQuestionnaireById(req.body.QuestionnaireId,true);// nécessaire réaffichage après ajout
|
||||
res.status(201).json({ message: txtQuestion.addOkMessage , questionnaire: questionnaire });
|
||||
}
|
||||
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");
|
||||
let question=await questionCtrl.searchQuestionById(req.params.id);
|
||||
if(!question)
|
||||
throw { message: txt.needQuestionForChoices+req.params.id };
|
||||
let choicesUpdated=[], choicesAdded=[], i=0, isCorrect, oneIsCorrect=false;
|
||||
while(!tool.isEmpty(req.body["choiceText"+i]))
|
||||
{
|
||||
if(req.body["choiceIsCorrect"+i]=="true")
|
||||
{
|
||||
isCorrect=true;
|
||||
oneIsCorrect=true;
|
||||
}
|
||||
else
|
||||
isCorrect=false;
|
||||
if(!tool.isEmpty(req.body["idChoice"+i]))
|
||||
choicesUpdated.push({ text:req.body["choiceText"+i], isCorrect:isCorrect, id:req.body["idChoice"+i] });
|
||||
else
|
||||
choicesAdded.push({ text:req.body["choiceText"+i], isCorrect:isCorrect, QuestionId:req.params.id });
|
||||
i++;
|
||||
}
|
||||
if(!oneIsCorrect)
|
||||
res.status(400).json({ errors: [txt.needOneGoodChoice] });
|
||||
else if(i<2)
|
||||
res.status(400).json({ errors: [txt.needMinChoicesForQuestion] });
|
||||
else if(config.nbChoicesMax!==0 && i>config.nbChoicesMax)
|
||||
res.status(400).json({ errors: [txt.needMaxChoicesForQuestion+config.nbChoicesMax] });
|
||||
else
|
||||
{
|
||||
let finded=false;
|
||||
for(let i in question.Choices)// = les réponses actuellement enregistrées
|
||||
{
|
||||
for(let j in choicesUpdated)
|
||||
{
|
||||
if(choicesUpdated[j].id==question.Choices[i].id)
|
||||
{
|
||||
finded=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!finded)
|
||||
await db["Choice"].destroy( { where: { id : question.Choices[i].id }, limit:1 }); // ce choix n'a pas été gardé
|
||||
finded=false;
|
||||
}
|
||||
for(let i in choicesUpdated)
|
||||
await db["Choice"].update(choicesUpdated[i], { where: { id: choicesUpdated[i].id } , fields: ["text", "isCorrect"], limit:1 });
|
||||
for(let i in choicesAdded)
|
||||
await db["Choice"].create(choicesAdded[i], { fields: ["text", "isCorrect", "QuestionId"] });
|
||||
question=await questionCtrl.creaQuestionJson(req.params.id);// attendre pour pouvoir tout retourner
|
||||
await questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId,true);// pour le cache + HTML
|
||||
questionnaire=await questionnaireCtrl.searchQuestionnaireById(req.body.QuestionnaireId, true);// nécessaire réaffichage après enregistrement
|
||||
res.status(200).json({ message: txtQuestion.updateOkMessage , questionnaire: questionnaire });
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
const returnAPI=toolError.returnSequelize(e);
|
||||
if(returnAPI.messages)
|
||||
{
|
||||
res.status(returnAPI.status).json({ errors : returnAPI.messages });
|
||||
next();
|
||||
}
|
||||
else
|
||||
next(e);
|
||||
}
|
||||
}
|
237
controllers/illustration.js
Normal file
237
controllers/illustration.js
Normal file
@ -0,0 +1,237 @@
|
||||
const sharp = require("sharp");
|
||||
|
||||
const config = require("../config/main.js");
|
||||
const configIllustrations = require("../config/illustrations.js");
|
||||
|
||||
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+"/illustration");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const illustrationDatas = await checkHasFile(req);
|
||||
// Le fichier peut avoir été bloqué par multer :
|
||||
if(!illustrationDatas.url)
|
||||
res.status(400).json({ errors: [txt.needGoodFile] });
|
||||
else
|
||||
{
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustrationDatas.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
{
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url);
|
||||
throw { message: txt.needQuestionnaireForIllustration };
|
||||
}
|
||||
else if(configIllustrations.nbIllustrationsMax!==0 && questionnaire.Illustrations.length >= configIllustrations.nbIllustrationsMax)
|
||||
{
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url);
|
||||
res.status(400).json({ errors: [txt.needMaxIllustrationsForQuestionnaire] });
|
||||
}
|
||||
else
|
||||
{
|
||||
const illustration=await db["Illustration"].create({ ...illustrationDatas }, { fields: ["url", "alt", "title", "caption", "QuestionnaireId"] });
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustrationDatas.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher
|
||||
res.status(201).json({ message: txt.addedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
}
|
||||
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 illustration=await searchIllustrationById(req.params.id);
|
||||
if(!illustration)
|
||||
res.status(404).json({ errors: txt.notFound });
|
||||
else
|
||||
{
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustration.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
{
|
||||
if(illustrationDatas.url)
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url);
|
||||
throw { message: txt.needQuestionnaireForIllustration };
|
||||
}
|
||||
else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId)
|
||||
{
|
||||
if(illustrationDatas.url)
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations, illustrationDatas.url);
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!tool.isEmpty(req.body.fileError))
|
||||
res.status(400).json({ errors: [req.body.fileError] });
|
||||
else
|
||||
{
|
||||
const illustrationDatas = await checkHasFile(req);
|
||||
// Lors d'une mise à jour, un nouveau fichier n'a pas forcément été envoyé ou peut avoir été bloqué par multer
|
||||
// Mais si c'est le cas, on supprime l'ancien fichier :
|
||||
if(illustrationDatas.url)
|
||||
{
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations+"/min", illustration.url);
|
||||
}
|
||||
await db["Illustration"].update({ ...illustrationDatas }, { where: { id : req.params.id } , fields: ["url", "alt", "title", "caption"], limit:1 });
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustrationDatas.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher
|
||||
res.status(200).json({ message: txt.updatedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
}
|
||||
}
|
||||
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 illustration=await searchIllustrationById(req.params.id);
|
||||
if(!illustration)
|
||||
throw { message: txt.notFound+req.params.id };
|
||||
else
|
||||
{
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(illustration.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw { message: txt.needQuestionnaireForIllustration };
|
||||
else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId)
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
const delIllus=await deleteIllustrationById(req.params.id);
|
||||
if(delIllus)
|
||||
{
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(illustration.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher
|
||||
res.status(200).json({ message: txt.deletedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
else
|
||||
res.status(400).json({ errors: [txtGeneral.serverError] });
|
||||
}
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
exports.getOneIllustrationById = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const illustration=await searchIllustrationById(req.params.id);
|
||||
if(illustration)
|
||||
res.status(200).json(illustration);
|
||||
else
|
||||
res.status(404).json(null);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// cron de nettoyage des fichiers illustrations n'existant plus dans la bd
|
||||
exports.deleteOldFiles= async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const illustrations=await db["Illustration"].findAll({ attributes: ["url"] });
|
||||
let saveFiles=[];
|
||||
for(let i in illustrations)
|
||||
saveFiles.push(illustrations[i].url);
|
||||
await toolFile.deleteFilesInDirectory(configIllustrations.dirIllustrations, saveFiles);
|
||||
await toolFile.deleteFilesInDirectory(configIllustrations.dirIllustrations+"/min", saveFiles);
|
||||
// + le répertoire temporaire où rien ne devrait traîner :
|
||||
const fileExpiration=new Date().getTime()-1000;
|
||||
await toolFile.deleteOldFilesInDirectory(configIllustrations.dirIllustrationsTmp, fileExpiration);
|
||||
res.status(200).json(deleteFiles);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
// Gère le redimensionnement de l'image si un fichier est envoyé.
|
||||
// c'est multer qui vérifie dans le middleware précédent que l'image a le bon format, puis lui donne un nom (filename) si c'est ok
|
||||
const checkHasFile = async (req) =>
|
||||
{
|
||||
if(req.file)
|
||||
{ // à revoir ? : là l'image est aggrandie si + petite que demandé
|
||||
await sharp(req.file.path).resize(configIllustrations.illustrationsWidthMaxInPx).toFile(configIllustrations.dirIllustrations+"/"+req.file.filename);
|
||||
await sharp(req.file.path).resize(configIllustrations.illustrationsMiniaturesWidthMaxInPx).toFile(configIllustrations.dirIllustrations+"/min/"+req.file.filename);
|
||||
await toolFile.deleteFile(configIllustrations.dirIllustrationsTmp, req.file.filename);
|
||||
}
|
||||
// La gestion du téléchargement du fichier de l'illustration fait que les données sont envoyées sous forme de chaîne de caractères (form-data), qu'il faut transformer en json
|
||||
const datas=req.file ? { ...req.body, url: req.file.filename } : { ...req.body };
|
||||
return datas;
|
||||
}
|
||||
|
||||
const searchIllustrationById = async (id) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const illustration=await db["Illustration"].findByPk(id);
|
||||
if(illustration)
|
||||
return illustration;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const deleteIllustrationById = async (id) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const illustration=await searchIllustrationById(id);
|
||||
if(!illustration)
|
||||
throw { message: txt.notFound+id };
|
||||
else
|
||||
{
|
||||
const nb=await db["Illustration"].destroy( { where: { id : id }, limit:1 });
|
||||
if(nb===1)
|
||||
{
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations, illustration.url);
|
||||
toolFile.deleteFile(configIllustrations.dirIllustrations+"/min", illustration.url);
|
||||
questionnaireCtrl.creaQuestionnaireJson(illustration.QuestionnaireId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.deleteIllustrationById = deleteIllustrationById;
|
144
controllers/link.js
Normal file
144
controllers/link.js
Normal file
@ -0,0 +1,144 @@
|
||||
const config = require("../config/main.js");
|
||||
const configLinks = require("../config/links.js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolError = require("../tools/error");
|
||||
|
||||
const questionnaireCtrl = require("./questionnaire");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/link");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(req.body.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw { message: txt.needQuestionnaire };
|
||||
else if(configLinks.nbLinksMax!==0 && questionnaire.Links.length>=configLinks.nbLinksMax)
|
||||
res.status(400).json({ errors: txt.needMaxLinksForQuestionnaire });
|
||||
else
|
||||
{
|
||||
const link=await db["Link"].create({ ...req.body }, { fields: ["url","anchor", "QuestionnaireId"] });
|
||||
questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId);
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher
|
||||
res.status(201).json({ message: txt.addedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
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 link=await searchLinkById(req.params.id);
|
||||
if(!link)
|
||||
res.status(404).json({ errors: txt.notFound });
|
||||
else
|
||||
{
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(link.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw { message: txt.needQuestionnaire };
|
||||
else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId)
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
await db["Link"].update({ ...req.body }, { where: { id : req.params.id } , fields: ["url","anchor"], limit:1 });
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(link.QuestionnaireId);// me permet de retourner en réponse les infos actualisées pour les afficher
|
||||
res.status(200).json({ message: txt.updatedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
}
|
||||
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 link=await searchLinkById(req.params.id);
|
||||
if(!link)
|
||||
res.status(404).json({ errors: txt.notFound });
|
||||
else
|
||||
{
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(link.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw { message: txt.needQuestionnaire };
|
||||
else if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.Questionnaire.CreatorId)
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
const nb=await db["Link"].destroy( { where: { id : req.params.id }, limit:1 });
|
||||
if(nb===1)
|
||||
{
|
||||
const questionnaireDatas=await questionnaireCtrl.creaQuestionnaireJson(link.QuestionnaireId);
|
||||
res.status(200).json({ message: txt.deletedOkMessage, questionnaire: questionnaireDatas });
|
||||
}
|
||||
else // ne devrait pas être possible, car déjà testé + haut !
|
||||
throw { message: txt.needQuestionnaire };
|
||||
}
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
exports.getOneById = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const link=await searchLinkById(req.params.id);
|
||||
if(link)
|
||||
res.status(200).json(link);
|
||||
else
|
||||
res.status(404).json(null);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
const searchLinkById = async (id) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const link = await db["Link"].findByPk(id);
|
||||
if(link)
|
||||
return link;
|
||||
else
|
||||
return false;
|
||||
}
|
129
controllers/pause.js
Normal file
129
controllers/pause.js
Normal file
@ -0,0 +1,129 @@
|
||||
const { QueryTypes } = require("sequelize");
|
||||
|
||||
const config = require("../config/main.js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolError = require("../tools/error");
|
||||
|
||||
const userCtrl=require("./user");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/pause");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const connectedUser=req.connectedUser;
|
||||
req.body.SubscriptionId=connectedUser.Subscription.id;
|
||||
await db["Pause"].create({ ...req.body });
|
||||
userCtrl.creaUserJson(connectedUser.User.id);
|
||||
res.status(201).json({ message: txt.createdOkMessage });
|
||||
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 connectedUser=req.connectedUser;
|
||||
if(!checkPauseIsOk(req.params.id, connectedUser))
|
||||
res.status(404).json({ errors: txtGeneral.serverError });
|
||||
else
|
||||
{
|
||||
await db["Pause"].update({ ...req.body }, { where: { id : req.params.id } , fields: ["name", "startingAt", "endingAt"], limit:1 }),
|
||||
userCtrl.creaUserJson(connectedUser.User.id);
|
||||
res.status(201).json({ message: txt.updatedOkMessage });
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
const returnAPI=toolError.returnSequelize(e);
|
||||
if(returnAPI.length!==0)
|
||||
{
|
||||
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(!checkPauseIsOk(req.params.id, connectedUser))
|
||||
res.status(404).json({ errors: txtGeneral.serverError });
|
||||
else
|
||||
{
|
||||
await db["Pause"].destroy({ where: { id : req.params.id }, limit:1 });
|
||||
userCtrl.creaUserJson(connectedUser.User.id);
|
||||
res.status(200).json({ message: txt.deletedOkMessage });
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Cron
|
||||
exports.deleteOldPauses= async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
// on laisse deux jours de rab pour les décalages horaires & co
|
||||
const userPauses=await db.sequelize.query("SELECT DISTINCT `Subscriptions`.`UserId` FROM `Subscriptions` INNER JOIN `Pauses` ON `Subscriptions`.`id`=`Pauses`.`SubscriptionId` WHERE ADDDATE(`endingAt`, 2) < NOW()", { type: QueryTypes.SELECT });
|
||||
if(userPauses.length!==0)
|
||||
{
|
||||
await db.sequelize.query("DELETE FROM `Pauses` WHERE ADDDATE(`endingAt`, 2) < NOW()");
|
||||
for(i in userPauses)
|
||||
await userCtrl.creaUserJson(userPauses[i].UserId);
|
||||
}
|
||||
res.status(200).json(true);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
// Vérifie si la période de pause appartient bien à cet utilisateur
|
||||
const checkPauseIsOk = (idPause, user) =>
|
||||
{
|
||||
if(!user.Pauses)
|
||||
return false;
|
||||
let PauseIsOk=false, i=0;
|
||||
while (!PauseIsOk && user.Pauses[i])
|
||||
{
|
||||
if(user.Pauses[i].id == idPause)// ! n'ont pas forcément le même type
|
||||
PauseIsOk=true;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
return PauseIsOk;
|
||||
}
|
132
controllers/payment.js
Normal file
132
controllers/payment.js
Normal file
@ -0,0 +1,132 @@
|
||||
const config = require("../config/main.js");
|
||||
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolMail = require("../tools/mail");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/payment");
|
||||
const txtUser = require("../lang/"+config.adminLang+"/user");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
const userCtrl = require("./user");
|
||||
|
||||
exports.getOneUserPayments = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const connectedUser=req.connectedUser;
|
||||
if(connectedUser===false || ["admin","manager"].indexOf(connectedUser.User.status) === -1)
|
||||
res.status(403).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const Payments=await db["Payment"].findAll({ where: { UserId: req.params.id }, order: [["createdAt", "DESC"]] });
|
||||
res.status(200).json(Payments);
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
exports.saveUserPaymentInfos = async (req, res, next) =>
|
||||
{
|
||||
// exemple d'url : WP-infos.html?dom=NOM_DE_DOMAINE_DU_BOUTON&ref=ID_DU_USER&mt=MONTANT_TTC&cmd=CODE_COMMANDE_WEBPORTAGE&cl=NOM+DU+CLIENT&hKey=le_hash_en_md5
|
||||
// dom=wikilerni.com&ref=5&mt=24&cmd=de11de&cl=monsieur+dugenoux&hKey=998dccdef52bd27dc0a674941c0e9340
|
||||
try
|
||||
{
|
||||
require('dotenv').config();
|
||||
const db = require("../models/index");
|
||||
const md5 = require("md5");
|
||||
const montantsAbonnement=["12","24", "60", "120"];
|
||||
// !! attention req.query enlève les caractères spéciaux comme les "+" des paramètres de l'url. Il vaut donc mieux utiliser req.url pour comparer avec le hash au reste de la chaîne.
|
||||
const testUrl=req.url.slice(req.url.indexOf("?")+1,req.url.lastIndexOf("&"));
|
||||
console.log(testUrl);
|
||||
console.log(md5(testUrl+process.env.MD5_WP));
|
||||
if(md5(testUrl+process.env.MD5_WP)!==req.query.hKey) // le hashage est effectué après le remplacement des caractères spéciaux dans l'url.
|
||||
throw { message: txt.paymentUrlFail+testUrl };
|
||||
else if(req.query.ref==="" || montantsAbonnement.indexOf(req.query.mt) === -1)
|
||||
throw { message: txt.paymentDatasFail+testUrl };
|
||||
else
|
||||
{
|
||||
const client=await userCtrl.searchUserById(req.query.ref);
|
||||
if(!client)
|
||||
throw { message: txt.paymentUserNotFound+testUrl };
|
||||
else
|
||||
{
|
||||
// Si cet utilisateur a un parrain on le remercie et lui ajoute 30 jours d'abonnement
|
||||
// Cela impacte aussi la durée de l'abonnement commandé par l'utilisateur
|
||||
let numberOfDays=365;
|
||||
if(client.User.GodfatherId)
|
||||
{
|
||||
const parrain=await userCtrl.searchUserById(client.User.GodfatherId);
|
||||
if(parrain)
|
||||
{
|
||||
parrain.Subscription.numberOfDays+=30;
|
||||
numberOfDays+=30;
|
||||
await db["Subscription"].update({ ...parrain.Subscription }, { where: { UserId : client.User.GodfatherId }, fields: ["numberOfDays"], limit:1 });
|
||||
userCtrl.creaUserJson(client.User.GodfatherId);
|
||||
const mapMail =
|
||||
{
|
||||
USER_NAME: parrain.User.name
|
||||
};
|
||||
const mailDatas=
|
||||
{
|
||||
mailSubject: txt.mailPaymentThankGodfatherSubject,
|
||||
mailPreheader: txt.mailPaymentThankGodfatherSubject,
|
||||
mailTitle: txt.mailPaymentThankGodfatherSubject,
|
||||
mailHeaderLinkUrl: config.siteUrl+"/"+configTpl.userHomePage,
|
||||
mailHeaderLinkTxt: txt.mailPaymentLinkTxt,
|
||||
mailMainContent: tool.replaceAll(txt.mailPaymentThankGodfatherBodyHTML, mapMail),
|
||||
linksCTA: [{ url:config.siteUrl+"/"+configTpl.userHomePage, txt:txt.mailPaymentLinkTxt }],
|
||||
mailRecipientAddress: parrain.User.email
|
||||
}
|
||||
await toolMail.sendMail(parrain.User.smtp, parrain.User.email, txt.mailPaymentThankGodfatherSubject, tool.replaceAll(txt.mailPaymentThankGodfatherBodyTxt, mapMail), "", mailDatas);
|
||||
}
|
||||
else
|
||||
res.alerte=txt.paymentGodfatherNotFound+client.User.GodfatherId;
|
||||
}
|
||||
const infosClient=
|
||||
{
|
||||
clientName: req.query.cl,
|
||||
amount: req.query.mt,
|
||||
codeCommande: req.query.cmd,
|
||||
UserId: client.User.id,
|
||||
numberOfDays: client.Subscription.numberOfDays+numberOfDays
|
||||
};
|
||||
await db["Payment"].create({ ...infosClient }, { fields: ["clientName", "amount", "codeCommande", "UserId"] });
|
||||
await db["Subscription"].update({ ...infosClient }, { where: { UserId : infosClient.UserId }, fields: ["numberOfDays"], limit:1 });
|
||||
userCtrl.creaUserJson(infosClient.UserId);
|
||||
// mail remerciement abonné
|
||||
const mapMail2 =
|
||||
{
|
||||
SITE_NAME: config.siteName,
|
||||
USER_NAME: client.User.name,
|
||||
NBDAYS: numberOfDays
|
||||
};
|
||||
const mailDatas2 =
|
||||
{
|
||||
mailSubject: txt.mailPaymentThankSubject,
|
||||
mailPreheader: txt.mailPaymentThankSubject,
|
||||
mailTitle: txt.mailPaymentThankSubject,
|
||||
mailHeaderLinkUrl: config.siteUrl+"/"+configTpl.userHomePage,
|
||||
mailHeaderLinkTxt: txt.mailPaymentLinkTxt,
|
||||
mailMainContent: tool.replaceAll(txt.mailPaymentThankBodyHTML, mapMail2),
|
||||
linksCTA: [{ url:config.siteUrl+"/"+configTpl.userHomePage, txt:txt.mailPaymentLinkTxt }],
|
||||
mailRecipientAddress: client.User.email
|
||||
}
|
||||
await toolMail.sendMail(client.User.smtp, client.User.email, txt.mailPaymentThankSubject, tool.replaceAll(txt.mailPaymentThankBodyTxt, mapMail2), "", mailDatas2);
|
||||
// + info admin site
|
||||
await toolMail.sendMail(0, config.adminEmail, txt.mailPaymentAdminNoticeSubject, txt.mailPaymentAdminNoticeBodyTxt.replace("EMAIL", client.User.email), txt.mailPaymentAdminNoticeBodyHTML.replace("EMAIL", client.User.email));
|
||||
res.status(200).json(true);
|
||||
}
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
179
controllers/question.js
Normal file
179
controllers/question.js
Normal file
@ -0,0 +1,179 @@
|
||||
const { Op, QueryTypes } = require("sequelize");
|
||||
|
||||
const config = require("../config/main.js");
|
||||
|
||||
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+"/question");
|
||||
const txtGeneral = require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
exports.create = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(req.body.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw txt.needQuestionnaire;
|
||||
else if(config.nbQuestionsMax!==0 && questionnaire.Questions.length>=config.nbQuestionsMax)
|
||||
res.status(400).json({ errors: [txt.needMaxQuestions+config.nbQuestionsMax] });
|
||||
else
|
||||
{
|
||||
const question=await db["Question"].create({ ...req.body }, { fields: ["text", "explanation", "rank", "QuestionnaireId"] });
|
||||
questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId);
|
||||
req.body.QuestionId=question.id;
|
||||
next();// je passe la main au contrôleur qui gère les réponses possibles saisies pour cette question
|
||||
return true;
|
||||
}
|
||||
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 question=await searchQuestionById(req.params.id);
|
||||
if(!question)
|
||||
throw txt.notFound;
|
||||
const questionnaire=questionnaireCtrl.searchQuestionnaireById(question.Question.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw txt.needQuestionnaire;
|
||||
if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.CreatorId)
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
await db["Question"].update({ ...req.body }, { where: { id : req.params.id } , fields: ["text", "explanation", "rank"], limit:1 });
|
||||
next();// je passe la main au contrôleur qui gère les réponses possibles saisies pour cette question
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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 question=await searchQuestionById(req.params.id);
|
||||
if(!question)
|
||||
throw txt.notFound;
|
||||
let questionnaire=questionnaireCtrl.searchQuestionnaireById(question.Question.QuestionnaireId);
|
||||
if(!questionnaire)
|
||||
throw txt.needQuestionnaire;
|
||||
if(req.connectedUser.User.status==="creator" && req.connectedUser.User.id!==questionnaire.CreatorId)
|
||||
res.status(401).json({ errors: txtGeneral.notAllowed });
|
||||
else
|
||||
{
|
||||
if(await deleteQuestionById(req.params.id))
|
||||
{
|
||||
questionnaire=await questionnaireCtrl.searchQuestionnaireById(req.body.QuestionnaireId,true);// nécessaire réaffichage après suppression
|
||||
res.status(200).json({ message: txt.deleteOkMessage, questionnaire: questionnaire });
|
||||
}
|
||||
else
|
||||
res.status(400).json({ errors: txtGeneral.serverError });
|
||||
}
|
||||
next();// pour middleware mesurant la durée de la réponse
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// CRON supprimant les fichiers Json obsolètes
|
||||
exports.deleteJsonFiles= async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const questions=await db["Question"].findAll({ attributes: ["id"] });
|
||||
let saveFiles=[];
|
||||
for(let i in questions)
|
||||
saveFiles.push(questions[i].id+".json");
|
||||
const deleteFiles = await toolFile.deleteFilesInDirectory(config.dirCacheQuestions, saveFiles);
|
||||
res.status(200).json(deleteFiles);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
// Création du fichier des données relatives à une question (avec les réponses proposées)
|
||||
const creaQuestionJson = async (id) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const Question=await db["Question"].findByPk(id);
|
||||
if(Question)
|
||||
{
|
||||
let datas={ Question };
|
||||
const Choices=await db["Choice"].findAll({ where: { QuestionId: Question.id }});
|
||||
if(Choices)
|
||||
datas.Choices=Choices;
|
||||
await toolFile.createJSON(config.dirCacheQuestions, id, datas);
|
||||
return datas;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.creaQuestionJson = creaQuestionJson;
|
||||
|
||||
// Retourne les données d'une question
|
||||
const searchQuestionById = async (id) =>
|
||||
{
|
||||
const question=await toolFile.readJSON(config.dirCacheQuestions, id);
|
||||
if(question)
|
||||
return question;
|
||||
else
|
||||
return await creaQuestionJson(id);
|
||||
}
|
||||
exports.searchQuestionById = searchQuestionById;
|
||||
|
||||
// Supprime une question et ses dépendances
|
||||
const deleteQuestionById = async (id) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const question=await searchQuestionById(id);
|
||||
if(!question)
|
||||
throw txt.notFound;
|
||||
const nb=await db["Question"].destroy( { where: { id : id }, limit:1 });
|
||||
if(nb===1)
|
||||
{
|
||||
toolFile.deleteJSON(config.dirCacheQuestions, id);
|
||||
questionnaireCtrl.creaQuestionnaireJson(question.Question.QuestionnaireId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
throw txt.notFound;
|
||||
}
|
||||
exports.deleteQuestionById = deleteQuestionById;
|
728
controllers/questionnaire.js
Normal file
728
controllers/questionnaire.js
Normal file
@ -0,0 +1,728 @@
|
||||
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))
|
||||
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 `introduction` LIKE :search OR `keywords` LIKE :search) AND `isPublished` = 1", { replacements: { id:req.connectedUser.User.id, search: "%"+search+"%" }, type: QueryTypes.SELECT });
|
||||
else
|
||||
getQuestionnaires=await db.sequelize.query("SELECT `id` FROM `Questionnaires` WHERE (`title` LIKE :search OR `introduction` LIKE :search OR `keywords` LIKE :search) AND `isPublished` = 1", { replacements: { search: "%"+search+"%" }, type: QueryTypes.SELECT });
|
||||
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();
|
||||
let dateNeeded="", questionnairesDatas, dateSearch, dateQuestionnaire;
|
||||
for(let i in questionnaires)
|
||||
{
|
||||
questionnairesDatas=await searchQuestionnaireById(questionnaires[i].id);
|
||||
questionnaires[i].isPublishable=checkQuestionnaireIsPublishable(questionnairesDatas, false); // le questionnaire est-il complet ?
|
||||
if(dateNeeded==="") // si il y a plus de 24H entre deux dates de publication, c'est mal !
|
||||
{
|
||||
if(i==0)
|
||||
dateSearch=new Date(Date.now()+3600*1000*24);
|
||||
else
|
||||
dateSearch=new Date(questionnaires[i-1].datePublishing).getTime()+3600*1000*24;
|
||||
dateQuestionnaire=new Date(questionnaires[i].datePublishing).getTime();
|
||||
if(dateQuestionnaire > dateSearch)
|
||||
dateNeeded=dateSearch;
|
||||
}
|
||||
}
|
||||
if(questionnaires.length > 0 && dateNeeded==="")
|
||||
dateNeeded=new Date(dateQuestionnaire+3600*1000*24);// le jour suivant celui du dernier questionnaire
|
||||
else
|
||||
dateNeeded=new Date();// rien pour ce jour
|
||||
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));
|
||||
console.log(txtQuestionnaire.haveBeenPublished.replace(":NB", nb));
|
||||
await toolMail.sendMail(0, config.adminEmail, "Publication articles", txtQuestionnaire.haveBeenPublished.replace(":NB", nb), "<p>"+txtQuestionnaire.haveBeenPublished.replace(":NB", nb)+"</p>");
|
||||
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)
|
||||
/*if(wasPublished)
|
||||
toolFile.deleteFile(config.dirHTMLQuestionnaire, Questionnaire.slug+".html");*/
|
||||
}
|
||||
// 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,
|
||||
linkCanonical: config.siteUrl+"/"+config.dirHTMLQuestionnaire+"/"+questionnaire.Questionnaire.slug+".html"
|
||||
}
|
||||
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);
|
||||
console.log("je viens de publier le questionnaire :"+questionnaires[i].slug);
|
||||
await toolMail.sendMail(0, config.adminEmail, "Publication d'un article", "Je viens de publier le quiz : "+config.siteUrl+"/quizs/"+questionnaires[i].slug+".html", "<p>Je viens de publier le quiz : "+config.siteUrl+"/quizs/"+questionnaires[i].slug+".html</p>");
|
||||
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");
|
||||
const Questionnaires=await db["Questionnaire"].findAll({ where: { isPublished : true }, order: [["updatedAt", "DESC"], ["id", "DESC"]], attributes: ["id"], limit: config.nbNewQuestionnaires });
|
||||
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;
|
391
controllers/subscription.js
Normal file
391
controllers/subscription.js
Normal file
@ -0,0 +1,391 @@
|
||||
// Contrôleurs gérant l'abonnement de l'utilisateur mais aussi les questionnaires auxquels il a accès
|
||||
|
||||
const { Op, QueryTypes } = require("sequelize");// pour certaines requêtes sql
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const config = require("../config/main");
|
||||
const configQuestionnaires = require("../config/questionnaires");
|
||||
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
|
||||
|
||||
const tool = require("../tools/main");
|
||||
const toolFile = require("../tools/file");
|
||||
const toolMail = require("../tools/mail");
|
||||
|
||||
const txt = require("../lang/"+config.adminLang+"/subscription");
|
||||
const txtQuestionnaire= require("../lang/"+config.adminLang+"/questionnaire");
|
||||
const txtQuestionnaireAccess= require("../lang/"+config.adminLang+"/questionnaireaccess");
|
||||
const txtGeneral= require("../lang/"+config.adminLang+"/general");
|
||||
|
||||
const answerCtrl = require("./answer");
|
||||
const questionnaireCtrl = require("./questionnaire");
|
||||
const userCtrl = require("./user");
|
||||
|
||||
// Clic sur lien de désabonnement aux alertes email
|
||||
exports.unsubscribeLink = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const userDatas= await userCtrl.checkTokenUser(req.params.token);
|
||||
await db["User"].update({ newsletterOk: false }, { where: { id : userDatas.User.id }, limit:1 });
|
||||
await db["Subscription"].update({ noticeOk: false }, { where: { UserId : userDatas.User.id }, limit:1 });
|
||||
userCtrl.creaUserJson(userDatas.User.id);
|
||||
res.status(200).json({ message: txt.unsubscriptionOk });
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// CRONS
|
||||
|
||||
// + une autre notification le jour "J" ??? vérifier si l'utilisateur actif les dernières 48H et laisser les autres tranquilles ?
|
||||
exports.notifyExpirationFreeAccount= async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const dateExpirationMin=new Date(new Date().getTime()-(config.freeAccountTimingInDays-config.freeAccountExpirationNotificationInDays+1)*24*3600*1000);
|
||||
const dateExpirationMax=new Date(new Date().getTime()-(config.freeAccountTimingInDays-config.freeAccountExpirationNotificationInDays)*24*3600*1000);
|
||||
console.log("je cherche les utilisateurs freemium dont l'abonnement a été créé entre le "+dateExpirationMin+" et le "+dateExpirationMax+".");
|
||||
const users=await db["Subscription"].findAll(
|
||||
{
|
||||
where:
|
||||
{
|
||||
[Op.and]:
|
||||
[
|
||||
{ numberOfDays: config.freeAccountTimingInDays },
|
||||
{ createdAt: { [Op.gte]: dateExpirationMin } },
|
||||
{ createdAt: { [Op.lt]: dateExpirationMax } }
|
||||
]
|
||||
},
|
||||
attributes: ["UserId"]
|
||||
});
|
||||
const sendNotification = async (user) =>
|
||||
{
|
||||
let userInfos=await userCtrl.searchUserById(user.UserId);
|
||||
if(userInfos && userInfos.User.status=="user")
|
||||
{
|
||||
//const token=jwt.sign({ userId: userInfos.User.id }, config.tokenPrivateKey, { expiresIn: config.tokenLoginLinkTimeInHours });
|
||||
const mapMail =
|
||||
{
|
||||
SITE_NAME: config.siteName,
|
||||
USER_NAME: userInfos.User.name,
|
||||
LINK_URL : config.siteUrl+"/"+configTpl.updateAccountPage+"#abo"
|
||||
};
|
||||
const mailDatas=
|
||||
{
|
||||
mailSubject: txt.mailEndFreeTimeSubject,
|
||||
mailPreheader: txt.mailEndFreeTimeSubject,
|
||||
mailTitle: txt.mailEndFreeTimeSubject,
|
||||
mailHeaderLinkUrl: config.siteUrl+"/"+configTpl.updateAccountPage+"#abo",
|
||||
mailHeaderLinkTxt: txt.mailEndFreeTimeLinkTxt,
|
||||
mailMainContent: tool.replaceAll(txt.mailEndFreeTimeBodyHTML, mapMail),
|
||||
linksCTA: [{ url:config.siteUrl+"/"+configTpl.updateAccountPage+"#abo", txt:txt.mailEndFreeTimeLinkTxt }],
|
||||
mailRecipientAddress: userInfos.User.email
|
||||
}
|
||||
await toolMail.sendMail(userInfos.User.smtp, userInfos.User.email, txt.mailEndFreeTimeSubject, tool.replaceAll(txt.mailEndFreeTimeBodyTxt, mapMail), "", mailDatas);
|
||||
}
|
||||
}
|
||||
for(let i in users)
|
||||
sendNotification(users[i]);
|
||||
if(res.message)
|
||||
res.message+="\n"+users.length+txt.mailEndFreeTimeMessage;
|
||||
else
|
||||
res.message=users.length+txt.mailEndFreeTimeMessage;
|
||||
res.status(200).json(true);
|
||||
console.log(users.length+txt.mailEndFreeTimeMessage);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
exports.notifyExpirationAccount= async(req, res, next) =>
|
||||
{ // utiliser la vue puis des recherches en sql natif ou ajouter un modèle : https://stackoverflow.com/questions/48407329/cant-able-to-create-views-in-mysql-using-sequelize-orm
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const getUsers= async (nbDays) =>
|
||||
{
|
||||
const dateExpirationMin=new Date(new Date().getTime()+nbDays*24*3600*1000);
|
||||
const dateExpirationMax=new Date(new Date().getTime()+(nbDays+1)*24*3600*1000);
|
||||
const users=await db["Subscription"].findAll(
|
||||
{
|
||||
where:
|
||||
{
|
||||
[Op.and]:
|
||||
[
|
||||
{ numberOfDays: { [Op.gt]: config.freeAccountTimingInDays } },
|
||||
db.sequelize.where(db.sequelize.fn('ADDDATE', db.sequelize.col('createdAt'), db.sequelize.literal('INTERVAL `numberOfDays` DAY')), { [Op.gte]: dateExpirationMin }),
|
||||
db.sequelize.where(db.sequelize.fn('ADDDATE', db.sequelize.col('createdAt'), db.sequelize.literal('INTERVAL `numberOfDays` DAY')), { [Op.lt]: dateExpirationMax })
|
||||
]
|
||||
},
|
||||
attributes: ["UserId"],
|
||||
});
|
||||
return users;
|
||||
}
|
||||
const sendNotification= async (user, mail) => // utiliser la paramètre "mail" pour adapter le texte du mail !
|
||||
{
|
||||
let userInfos=await searchUserById(user.UserId);
|
||||
if(userInfos && userInfos.User.status=="user")
|
||||
{
|
||||
//const token=jwt.sign({ userId: userInfos.User.id }, config.tokenPrivateKey, { expiresIn: config.tokenLoginLinkTimeInHours });
|
||||
const mapMail =
|
||||
{
|
||||
SITE_NAME: config.siteName,
|
||||
USER_NAME: userInfos.User.name,
|
||||
LINK_URL : config.siteUrl+"/"+configTpl.updateAccountPage+"#abo"
|
||||
};
|
||||
const mailDatas=
|
||||
{
|
||||
mailSubject: txt.mailExpirationSubject,
|
||||
mailPreheader: txt.mailExpirationSubject,
|
||||
mailTitle: txt.mailExpirationSubject,
|
||||
mailHeaderLinkUrl: config.siteUrl+"/"+configTpl.updateAccountPage+"#abo",
|
||||
mailHeaderLinkTxt: txt.mailExpirationLinkTxt,
|
||||
mailMainContent: tool.replaceAll(txt.mailExpirationBodyHTML, mapMail),
|
||||
linksCTA: [{ url:config.siteUrl+"/"+configTpl.updateAccountPage+"#abo", txt:txt.mailExpirationLinkTxt }],
|
||||
mailRecipientAddress: userInfos.User.email
|
||||
}
|
||||
await toolMail.sendMail(userInfos.User.smtp, userInfos.User.email, txt.mailExpirationSubject, tool.replaceAll(txt.mailExpirationBodyTxt, mapMail), "", mailDatas);
|
||||
}
|
||||
}
|
||||
// première salve :
|
||||
let users1=await getUsers(config.accountExpirationFirstNotificationInDays);
|
||||
for(i in users1)
|
||||
sendNotification(users1[i], "first");
|
||||
// deuxième relance :
|
||||
let users2=await getUsers(config.accountExpirationSecondNotificationInDays);
|
||||
for(i in users2)
|
||||
sendNotification(users2[i], "second");
|
||||
if(res.message)
|
||||
res.message+="\n"+tool.replaceAll(txt.mailExpirationMessage, { FIRST:users1.length , SECOND:users2.length });
|
||||
else
|
||||
res.message=tool.replaceAll(txt.mailExpirationMessage, { FIRST:users1.length , SECOND:users2.length });
|
||||
res.status(200).json(true);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// CRON donnant accès à l'utilisateur à nouveau quiz suivant son choix
|
||||
exports.addNewQuestionnaireUsers = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const db = require("../models/index");
|
||||
// Utilisateurs dont l'abonnement est toujours actif et souhaitant recevoir un nouveau quiz le jour de l'appel de cette méthode.
|
||||
// Le tout en heure locale et en ignorant ceux qui ont déjà été servis ce jour.
|
||||
const subscriptionsOk = await db.sequelize.query("SELECT `Subscriptions`.`id` as SubscriptionId, `UserId`, `name`, `email`, `smtp`, `language`, `noticeOk`, `receiptDays`, ADDDATE(UTC_TIMESTAMP, INTERVAL `timeDifference` MINUTE) AS localDate FROM `Subscriptions` INNER JOIN `Users` ON `Subscriptions`.`UserId`=`Users`.`id` WHERE `status`='user' AND ADDDATE(`Subscriptions`.`createdAt`, `numberOfDays`) > UTC_TIMESTAMP HAVING HOUR(localDate) > "+config.hourGiveNewQuestionnaireBegin+" AND HOUR(localDate) < "+config.hourGiveNewQuestionnaireEnd+" AND LOCATE(DAYOFWEEK(localDate),receiptDays)!=0 AND SubscriptionId NOT IN (SELECT DISTINCT `SubscriptionId` FROM `Pauses` WHERE ADDDATE(`startingAt`, INTERVAL `timeDifference` MINUTE) <= localDate AND ADDDATE(`endingAT`, INTERVAL `timeDifference` MINUTE) > localDate) AND `UserId` NOT IN (SELECT DISTINCT `UserId` FROM `QuestionnaireAccesses` WHERE DATEDIFF(NOW(),`createdAt`) < 1 AND `selfCreatedOk` = false) LIMIT "+config.numberNewQuestionnaireAtSameTime, { type: QueryTypes.SELECT });
|
||||
if(subscriptionsOk.length===0)
|
||||
{
|
||||
res.status(200).json({ message: txt.allSubscriptionProcessed });
|
||||
//console.log(txt.allSubscriptionProcessed);
|
||||
}
|
||||
else
|
||||
{
|
||||
await toolMail.sendMail(0, config.adminEmail, "Abonnements à traiter", subscriptionsOk.length+" abonnements à traiter.", "<p>"+subscriptionsOk.length+" abonnements à traiter.</p>");
|
||||
let newQuestionnaire, access, questionnaire, token;
|
||||
for (let i in subscriptionsOk)
|
||||
{
|
||||
newQuestionnaire=await db.sequelize.query("SELECT `Questionnaires`.`id`, `title`, `slug`, `introduction`, `url`, `anchor`,`estimatedTime` FROM `Questionnaires` INNER JOIN `Links` ON `Links`.`QuestionnaireId`=`Questionnaires`.`id` WHERE `isPublished`=1 AND `language`='"+subscriptionsOk[i].language+"' AND `Questionnaires`.`id` NOT IN (SELECT `QuestionnaireId` FROM `QuestionnaireAccesses` WHERE `UserId`="+subscriptionsOk[i].UserId+") ORDER BY `id` LIMIT 1", { type: QueryTypes.SELECT });
|
||||
if(newQuestionnaire.length!==0)
|
||||
{
|
||||
access=await db["QuestionnaireAccess"].create({ QuestionnaireId: newQuestionnaire[0].id, UserId: subscriptionsOk[i].UserId, selfCreatedOk: false });
|
||||
if(access)
|
||||
{
|
||||
answerCtrl.creaUserQuestionnairesWithoutAnswerJson(subscriptionsOk[i].UserId);
|
||||
if(subscriptionsOk[i].noticeOk)
|
||||
{
|
||||
token=jwt.sign({ userId: subscriptionsOk[i].UserId }, config.tokenPrivateKey, { expiresIn: config.tokenUnsubscribeLinkTimeInDays });
|
||||
const mapMail =
|
||||
{
|
||||
USER_NAME: subscriptionsOk[i].name,
|
||||
QUESTIONNAIRE_URL: config.siteUrl+"/"+configQuestionnaires.dirWebQuestionnaire+"/"+newQuestionnaire[0].slug+".html#questionnaire",
|
||||
UNSUBSCRIBE_URL: config.siteUrl+"/"+configTpl.stopMailPage+token
|
||||
};
|
||||
const mailDatas=
|
||||
{
|
||||
mailSubject: newQuestionnaire[0].title,
|
||||
mailPreheader: newQuestionnaire[0].title,
|
||||
mailTitle: newQuestionnaire[0].title,
|
||||
mailHeaderLinkUrl: config.siteUrl+"/"+configTpl.stopMailPage+token,
|
||||
mailHeaderLinkTxt: txt.mailStopMailLinkTxt,
|
||||
mailMainContent: newQuestionnaire[0].introduction+"<p><b>"+txtQuestionnaire.estimatedTime+"</b> "+txtQuestionnaire.estimatedTimeOption[newQuestionnaire[0].estimatedTime]+".</p>",
|
||||
linksCTA: [{ url:newQuestionnaire[0].url, txt:newQuestionnaire[0].anchor }, { url:config.siteUrl+"/"+configQuestionnaires.dirWebQuestionnaire+"/"+newQuestionnaire[0].slug+".html#questionnaire", txt:txtQuestionnaire.btnShowQuestionnaire }],
|
||||
mailRecipientAddress: subscriptionsOk[i].email
|
||||
}
|
||||
toolMail.sendMail(subscriptionsOk[i].smtp, subscriptionsOk[i].email, newQuestionnaire[0].title, tool.replaceAll(txt.mailNewQuestionnaireBodyTxt, mapMail), "", mailDatas);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(res.alerte)
|
||||
res.alerte+="\n"+txt.noNewQuestionnaireForUser+subscriptionsOk[i].email;
|
||||
else
|
||||
res.alerte=txt.noNewQuestionnaireForUser+subscriptionsOk[i].UserId;
|
||||
await toolMail.sendMail(0, config.adminEmail, "Abonné sans nouveau quiz", txt.noNewQuestionnaireForUser+subscriptionsOk[i].email, "<p>"+txt.noNewQuestionnaireForUser+subscriptionsOk[i].email+"</p>");
|
||||
}
|
||||
}
|
||||
res.status(200).json(subscriptionsOk);
|
||||
console.log(subscriptionsOk);
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FONCTIONS UTILITAIRES
|
||||
|
||||
// Retourne un booléen suivant si l'utilisateur a accès ou non à un questionnaire
|
||||
const checkQuestionnaireAccess = async (UserId, QuestionnaireId) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const checkQuestionnaireAccess=await db["QuestionnaireAccess"].findOne({ where: { UserId : UserId, QuestionnaireId : QuestionnaireId }, attributes: ["createdAt"] });
|
||||
if(checkQuestionnaireAccess)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.checkQuestionnaireAccess = checkQuestionnaireAccess;
|
||||
|
||||
// Combien d'abonnements ont été enregistrés ces dernières 24 H ? depuis le début ? combien sont en premium ?
|
||||
// Revoir : chercher les dates de paiement WP pour avoir stats 24 H ?
|
||||
const getStatsSubscriptions = async () =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const getSubscriptions24H = await db.sequelize.query("SELECT `id` FROM `Subscriptions` WHERE `createdAt` > ADDDATE(NOW(), -1)", { type: QueryTypes.SELECT });
|
||||
const getSubscriptionsTot = await db.sequelize.query("SELECT `id` FROM `Subscriptions`", { type: QueryTypes.SELECT });
|
||||
const getSubscriptionsPremium = await db.sequelize.query("SELECT `id` FROM `Subscriptions` WHERE `numberOfDays` > :nb", { replacements: { nb: config.freeAccountTimingInDays }, type: QueryTypes.SELECT });
|
||||
if(getSubscriptions24H && getSubscriptionsTot && getSubscriptionsPremium)
|
||||
{
|
||||
const stats =
|
||||
{
|
||||
nbSubscriptions24H : getSubscriptions24H.length,
|
||||
nbSubscriptionsTot : getSubscriptionsTot.length,
|
||||
nbSubscriptionsPremium : getSubscriptionsPremium.length
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.getStatsSubscriptions = getStatsSubscriptions;
|
||||
|
||||
/* Abandonné pour l'instant
|
||||
*
|
||||
// Recherche par mots-clés parmis les questionnaires auxquels l'utilisateur a accès !! où ceux auxquels il a répondu ? est-ce que cela a un intérêt ?
|
||||
// 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");
|
||||
const getQuestionnaires=await db.sequelize.query("SELECT `Questionnaires`.`id` FROM `Questionnaires` INNER JOIN `QuestionnaireAccesses` WHERE `Questionnaires`.`id`=`QuestionnaireAccesses`.`QuestionnaireId` AND `QuestionnaireAccesses`.`UserId`=:id AND `Questionnaires`.`isPublished` = 1 AND (`Questionnaires`.`title` LIKE :search OR `Questionnaires`.`introduction` LIKE :search)", { replacements: { id: req.connectedUser.User.id, search: "%"+search+"%" }, type: QueryTypes.SELECT });
|
||||
let begin=0, end, output="";
|
||||
if(!tool.isEmpty(req.body.begin))
|
||||
begin=req.body.begin;
|
||||
end=begin+configTpl.maxQuestionnairesByPage-1;// commence à 0 !
|
||||
if(req.body.output!==undefined)
|
||||
output=req.body.output;
|
||||
datas=await questionnaireCtrl.getListingsQuestionnairesOuput(getQuestionnaires, begin, end, output);
|
||||
res.status(200).json(datas);
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne un questionnaire au hasard parmi ceux auxquels l'utilisateur a accès
|
||||
exports.getOneRandomQuestionnaire = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const questionnaires=await getUserQuestionnaires(req.params.id, false);
|
||||
if(!questionnaires || questionnaires.ids.length===0)
|
||||
res.status(404).json({ txtCode: "notFound" });
|
||||
else
|
||||
{
|
||||
const randomInt=tool.getRandomInt(0, questionnaires.ids.length);
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(questionnaires.ids[randomInt]);
|
||||
if(questionnaire)
|
||||
res.status(200).json(questionnaire);
|
||||
else
|
||||
throw { message : txtQuestionnaireAccess.notFound+questionnaires.ids[randomInt], status : 404 };
|
||||
}
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne la liste des questionnaires auxquels un utilisateur a accès.
|
||||
// Ils sont listés par ordre de fraîcheur, les + récents étant en début de liste
|
||||
// Si un questionnaire de début et un nombre de questionnaires sont fournis, l'ensemble des informations du questionnaire sont retournées
|
||||
// Sinon, seulement les ids.
|
||||
exports.getQuestionnairesByUser = async(req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
let datas;
|
||||
if(req.params.begin && req.params.nb)
|
||||
datas=await getUserQuestionnaires(req.params.id, true, req.params.begin, req.params.nb);
|
||||
else
|
||||
datas=await getUserQuestionnaires(req.params.id, false);
|
||||
if(datas)
|
||||
res.status(200).json(datas);
|
||||
else
|
||||
res.status(404).json(txtQuestionnaire.notFound);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
*
|
||||
// Création du fichier des identifiants des questionnaires d'un utilisateur
|
||||
// Les premiers étant les derniers
|
||||
const creaUserQuestionnairesJson = async (UserId) =>
|
||||
{
|
||||
UserId=tool.trimIfNotNull(UserId);
|
||||
if(UserId===null)
|
||||
return false;
|
||||
const db = require("../models/index");
|
||||
const userQuestionnaires=await db.sequelize.query("SELECT `QuestionnaireId` FROM `QuestionnaireAccesses` WHERE `UserId`=:id ORDER BY `createdAt` DESC", { replacements: { id: UserId }, type: QueryTypes.SELECT });
|
||||
if(userQuestionnaires)
|
||||
{
|
||||
const questionnairesId=[];// les ids suffisent et allègent le fichier
|
||||
for(i in userQuestionnaires)
|
||||
questionnairesId.push(userQuestionnaires[i].QuestionnaireId);
|
||||
await toolFile.createJSON(config.dirCacheUsersQuestionnaires, UserId, { ids: questionnairesId });
|
||||
return { ids: questionnairesId };
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
exports.creaUserQuestionnairesJson = creaUserQuestionnairesJson;
|
||||
* */
|
321
controllers/tag.js
Normal file
321
controllers/tag.js
Normal file
@ -0,0 +1,321 @@
|
||||
const { Op, QueryTypes } = require("sequelize");// pour certaines requêtes sql
|
||||
|
||||
const pug = require("pug");
|
||||
var striptags = require("striptags");
|
||||
|
||||
const config = require("../config/main.js");
|
||||
const configTags = require("../config/tags.js");
|
||||
|
||||
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");
|
||||
|
||||
// Actualise le classement d'un questionnaire suivant les tags envoyés
|
||||
exports.checkTags = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if(req.body.QuestionnaireId==undefined)
|
||||
throw { message: txt.neededParams };
|
||||
const tagsCurrent=await getUsedTagsQuestionnaire(req.body.QuestionnaireId);
|
||||
if(tagsCurrent===false)
|
||||
throw { message: txt.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
|
||||
// les tags jusqu'ici associés sont-ils toujours utilisés ?
|
||||
let deleteLink;
|
||||
for (i in tagsCurrent)
|
||||
{
|
||||
if(tagsReceived.indexOf(tagsCurrent[i].name.toLowerCase())===-1)
|
||||
deleteLink=await unlinkTagQuestionnaire(tagsCurrent[i].id, req.body.QuestionnaireId);
|
||||
}
|
||||
// parmis les tags envoyés, certains sont-ils nouveaux pour ce questionnaire ?
|
||||
let findTag=false, creaLink;
|
||||
for(i in tagsReceived)
|
||||
{
|
||||
for(j in tagsCurrent)
|
||||
{
|
||||
if(tagsCurrent[j].name.toLowerCase()===tagsReceived[i])
|
||||
{
|
||||
findTag=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!findTag && tagsReceived[i]!=="") // revoir : remettre les majuscules lors de l'enregistrement ?
|
||||
{
|
||||
creaLink=await linkTagQuestionnaire(tagsReceived[i], req.body.QuestionnaireId);
|
||||
if(creaLink!==true)
|
||||
throw creaLink;// nécessaire pour retourner les erreurs du modèle (mais uniquement "tag trop long" possible)
|
||||
}
|
||||
findTag=false;
|
||||
}
|
||||
await questionnaireCtrl.creaQuestionnaireJson(req.body.QuestionnaireId);// attendre avant de répondre pour que cela pris en compte au réaffichage
|
||||
if(req.method=="PUT")
|
||||
res.status(200).json({ message: txtGeneral.updateOkMessage });
|
||||
else if(req.method=="POST")
|
||||
res.status(201).json({ message: txtGeneral.addOkMessage, id:req.body.QuestionnaireId });
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
const returnAPI=toolError.returnSequelize(e);
|
||||
if(returnAPI.messages)
|
||||
{
|
||||
res.status(returnAPI.status).json({ errors : returnAPI.messages });
|
||||
next();
|
||||
}
|
||||
else
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne la liste des tags déjà connus débutant par l'expression donnée :
|
||||
exports.getTagsBeginningBy = async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
let tags=await getAllTags(), tagsOk=[], search=req.body.search.trim().toLowerCase(), item;
|
||||
if(search.length >= 2)
|
||||
{
|
||||
for(i in tags)
|
||||
{
|
||||
|
||||
item=tags[i].name.toLowerCase();// restera le problème des accents
|
||||
if(item.startsWith(search))
|
||||
tagsOk.push(tags[i]);
|
||||
}
|
||||
}
|
||||
res.status(200).json(tagsOk);
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Fais suite à la même fonction dans questionnaire.js
|
||||
// Va récupérer la liste des tags utilisés pour classer au moins un questionnaire publié
|
||||
// Puis regénère les fichiers HTML pour chacun de ces tags
|
||||
exports.HTMLRegenerate= async (req, res, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const tagsUsed=await getUsedTags();
|
||||
for(let i in tagsUsed)
|
||||
await creaQuestionnairesTagJson(tagsUsed[i].id);// provoque la regénération du json + du html
|
||||
res.status(200).json({ message: res.messageToNext.replace("#NB2", tagsUsed.length) });
|
||||
res.messageToNext=null;
|
||||
next();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
|
||||
// UTILITAIRES
|
||||
|
||||
// Créer la liste de tous les tags présents dans la base de données
|
||||
const creaAllTagsJson = async () =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
const tags=await db["Tag"].findAll();
|
||||
await toolFile.createJSON(configTags.dirCacheTags, "all", tags);
|
||||
return tags;
|
||||
}
|
||||
|
||||
// Retourne la liste de tous les tags
|
||||
const getAllTags = async () =>
|
||||
{
|
||||
const tags=await toolFile.readJSON(configTags.dirCacheTags, "all");
|
||||
if(tags)
|
||||
return tags;
|
||||
else
|
||||
return await creaAllTagsJson();
|
||||
}
|
||||
|
||||
// Créer la liste de tous tags utilisés pour classer au moins un quiz publié
|
||||
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);
|
||||
return tags;
|
||||
}
|
||||
exports.creaUsedTagsJson = creaUsedTagsJson;// utile pour actualiser en cas de publication/dépublication d'un quiz
|
||||
|
||||
// Retourne la liste des tags utilisés
|
||||
const getUsedTags = async () =>
|
||||
{
|
||||
const tags=await toolFile.readJSON(configTags.dirCacheTags, "used");
|
||||
if(tags)
|
||||
return tags;
|
||||
else
|
||||
return await creaUsedTagsJson();
|
||||
}
|
||||
exports.getUsedTags = getUsedTags;
|
||||
|
||||
// Retourne la liste des tags d'un questionnaire avec leurs noms, slugs, etc.
|
||||
const getUsedTagsQuestionnaire = async (id) =>
|
||||
{
|
||||
id=tool.trimIfNotNull(id);
|
||||
if(id===null)
|
||||
return false;
|
||||
const questionnaire=await questionnaireCtrl.searchQuestionnaireById(id);
|
||||
if(!questionnaire)
|
||||
throw { message: txtQuestionnaire.notFound };
|
||||
else
|
||||
{
|
||||
const allTags=await getAllTags();
|
||||
let tagsQuestionnaire=[];
|
||||
for(i in questionnaire.Tags)
|
||||
{
|
||||
for(j in allTags)
|
||||
{
|
||||
if(allTags[j].id===questionnaire.Tags[i].TagId)
|
||||
{
|
||||
tagsQuestionnaire.push(allTags[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tagsQuestionnaire;
|
||||
}
|
||||
}
|
||||
exports.getTagsQuestionnaire = getUsedTagsQuestionnaire;
|
||||
|
||||
// Créer la liste complète des questionnaires publiés, classés par un tag
|
||||
const creaQuestionnairesTagJson = async (id) =>
|
||||
{
|
||||
id=tool.trimIfNotNull(id);
|
||||
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 `Questionnaires`.`publishingAt`", { replacements: { id: id }, type: QueryTypes.SELECT , model: db["Questionnaire"], mapToModel: true });
|
||||
await toolFile.createJSON(configTags.dirCacheTags, "liste-"+id, questionnaires);// le supprimer si liste vide ?
|
||||
creaUsedTagsJson();
|
||||
creaQuestionnairesTagHTML(id, questionnaires);// pas await, car potentiellement long !
|
||||
return questionnaires;
|
||||
}
|
||||
exports.creaQuestionnairesTagJson = creaQuestionnairesTagJson;
|
||||
|
||||
const creaQuestionnairesTagHTML = async (id, Questionnaires) =>
|
||||
{
|
||||
id=tool.trimIfNotNull(id);
|
||||
if(id===null || Questionnaires===null)
|
||||
return false;
|
||||
const tag=await searchTagById(id);
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
const compiledFunction = pug.compileFile("./views/"+config.theme+"/tag.pug");
|
||||
const configTpl = require("../views/"+config.theme+"/config/"+config.availableLangs[0]+".js");
|
||||
const pageDatas=
|
||||
{
|
||||
config: config,
|
||||
configTpl: configTpl,
|
||||
tool: tool,
|
||||
striptags: striptags,
|
||||
txtGeneral : txtGeneral,
|
||||
txtQuestionnaire: txtQuestionnaire,
|
||||
txtIllustration: txtIllustration,
|
||||
pageLang: config.adminLang,
|
||||
metaDescription: config.siteName+" : "+txt.tagMetaDescription+tag.name,
|
||||
pageTitle: config.siteName+" - "+tag.name,
|
||||
contentTitle: config.siteName+" - "+tag.name,
|
||||
tagInfos: tag,
|
||||
linkCanonical: config.siteUrl+"/"+configTags.dirWebTags+"/"+tag.slug+".html"
|
||||
}
|
||||
const nbPages=Math.ceil(Questionnaires.length / configTpl.maxQuestionnairesByPage);
|
||||
pageDatas.nbPages=nbPages;
|
||||
let debut=0, fin, questionnairesPage, questionnairesInfos=[], html, url;
|
||||
for (let i = 1; i <= nbPages; i++)
|
||||
{
|
||||
let questionnairesPage = Questionnaires.slice(debut, debut+configTpl.maxQuestionnairesByPage);
|
||||
for(let j in questionnairesPage)
|
||||
questionnairesInfos.push(await questionnaireCtrl.searchQuestionnaireById(questionnairesPage[j].id));
|
||||
pageDatas.questionnaires=questionnairesInfos;
|
||||
pageDatas.page=i;
|
||||
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);
|
||||
debut+=configTpl.maxQuestionnairesByPage;
|
||||
questionnairesInfos=[];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retourne un tag, si il existe
|
||||
const searchTagByName = async (name) =>
|
||||
{
|
||||
name=tool.trimIfNotNull(name);
|
||||
if(name===null)
|
||||
return false;
|
||||
const db = require("../models/index");
|
||||
const tag=await db["Tag"].findOne({ where: { name: name } }); // utile de faire en sql pour les problèmes de majuscules / minuscules
|
||||
if(tag)
|
||||
return tag;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const searchTagById = async (id) =>
|
||||
{
|
||||
id=tool.trimIfNotNull(id);
|
||||
if(id===null)
|
||||
return false;
|
||||
const db = require("../models/index");
|
||||
const tag=await db["Tag"].findByPk(id);
|
||||
if(tag)
|
||||
return tag;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Supprime l'association entre un tag et un questionnaire + actualise la liste des questionnaires pour le tag concerné
|
||||
// La mise à jour du json/HTML du questionnaire est appelée par le contrôleur appelant cette fonction
|
||||
const unlinkTagQuestionnaire = async (tagId, questionnaireId) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
await db["QuestionnaireClassification"].destroy( { where: { TagId: tagId, QuestionnaireId : questionnaireId }, limit:1 });
|
||||
creaQuestionnairesTagJson(tagId);// peut être lent !
|
||||
return true;
|
||||
}
|
||||
|
||||
// Créer l'association entre un tag et un questionnaire + actualise la liste des questionnaires / tag
|
||||
// La mise à jour du json/HTML du questionnaire est appelée par le contrôleur appelant cette fonction
|
||||
const linkTagQuestionnaire = async (tagName, questionnaireId) =>
|
||||
{
|
||||
const db = require("../models/index");
|
||||
// ce tag est-il nouveau ?
|
||||
let tagLinked=await searchTagByName(tagName);
|
||||
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();
|
||||
}
|
||||
if(tagLinked)
|
||||
{
|
||||
await db["QuestionnaireClassification"].create({ TagId: tagLinked.id, QuestionnaireId: questionnaireId });
|
||||
creaQuestionnairesTagJson(tagLinked.id);// peut être lent !
|
||||
}
|
||||
return true;
|
||||
}
|
1184
controllers/user.js
Normal file
1184
controllers/user.js
Normal file
File diff suppressed because it is too large
Load Diff
27
example.env
Normal file
27
example.env
Normal file
@ -0,0 +1,27 @@
|
||||
# COMPLÉTER LES VARIABLES D'ENVIRONNEMENT CI-DESSOUS, SUPPRIMER TOUTES LES LIGNES DE COMMENTAIRES SANS LAISSER D'ESPACES. PUIS ENREGISTRER LE FICHIER : .env
|
||||
# development/production ?
|
||||
NODE_ENV=
|
||||
# DATABASE LOGIN DETAILS :
|
||||
DB_HOST=
|
||||
DB_USER=
|
||||
DB_PASS=
|
||||
DB_NAME=
|
||||
# INFORMATION FOR CONNECTING TO THE STMP SERVER(S). IF THERE ARE SEVERAL, SEPARATE THE INFORMATION WITH A COMMA WITHOUT SPACES.
|
||||
SMTP_NAMES=
|
||||
SMTP_HOSTS=
|
||||
SMTP_PORTS=
|
||||
SMTP_SECURES=
|
||||
SMTP_LOGINS=
|
||||
SMTP_PASSWORDS=
|
||||
# AN INTEGER NUMBER USED FOR PASSWORD ENCRYPTION (see : https://www.npmjs.com/package/bcrypt) :
|
||||
BCRYPT_SALT_ROUNDS=
|
||||
# STRING USED BY THE CONNECTION TOKENS (see : https://www.npmjs.com/package/jsonwebtoken) :
|
||||
TOKEN_PRIVATE_KEY=
|
||||
# STRING USED BY THE CRONJOBS TOKENS :
|
||||
CRON_TOKEN=
|
||||
# NUMBER OF LOGIN ERRORS BEFORE THE USER IS BLOCKED :
|
||||
MAX_LOGIN_FAILS=
|
||||
# TIME DURING WHICH THE USER CAN NO LONGER LOG IN :
|
||||
LOGIN_FAIL_TIME_IN_MINUTES=Time during which the user can no longer log in.
|
||||
# ONLY USEFUL IF YOU USE THE WEBPORTAGE PAYMENT SOLUTION :
|
||||
MD5_WP=
|
6672
front/package-lock.json
generated
Normal file
6672
front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
front/package.json
Normal file
31
front/package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "wikilerni",
|
||||
"version": "0.1.1",
|
||||
"description": "Front-end of WikiLerni web application",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack",
|
||||
"start": "webpack-dev-server"
|
||||
},
|
||||
"keywords": [
|
||||
"quiz",
|
||||
"wikipédia",
|
||||
"questionnaire",
|
||||
"e-learning"
|
||||
],
|
||||
"author": "Fabrice PENHOËT",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.0",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%"
|
||||
]
|
||||
}
|
50
front/public/.htaccess
Normal file
50
front/public/.htaccess
Normal file
@ -0,0 +1,50 @@
|
||||
# Activation de la génération des en-têtes Expires
|
||||
ExpiresActive On
|
||||
# Les documents HTML, JS, JSON, CSS, XML expirent dès leur modification
|
||||
ExpiresByType text/html M0
|
||||
ExpiresByType text/javascript M0
|
||||
ExpiresByType application/javascript M0
|
||||
ExpiresByType application/json M0
|
||||
ExpiresByType text/css M0
|
||||
ExpiresByType application/xml M0
|
||||
|
||||
# Compression de certains fichiers
|
||||
SetOutputFilter DEFLATE
|
||||
|
||||
AddOutputFilterByType DEFLATE application/javascript
|
||||
AddOutputFilterByType DEFLATE application/rss+xml
|
||||
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
|
||||
AddOutputFilterByType DEFLATE application/x-font
|
||||
AddOutputFilterByType DEFLATE application/x-font-opentype
|
||||
AddOutputFilterByType DEFLATE application/x-font-otf
|
||||
AddOutputFilterByType DEFLATE application/x-font-truetype
|
||||
AddOutputFilterByType DEFLATE application/x-font-ttf
|
||||
AddOutputFilterByType DEFLATE application/x-javascript
|
||||
AddOutputFilterByType DEFLATE application/xhtml+xml
|
||||
AddOutputFilterByType DEFLATE application/xml
|
||||
AddOutputFilterByType DEFLATE font/opentype
|
||||
AddOutputFilterByType DEFLATE font/otf
|
||||
AddOutputFilterByType DEFLATE font/ttf
|
||||
AddOutputFilterByType DEFLATE image/png
|
||||
AddOutputFilterByType DEFLATE image/svg+xml
|
||||
AddOutputFilterByType DEFLATE image/x-icon
|
||||
AddOutputFilterByType DEFLATE text/css
|
||||
AddOutputFilterByType DEFLATE text/html
|
||||
AddOutputFilterByType DEFLATE text/javascript
|
||||
AddOutputFilterByType DEFLATE text/xml
|
||||
|
||||
# Bloquer ETag
|
||||
Header unset ETag
|
||||
FileETag none
|
||||
|
||||
# Protection de la lecture des répertoires
|
||||
Options -Indexes
|
||||
|
||||
# protection du htaccess
|
||||
<files .htaccess>
|
||||
order allow,deny
|
||||
deny from all
|
||||
</files>
|
||||
|
||||
# erreur 404
|
||||
ErrorDocument 404 /404.html
|
56
front/public/404.html
Normal file
56
front/public/404.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="L'erreur est humaine !">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni : page non trouvée</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="page" class="cardboard">
|
||||
<div class="framed">
|
||||
<h2>Page non trouvée !</h2>
|
||||
<p class="engraved">La page que vous demandez n'a pas été trouvée !<br>Peut-être a-t'elle été supprimée ou déplacée ?</p>
|
||||
<p class="engraved">
|
||||
<figure>
|
||||
<img alt="Illustration : page non trouvée" src="/img/404-notfound.png">
|
||||
<figCaption>Crédit illustration : <a title="coursetakers.ae / CC BY-SA (https://creativecommons.org/licenses/by-sa/4.0)" href="https://commons.wikimedia.org/wiki/File:Found_nothing.png">CC BY-SA coursetakers.ae</a></figCaption>
|
||||
</figure></p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
1463
front/public/JS/accountUser.app.js
Normal file
1463
front/public/JS/accountUser.app.js
Normal file
File diff suppressed because one or more lines are too long
1294
front/public/JS/connection.app.js
Normal file
1294
front/public/JS/connection.app.js
Normal file
File diff suppressed because one or more lines are too long
1113
front/public/JS/deconnection.app.js
Normal file
1113
front/public/JS/deconnection.app.js
Normal file
File diff suppressed because one or more lines are too long
1168
front/public/JS/deleteValidation.app.js
Normal file
1168
front/public/JS/deleteValidation.app.js
Normal file
File diff suppressed because one or more lines are too long
1278
front/public/JS/homeManager.app.js
Normal file
1278
front/public/JS/homeManager.app.js
Normal file
File diff suppressed because one or more lines are too long
1518
front/public/JS/homeUser.app.js
Normal file
1518
front/public/JS/homeUser.app.js
Normal file
File diff suppressed because one or more lines are too long
864
front/public/JS/index.app.js
Normal file
864
front/public/JS/index.app.js
Normal file
File diff suppressed because one or more lines are too long
1210
front/public/JS/loginLink.app.js
Normal file
1210
front/public/JS/loginLink.app.js
Normal file
File diff suppressed because one or more lines are too long
872
front/public/JS/loginlink.app.js
Normal file
872
front/public/JS/loginlink.app.js
Normal file
File diff suppressed because one or more lines are too long
2070
front/public/JS/manageQuestionnaires.app.js
Normal file
2070
front/public/JS/manageQuestionnaires.app.js
Normal file
File diff suppressed because one or more lines are too long
1608
front/public/JS/manageUsers.app.js
Normal file
1608
front/public/JS/manageUsers.app.js
Normal file
File diff suppressed because one or more lines are too long
1174
front/public/JS/newLoginValidation.app.js
Normal file
1174
front/public/JS/newLoginValidation.app.js
Normal file
File diff suppressed because one or more lines are too long
11169
front/public/JS/polyfill.app.js
Normal file
11169
front/public/JS/polyfill.app.js
Normal file
File diff suppressed because one or more lines are too long
1458
front/public/JS/questionnaire.app.js
Normal file
1458
front/public/JS/questionnaire.app.js
Normal file
File diff suppressed because one or more lines are too long
1104
front/public/JS/quiz.app.js
Normal file
1104
front/public/JS/quiz.app.js
Normal file
File diff suppressed because one or more lines are too long
1328
front/public/JS/subscribe.app.js
Normal file
1328
front/public/JS/subscribe.app.js
Normal file
File diff suppressed because one or more lines are too long
1186
front/public/JS/subscribeValidation.app.js
Normal file
1186
front/public/JS/subscribeValidation.app.js
Normal file
File diff suppressed because one or more lines are too long
1235
front/public/JS/unsubscribe.app.js
Normal file
1235
front/public/JS/unsubscribe.app.js
Normal file
File diff suppressed because one or more lines are too long
868
front/public/JS/validation.app.js
Normal file
868
front/public/JS/validation.app.js
Normal file
File diff suppressed because one or more lines are too long
138
front/public/a-propos.html
Normal file
138
front/public/a-propos.html
Normal file
@ -0,0 +1,138 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Foire Aux Questions WikiLerni, pour tout savoir sur le site.">
|
||||
<title>Tout savoir sur WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="canonical" href="https://www.wililerni.com/a-propos.html">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="page" class="cardboard">
|
||||
|
||||
<div class="framed">
|
||||
<h2>Qu'est-ce que WikiLerni ?</h2>
|
||||
|
||||
<p class="engraved">WikiLerni vous propose de lire une sélection d'articles de Wikipédia.<br>
|
||||
Suite à chaque lecture, une série de questions vous permet de tester ce que vous avez retenu.<br>
|
||||
Toutes les réponses à ce quiz se trouvent dans l'article proposé à la lecture.<br>
|
||||
Vous pouvez sauvegarder vos résultats au quiz en créant un compte WikiLerni.<br>
|
||||
Vous pourrez ensuite répondre de nouveau aux mêmes questions plusieurs semaines, mois... après avoir lu l'article.<br>
|
||||
De quoi tester votre mémoire à plus en moins long terme !</p>
|
||||
|
||||
<h2>Que signifie "WikiLerni" ?</h2>
|
||||
|
||||
<p class="engraved">Le nom "WikiLerni" est composé de deux parties :
|
||||
<ul>
|
||||
<li>« Wiki » fait évidemment référence à l'encyclopédie en ligne Wikipédia. Comme je vous sais curieux, sachez que le terme « wiki » vient lui-même du mot hawaïen « wikiwiki » signifiant « rapide », « vite » ou « informel ».</li>
|
||||
<li>« Lerni » est un verbe espéranto signifiant « apprendre » ou encore « étudier ». Vous pouvez penser à « learn » en anglais ou encore « lernen » en allemand.</li>
|
||||
</ul></p>
|
||||
<p>Bref, WikiLerni vous invite à <b>apprendre de nouvelles choses avec Wikipédia !</b><br>
|
||||
Et en lisant ces quelques lignes, vous venez peut-être déjà d'apprendre quelque chose :-)</p>
|
||||
|
||||
<h2>À qui s'adresse WikiLerni ?</h2>
|
||||
|
||||
<p class="engraved">À toute personne curieuse aimant apprendre de nouvelles choses !<br>
|
||||
Contrairement à d'autres sites de quiz testant votre culture générale, WikiLerni ne vous demande pas d'être déjà très "savants", même si vous l'êtes forcément, au moins dans certains domaines. Si ! Si !<br>
|
||||
Vous êtes ici pour apprendre et toutes les réponses aux questions des quizs se trouvent dans l'article qui vous est proposé à la lecture.<br>
|
||||
C'est donc une façon ludique d'apprendre de nouvelles choses sur des sujets auxquels vous ne vous seriez peut-être jamais intéressé par vous-même.</p>
|
||||
|
||||
<h2>Est-il nécessaire de créer un compte pour utiliser WikiLerni ?</h2>
|
||||
|
||||
<p class="engraved">Non, vous pouvez parcourir librement WikiLerni sans avoir besoin d'être connecté au site.<br>
|
||||
Votre compte vous permettra de :
|
||||
<ul>
|
||||
<li>Sauvegarder vos résultats aux quizs</li>
|
||||
<li>Recevoir des suggestions de nouvelles lectures, directement par e-mail</li>
|
||||
<li>Faciliter votre navigation via un moteur de recherche interne à WikiLerni</li>
|
||||
<li> + d'autres fonctionnalités à venir...</li>
|
||||
</ul></p>
|
||||
|
||||
<h2>Comment sont sélectionnés les articles proposés par WikiLerni ?</h2>
|
||||
|
||||
<p class="engraved">Tout comme Wikipédia, WikiLerni se veut éclectique.<br>
|
||||
Donc il vous sera proposé des articles sur des sujets très variés : sciences, arts, histoire, littérature, mythologie, géographie, culture populaire, etc.<br>
|
||||
Il n'y aucun sujet qui ne soit pas digne d'intérêt à priori. Seront évités des articles indiqués par Wikipédia comme de faible qualité ou encore sujets à polémique.</p>
|
||||
|
||||
<p class="engraved">Les articles proposés à la lecture peuvent être de longueurs variées.<br>
|
||||
Une estimation de la durée de lecture vous est indiquée sur la page du quiz ou encore dans les e-mails que vous recevez si vous êtes abonné.<br>
|
||||
Vous pourrez ainsi choisir de laisser de côté un article un peu long pour y revenir quand vous aurez plus de temps.</p>
|
||||
|
||||
<p class="engraved">Pour l'instant, les articles proposés sont uniquement francophones.<br>
|
||||
Mais suivant le succès du site, des versions dans d'autres langues pourront être envisagées.<br>
|
||||
Si vous souhaitez vous-même lancer une version dans une autre langue, mais n'avez pas les compétences techniques pour le faire, n'hésitez <a href="/contact.hml">à me contacter</a> pour un éventuel partenariat.</p>
|
||||
|
||||
<h2>Quel lien entre WikiLerni et Wikipédia ?</h2>
|
||||
|
||||
<p class="engraved">Puisque toutes les suggestions de lecture de WikiLerni vous amènent sur Wikipédia, le lien est évident.<br>
|
||||
Pour autant, WikiLerni n'est pas un projet porté par la fondation Wikipédia, ni par une de ses associations locales, mais est un projet indépendant.<br>
|
||||
Au-delà de ce lien pratique, WikiLerni se veut très proche de l'esprit de Wikipédia en partageant son attrait pour la culture libre et le "libre" en général.
|
||||
L'application faisant fonctionner WikiLerni est un logiciel libre, c'est-à-dire que toute personne peut l'utiliser, étudier son code, le modifier, le distribuer selon son souhait.<br>Ceci est également vrai pour le graphisme du site et les quizs eux-mêmes : texte d'introduction, questions/réponses, illustrations... Sauf exceptions indiquées.</p>
|
||||
|
||||
<h2>Est-ce que WikiLerni est gratuit ?</h2>
|
||||
|
||||
<p class="engraved">Oui.. et non ! Réponse de normand venant d'un breton ? :-)<br>Vous pouvez tout à fait parcourir WikiLerni, lire les articles proposés et répondre aux quizs.<br>
|
||||
Tout cela se fait sans avoir besoin de vous abonner et donc gratuitement.<br>Par contre, si vous souhaitez garder vos résultats, recevoir par mail de nouvelles suggestions de lectures... vous devrez vous abonner au site.<br>Vous pourrez alors tester gratuitement l'abonnement pendant une période de découverte.<br>Ensuite, vous serez invité à souscrire à un abonnement, mais à un prix "libre", c'est-à-dire que différentes possibilités vous seront proposées.<br>Tout le monde n'a pas les mêmes moyens, ni le même intérêt pour le WikiLerni, donc à vous de choisir en conscience.<br>
|
||||
Vous aimez WikiLerni, mais ne pouvez vraiment pas payer pour ce service ? <a href="/contact.html">Contactez-moi</a>. Vous n'avez pas à vous justifier.<br>
|
||||
De même, si aucune des options ne vous convient ou encore si vous préférez un autre moyen de paiement (chèque, virement...), <a href="/contact.html">contactez-moi</a> pour me dire ce que vous souhaitez.<br>Des abonnements de groupe (famille, écoles, associations...) ou autres formules peuvent aussi être envisagées, dans la mesure où cela sera techniquement possible.<br>Bref, <b>nous sommes ici plus dans l'esprit d'un financement participatif que dans celui d'un abonnement classique</b>.<br>En souscrivant à un abonnement, vous permettez à WikiLerni d'exister.</p>
|
||||
|
||||
<h2>À quoi va servir l'argent de mon abonnement ?</h2>
|
||||
<p class="engraved">Cet argent va principalement servir à :
|
||||
<ul>
|
||||
<li>Payer les frais techniques liés au site : serveurs, routeurs e-mail, paiement en ligne...</li>
|
||||
<li>Développer le logiciel libre permettant à WikiLerni de fonctionner.</li>
|
||||
<li>Consacrer du temps à sélectionner les articles Wikipédia et préparer les questions.</li>
|
||||
<li>Gérer le site au quotidien : répondre à vos courriels, communiquer, etc.</li>
|
||||
</ul></p>
|
||||
<p class="engraved"><b>Tout cela sans vous imposer de publicités ou faire commerce de vos données personnelles.</b><br>
|
||||
Par ailleurs, une partie des bénéfices nets de WikiLerni seront distribués sous forme de dons à l'<a href="https://www.wikimedia.fr/" target="_blank">association Wikimédia France</a> et aux développeurs des logiciels libres utilisés par WikiLerni.<br>Je parle de bénéfices "nets", car au-delà des frais de fonctionnement, mon activité étant déclarée, il faut y soustraire TVA, cotisations, etc.<br><br>
|
||||
<b>Pas de publicité, respect de vos données personnelles, activité déclarée en France... cela change, non ?</b></p>
|
||||
|
||||
<h2>Comment puis-je aider WikiLerni ?</h2>
|
||||
|
||||
<p class="engraved">Tout d'abord en l'utilisant et <a href="/contact.html">me retournant</a> vos éventuelles remarques/suggestions.<br>
|
||||
Un bug ? Une erreur d'orthographe ? Une suggestion de fonctionnalité ? Quelque chose que vous ne comprenez pas ? N'hésitez pas à me le dire, cela m'intéresse.<br>
|
||||
Ensuite, si vous avez les moyens, vous pouvez souscrire un abonnement payant pour permettre au projet de perdurer.<br>
|
||||
Et WikiLerni n'ayant pas les moyens des grandes sociétés pour communiquer, vous pouvez aussi en parler autour de vous, en ligne ou dans la vie de tous les jours. <b>
|
||||
Vous le savez sans doute, rien ne vaut le bouche à oreille !</b><br>
|
||||
Un système de parrainage est d'ailleurs prévu pour vous récompenser : à chaque fois qu'une personne inscrite en vous désignant comme "parrain" souscrit un abonnement payant, votre propre abonnement se trouve prolongé de 30 jours.</p>
|
||||
|
||||
<h2><a class="button cardboard" href="/inscription.html">Tester gratuitement</a></h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
front/public/accueil.html
Normal file
79
front/public/accueil.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Page d'accueil de l'abonné.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Mon WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/homeUser.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 871px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 870px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/home.css" media="screen and (min-width: 751px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/home-mobile.css" media="screen and (max-width: 750px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/menu.css" media="screen and (min-width: 751px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/menu-mobile.css" media="screen and (max-width: 750px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="crash"></div>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<ul id="menu" class="cardboard">
|
||||
<li><a href="/accueil.html">MON WIKILERNI</a></li>
|
||||
<li><a href="/compte.html#infos" title="Email, mot de passe">Mes informations</a></li>
|
||||
<li><a href="/compte.html#subscribe" class="pure-menu-link">Mon abonnement</a></li>
|
||||
<li><a href="/sortie.html" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div id="home" class="cardboard">
|
||||
<img id="logo" src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" />
|
||||
<div id="message" class="cardboard"></div>
|
||||
|
||||
<h2>Chercher un quiz</h2>
|
||||
<form id="search" method="POST">
|
||||
<input id="searchQuestionnaires" type="text" name="searchQuestionnaires" placeholder="Votre recherche" class="cardboard" />
|
||||
<input id="begin" type="hidden" name="begin" value="0">
|
||||
<input type="submit" value="Chercher" class="cardboard" />
|
||||
<div class="line"><input type="checkbox" id="onlyAnswers" name="onlyAnswers" /><div class="checkbox_override"></div> Parmi mes réponses.</div>
|
||||
<div class="line"><button type="button" id="random" class="button cardboard">Au hasard !</button></div>
|
||||
</form>
|
||||
|
||||
|
||||
<h2 id="quizsTitle">Les quizs attendant votre réponse</h2>
|
||||
<div id="quizsIntro"></div>
|
||||
</div>
|
||||
|
||||
<div id="quizs">
|
||||
<div id="quizsList"></div>
|
||||
<nav id="pagination"><div id="previous"></div><div id="next"></div></nav>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
46
front/public/aurevoir.html
Normal file
46
front/public/aurevoir.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Validation de la suppression de votre compte</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/deleteValidation.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
<h1 class="cardboard">Validation de la suppression de votre compte</h1>
|
||||
<div id="response"><p class="error">Si vous voyez ce message, c'est que votre lien de validation n'est pas valide ou a expiré. Vous pouvez <a href="/compte.html">en demander un nouveau en cliquant ici</a>.</p></div>
|
||||
</div>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
168
front/public/compte.html
Normal file
168
front/public/compte.html
Normal file
@ -0,0 +1,168 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Mon compte WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/accountUser.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 871px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 870px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/account.css" media="screen and (min-width: 990px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/account-mobile.css" media="screen and (max-width: 989px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/menu.css" media="screen and (min-width: 751px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/menu-mobile.css" media="screen and (max-width: 750px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="crash"></div>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<ul id="menu" class="cardboard">
|
||||
<li><a href="/accueil.html">MON WIKILERNI</a></li>
|
||||
<li><a href="/compte.html#infos" title="Email, mot de passe">Mes informations</a></li>
|
||||
<li><a href="/compte.html#subscribe" class="pure-menu-link">Mon abonnement</a></li>
|
||||
<li><a href="/sortie.html" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="account" class="cardboard">
|
||||
<h1 class="cardboard" id="infos">Votre compte WikiLerni</h1>
|
||||
<div id="message"></div>
|
||||
<form id="accountUpdate" method="POST">
|
||||
<fieldset><label for="name">Nom ou pseudo</label><input id="name" type="text" name="name" class="cardboard"></fieldset>
|
||||
<fieldset><label for="email">Email</label><input id="email" type="email" name="email" class="cardboard">
|
||||
<div id="emailMessage"></div></fieldset>
|
||||
<fieldset><label for="newPassword">Nouveau mot de passe</label><input id="newPassword" type="password" name="newPassword" class="cardboard">
|
||||
<div id="newPasswordMessage"><span class="info">Laisser vide sauf si vous souhaitez le changer.</span></div></fieldset>
|
||||
<div class="framed">
|
||||
<p>Par défaut un nouveau quiz vous est proposé tous les jours. Vous pouvez préciser ci-dessous les jours souhaités.</p>
|
||||
<ul class="checkbox_list">
|
||||
<li class="checkbox_li">
|
||||
<label for="d2" class="check"><input type="checkbox" id="d2" name="d2" value="true" /><div class="checkbox_override"></div> Lundi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d3" class="check"><input type="checkbox" id="d3" name="d3" value="true" /><div class="checkbox_override"></div> Mardi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d4" class="check"><input type="checkbox" id="d4" name="d4" value="true" /><div class="checkbox_override"></div> Mercredi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d5" class="check"><input type="checkbox" id="d5" name="d5" value="true" /><div class="checkbox_override"></div> Jeudi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d6" class="check"><input type="checkbox" id="d6" name="d6" value="true" /><div class="checkbox_override"></div> Vendredi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d7" class="check"><input type="checkbox" id="d7" name="d7" value="true" /><div class="checkbox_override"></div> Samedi.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="d1" class="check"><input type="checkbox" id="d1" name="d1" value="true" /><div class="checkbox_override"></div> Dimanche.</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="checkbox_list">
|
||||
<li class="checkbox_li">
|
||||
<label for="noticeOk" class="check"><input type="checkbox" id="noticeOk" name="noticeOk" value="true" /><div class="checkbox_override"></div> Je souhaite recevoir les nouveaux quizs par email.</label>
|
||||
</li>
|
||||
<li class="checkbox_list">
|
||||
<label for="newsletterOk" class="check"><input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /><div class="checkbox_override"></div> J'accepte de recevoir d'autres messages ponctuels de WikiLerni (nouvelles fonctionnalités ...).</label>
|
||||
</li>
|
||||
<li class="checkbox_list">
|
||||
<label for="deleteOk" class="check"><input type="checkbox" id="deleteOk" name="deleteOk" value="true" /><div class="checkbox_override"></div> <span class="error">Je souhaite supprimer mon compte utilisateur.</span></label>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<div class="input_wrapper"><input type="submit" value="Valider" class="cardboard" id="submitDatas" /></div>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
|
||||
<h1 class="cardboard" id="subscribe">Votre abonnement</h1>
|
||||
<div id="subscribeIntro"></div>
|
||||
<!--<div class="info">Pour l'instant le paiement en ligne n'est pas encore possible.</div>-->
|
||||
<ul class="checkbox_list">
|
||||
<li class="checkbox_li">
|
||||
<label for="abo12" class="check"><input type="checkbox" id="abo12" name="abo12" value="true" /><div class="checkbox_override"></div> J'accepte de payer <b>1 € TTC/mois</b>, soit 12 € TTC.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="abo24" class="check"><input type="checkbox" id="abo24" name="abo24" value="true" /><div class="checkbox_override"></div> J'accepte de payer <b>2 € TTC/mois</b>, soit 24 € TTC.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="abo60" class="check"><input type="checkbox" id="abo60" name="abo60" value="true" /><div class="checkbox_override"></div> J'accepte de payer <b>5 € TTC/mois</b>, soit 60 € TTC.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="abo120" class="check"><input type="checkbox" id="abo120" name="abo120" value="true" /><div class="checkbox_override"></div> J'accepte de payer <b>10 € TTC/mois</b>, soit 120 € TTC.</label>
|
||||
</li>
|
||||
|
||||
<li class="checkbox_li">
|
||||
<label for="CGVOk" class="check" title="Vous devez d'abord choisir le montant de votre abonnement."><input type="checkbox" id="CGVOk" name="CGVOk" value="true" /><div class="checkbox_override"></div> <span class="info">J'ai lu et accepte les <a href="/CGV-CGU.html" target="_blank" rel="noopener">Condition Générales de Vente</a> (obligatoire).</span></label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="WPBtns">
|
||||
<script type="text/javascript">
|
||||
const userWP=JSON.parse(localStorage.getItem("user"));
|
||||
var paiement_ref = ""+userWP.id;// d'après test, doit être une chaîne pour que cela fonctionne.
|
||||
</script>
|
||||
<div id="WPBtn12" class="needJS">
|
||||
<h4>Paiement de votre abonnement annuel prémium à 12 € TTC/an.</h4>
|
||||
<script type="text/javascript" src="https://paiementsecurise.info/S-pan64po51vmnscc5-pBVw3HZ84GScLeOJ.js"></script>
|
||||
</div>
|
||||
<div id="WPBtn24" class="needJS">
|
||||
<h4>Paiement de votre abonnement annuel prémium à 24 € TTC/an.</h4>
|
||||
<script type="text/javascript" src="https://paiementsecurise.info/S-pan64po51vmnscc5-uKIw8rfTVVuEbBJI.js"></script>
|
||||
</div>
|
||||
<div id="WPBtn60" class="needJS">
|
||||
<h4>Paiement de votre abonnement annuel prémium à 60 € TTC/an.</h4>
|
||||
<script type="text/javascript" src="https://paiementsecurise.info/S-pan64po51vmnscc5-f5NsL6A4p1tGBC1G.js"></script>
|
||||
</div>
|
||||
<div id="WPBtn120" class="needJS">
|
||||
<h4>Paiement de votre abonnement annuel prémium à 120 € TTC/an.</h4>
|
||||
<script type="text/javascript" src="https://paiementsecurise.info/S-pan64po51vmnscc5-xDfE3jccOP4bwQFL.js"></script>
|
||||
</div>
|
||||
<p class="success">En cliquant sur le bouton de paiement, vous serez dirigé vers l'outil de facturation et de paiement en ligne.<br>Lors de votre premier abonnement, <b>vous devrez y créer un compte client qui est distinct de votre compte utilisateur WikiLerni</b>. Vous pouvez y utiliser un mot de passe différent. <br>Les années suivantes, lors de vos renouvellements, vous pourrez vous reconnecter à ce compte client.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<h3>Prix libre ?</h3>
|
||||
<p>WikiLerni pratique le "prix libre", c'est-à-dire que <b>vous pouvez choisir quel montant vous êtes prêt à payer pour continuer à utiliser WikiLerni</b>.</p>
|
||||
<p>Cependant, <b>il ne s'agit pas vraiment d'un don</b>, car sans ce financement participatif, <b>le site WikiLerni cessera son activité</b> et vous ne pourrez donc plus l'utiliser.</p>
|
||||
<p>Vous pouvez donc choisir en conscience ce que vous pouvez et souhaitez payer cette année pour WikiLerni, sachant que <b>ce choix ne vous engagera pas pour les futurs renouvellements</b>.</p>
|
||||
<p>Une fois sélectionné le montant qui vous convient, il vous faudra <b>cocher la case de validation des Conditions Générales de Vente</b>, pour voir apparaître un bouton de paiement qui vous mènera <b>sur l'outil de facturation et paiement en ligne de la société WebPortage</b>.</p>
|
||||
<p>Vous aimez WikiLerni, mais ne pouvez vraiment pas payer ? Vous préférez un autre montant ou un autre moyen de paiement (chèque, virement) ? Ou encore vous avez besoin d'explications ? Alors <a href="/contact.html">contactez-moi</a>. <b>Je me ferai un plaisir de vous répondre et d'essayer de m'adapter à chaque situation</b>.</p>
|
||||
</div>
|
||||
|
||||
<h1 class="cardboard" id="godfather">Les utilisateurs que vous avez parrainés</h1>
|
||||
<div class="engraved framed">
|
||||
<p>Vous pouvez parrainer d'autres utilisateurs. Pour ce faire, demandez-leur de saisir lors de l'inscription votre adresse e-mail <strong id="godfatherEmail"></strong> ou encore le code suivant : <strong id="godfatherCode"></strong>.</p>
|
||||
<p>À chaque fois qu'un utilisateur que vous avez parrainé <b>souscrit ou renouvelle un abonnement payant</b>, son abonnement comme le vôtre <b>se trouve prolongé gratuitement de 30 jours</b>. Cet avantage restera valable tant que cet utilisateur et vous-mêmes garderez votre compte WikiLerni.</p>
|
||||
</div>
|
||||
<p id="godchilds"><b>Pour l'instant, aucune personne ne s'est inscrite, en vous désignant comme "parrain".</b></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
85
front/public/connexion.html
Normal file
85
front/public/connexion.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Formulaire de connexion à WikiLerni.">
|
||||
<title>Se connecter à WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/connection.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/login.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/login-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="canonical" href="https://www.wililerni.com/connexion.html">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="login" class="cardboard">
|
||||
|
||||
<h1 class="cardboard">Connectez-vous à WikiLerni</h1>
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript.</noscript>
|
||||
<p class="engraved framed">Pas de compte WikiLerni ? <a href="/inscription.html">créez-le ici</a>.</p>
|
||||
<div id="message"></div>
|
||||
<form class="needJS" id="connection" method="POST">
|
||||
<fieldset>
|
||||
<label for="email">Email :</label><input id="email" type="email" name="email" placeholder="Adresse e-mail utilisée pour ce site" class="cardboard"required>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<label for="password">Mot de passe :</label>
|
||||
<input id="password" type="password" name="password" placeholder="Votre mot de passe" class="cardboard">
|
||||
<div id="passwordMessage" class="cardboard"><i>Oublié ? Alors laissez vide et cochez la case ci-dessous.</i></div>
|
||||
</fieldset>
|
||||
|
||||
<ul class="checkbox_li">
|
||||
<li class="checkbox_li">
|
||||
<label for="getLoginLink" class="check"><input type="checkbox" id="getLoginLink" name="getLoginLink" value="true" /><div class="checkbox_override"></div> Je préfère recevoir un lien de connexion par e-mail.</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="keepConnected" class="check"><input type="checkbox" id="keepConnected" name="keepConnected" value="true" /><div class="checkbox_override"></div> Je souhaite ne pas avoir à me connecter à chaque fois.</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="input_wrapper">
|
||||
<input id="submitDatas" type="submit" value="Valider" class="cardboard" />
|
||||
</div>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
|
||||
<div class="framed">
|
||||
<h2>Besoin d'aide?</h2>
|
||||
<p class="engraved">Si vous avez oublié votre mot de passe, il vous suffit de cocher la case "Je souhaite recevoir un lien de connexion par e-mail". Un lien valide pendant une courte durée vous permettra de vous connecter au site.</p>
|
||||
<p class="engraved">Si vous ne vous souvenez pas non plus de l'adresse e-mail utilisée sur ce site ou que vous n'y avez plus accès, vous pouvez <a href="/contact.html">nous contacter</a> en fournissant des informations permettant de vous identifier.</p>
|
||||
<p class="engraved">La case "Je souhaite ne pas avoir à me connecter à chaque fois." vous permettra de rester connecté.e jusqu'à 6 mois, pour peu que vous utilisiez le même navigateur internet.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
53
front/public/contact.html
Normal file
53
front/public/contact.html
Normal file
@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni : page de contact</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="page" class="cardboard">
|
||||
<div class="framed">
|
||||
<p>Pour me contacter, le plus simple est de m'écrire sur l'adresse suivante : <a href="mailto:bonjour@wikilerni.com">bonjour@wikilerni.com</a><br>J'essayerai de vous répondre au plus tôt.</p>
|
||||
<p>Je vous conseille d'ailleurs <b>d'ajouter cette adresse à votre carnet d'adresse</b>.<br>Cela limitera le risque que les messages de WikiLerni finissent dans votre dossier "spam", voire soient complètement bloqués ...</p>
|
||||
<p>Si vous souhaitez échanger par téléphone, merci d'indiquer vos coordonnées téléphoniques, ainsi que les créneaux horaires où vous êtes généralement disponibles.</p>
|
||||
<p>D'une manière générale, <b>merci de préciser votre demande dans votre message !</b> Ma boule de cristal fonctionne fort mal :)</p>
|
||||
<p>Si vous êtes adepte du chiffrement de e-mails, vous pouvez <a href="/WikiLerni-pub.asc">télécharger ma clé OpenPGP publique</a>.<br>Si vous ne savez pas de quoi il s'agit, ne vous en préoccupez pas, mais je sais que les intéressés apprécieront :)</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
59
front/public/credits.html
Normal file
59
front/public/credits.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Qui est à l'origine de WikiLerni et de son contenu ? Quels sont vos droits d'utilisation ?">
|
||||
<title>Qui sont les créateurs de WikiLerni et avec quelles licences ?</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="canonical" href="https://www.wililerni.com/credits.html">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="page" class="cardboard">
|
||||
<div class="framed engraved">
|
||||
<p>Le logiciel servant à faire fonctionner WikiLerni est un logiciel libre. J'en suis le créateur et pour l'instant le principal développeur. Je me nomme Fabrice PENHOËT et pour en savoir plus sur moi, vous pouvez <a href="https://cv.le-fab-lab.com/">consulter mon CV en ligne</a>. La licence utilisée est la GNU GENERAL PUBLIC LICENSE (GNU/GPLv3) dont vous pouvez lire <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" rel="licence">la version officielle</a> (en anglais). Pour des explications en français, évidemment, <a href="https://fr.wikipedia.org/wiki/Licence_publique_g%C3%A9n%C3%A9rale_GNU">Wikipédia y consacre un article</a> !</p>
|
||||
|
||||
<p>Le graphisme du site est la création de <a href="https://denissalem.tuxfamily.org/">Denis SALEM</a>. Les éléments graphiques sont soumis à la licence <a href="https://creativecommons.org/licenses/by-sa/2.0/fr" rel="licence">CC-By-SA</a>. La partie logicielle (CSS...) étant de nouveau soumise à la licence GNU/GPLv3.</p>
|
||||
|
||||
<p>Les textes du site, et notamment les quizs et leur introduction sont eux-mêmes libres. Cette fois, la licence utilisée est la <a href="https://creativecommons.org/licenses/by-sa/3.0/deed.fr" rel="licence">CC BY-SA 3.0</a>, par cohérence avec celle utilisée par Wikipédia.
|
||||
|
||||
<p>Les illustrations du site, notamment celles des quizs viennent principalement de Wikipédia. Les licences d'utilisation sont variables et un lien est généralement fourni. Les extraits des articles Wikipédia sont eux soumis à la licence <a href="https://creativecommons.org/licenses/by-sa/3.0/deed.fr" rel="licence">CC BY-SA 3.0</a>.</p>
|
||||
|
||||
<p>Si vous avez des doutes sur ce que vous pouvez faire ou pas du contenu de WikiLerni, n'hésitez pas <a href="/contact.html">à me demander</a>.<br>De même, si le logiciel utilisé par WikiLerni vous intéresse pour vos propres projets, mais que vous avez besoin d'aide pour le prendre en main, je peux vous fournir un devis sur demande.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
101
front/public/donnees.html
Normal file
101
front/public/donnees.html
Normal file
@ -0,0 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Tout savoir sur ce que WikiLerni fait de vos données personnelles : abonnements, sauvegardes, paiement en ligne, etc.">
|
||||
<title>WikiLerni et vos données personnelles</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/pages-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="canonical" href="https://www.wililerni.com/donnees.html">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="page" class="cardboard">
|
||||
|
||||
<div class="framed">
|
||||
<p class="engraved">CNIL, RGPD... aujourd'hui toutes les organisations souhaitent montrer patte blanche quant au bon usage qu'elles font de vos données personnelles.<br>Cela avec plus ou moins de sincérité et de pédagogie. Ici, je vous explique quelles données sont traitées par WikiLerni et pourquoi.<br>Néanmoins, pour la responsabilité légale du site, merci de vous reporter <a href="/CGV-CGU.html">aux CGU & CGV du site</a> qui sont les seuls textes valables.</p>
|
||||
|
||||
<h2>Les données liées à votre abonnement</h2>
|
||||
|
||||
<p class="engraved">Lorsque vous créez votre compte, vous devez choisir <b>un pseudonyme</b> qui est complètement libre, donc vous n'êtes pas obligé de saisir votre vrai nom.</p>
|
||||
|
||||
<p class="engraved">De même, <b>votre adresse e-mail</b> est libre. Vous devez juste y avoir accès pour pouvoir valider la création de votre compte.<br>
|
||||
Pour l'instant, WikiLerni ne bloque pas les adresses e-mail jetables. Toutefois, sachez qu'elles peuvent fragiliser la sécurité de votre compte.<br>
|
||||
Par ailleurs, certains fournisseurs d'adresses e-mail rejettent sytématiquement les courriels venant de sites internet et vous ne pourrez donc pas valider votre compte, etc. Ce n'est pas un choix de WikiLerni.</p>
|
||||
|
||||
<p class="engraved">Le <b>mot de passe</b> que vous choisissez est évidemment chiffré. Personne n'y a accès et je ne pourrai donc vous le redonner si vous l'avez oublié.<br>
|
||||
Mais vous pouvez vous connecter sans mot de passe en demandant à recevoir sur votre adresse e-mail un lien valable pendant une courte durée.</p>
|
||||
|
||||
<p class="engraved">En résumé, je peux donc accéder à votre e-mail, le pseudonyme que vous avez choisi, ainsi que quelques informations telles que les dates de création/modification de vos informations ou encore la date de votre dernière connexion au site. Ceci est utile au bon fonctionnement du site.</p>
|
||||
|
||||
<p class="engraved">J'ai aussi évidemment accès aux informations concernant votre abonnement (durée de votre abonnement, jours où vous souhaitez recevoir de nouveaux quizs, période de pauses, etc.). De nouveau, il s'agit d'informations nécessaires au site et que vous pouvez modifier vous-mêmes.</p>
|
||||
|
||||
<p class="engraved"><b>Lorsque que vous supprimez votre compte, toutes les données sont supprimées immédiatement et définitivement.</b><br>
|
||||
De même, si vous n'avez plus d'abonnement actif et que vous ne vous connectez pendant un certain nombre de mois, votre compte et ses informations sont supprimés définitivement.</p>
|
||||
|
||||
<p class="engraved">En fait, vos données peuvent toujours apparaître un certain temps dans les sauvegardes du site, mais ne comptez pas dessus pour récupérer votre compte après une suppression. Ses sauvegardes existent pour permettre de remettre en route l'ensemble du site en cas d'incident.</p>
|
||||
|
||||
<p class="engraved">Il existe quelques informations vous concernant auxquelles vous n'avez pas directement accès.<br>Le <b>décalage horaire de votre compte</b> qui est détecté périodiquement lorsque vous vous connectez au site. En effet, pour WikiLerni vous envoi en général ces messages durant la nuit, mais l'heure n'est pas la même suivant si vous habitez en Nouvelle-Calédonie ou en métropole.<br>Un champ mémo me permet d’enregistrer des données libres concernant votre compte. Il est vide dans 99 % des cas et ne contient rien de personnel. Mais vous pouvez me demander cette information si vous le souhaitez.</p>
|
||||
|
||||
<h2>Les prestataires</h2>
|
||||
|
||||
<p class="engraved">Le site WikiLerni est hébergé sur un serveur situé en France et appartenant à une entreprise elle-même française (alwaysdata).</p>
|
||||
|
||||
<p class="engraved">Pour envoyer ses e-mails en essayant d'éviter de se retrouver en "spam", WikiLerni utilise les services d'un routeur e-mail.<br>
|
||||
De nouveau, il s'agit d'une société française (Spirion), ses serveurs étant eux-mêmes situés en France (OVH) au moment où j'écris ce texte. Je l'ai choisie pour ça.<br>
|
||||
Donc, en théorie, ce prestataire peut avoir accès à votre adresse e-mail, mais à aucune autre information.<br>
|
||||
Il n'y aucun pistage des affichages ou clics des messages envoyés par WikiLerni, ce qui est chose rare !</p>
|
||||
<h2>Les données de facturation</h2>
|
||||
|
||||
<p class="engraved">Si vous optez pour un abonnement prémium, vous devrez passer par le site de la société WebPortage/Nodalys qui est une société de portage salarial me permettant d'avoir une activité déclarée en France. Les employés de Nodalys ont donc accès à vos données de facturation et paiement. Pour en savoir plus sur ce sujet <a href="https://www.webportage.com/protection-donnees-cookies">cliquez-ici</a>.</p>
|
||||
|
||||
<p class="engraved">Ce logiciel de facturation est séparé de WikiLerni, tout comme ceux de Paypal ou Paybox qui vous permettrons de payer votre abonnement en ligne.
|
||||
Si vous souhaitez éviter de passer par Paypal ou Paybox, vous pouvez me contacter pour demander un paiement par chèque ou virement.</p>
|
||||
<h2>Les statistiques de visite</h2>
|
||||
|
||||
<p class="engraved">Lorsque l'on gère un site internet, il est difficile de naviguer complètement à vue et avoir certaines informations sur les visites de son site est utile.
|
||||
Pour ce faire WikiLerni privilégie en toute cohérence un logiciel libre nommé Matomo.<br>
|
||||
Ce logiciel est configuré conformément aux préconisations de la CNIL, c'est-à-dire entre autres pour ne pas collecter votre adresse IP, qui est une information permettant de vous identifier sur internet.<br>
|
||||
Par ailleurs, Matomo est inactif lorsque vous êtes connecté à votre compte WikiLerni.<br>
|
||||
Cet outil est installé sur un serveur internet situé en France et je suis la seule personne à avoir accès à ces informations.</p>
|
||||
|
||||
<p class="engraved">Si vous souhaitez vous opposer à ce suivi statistique, vous pouvez utiliser le lien suivant :<br>
|
||||
<iframe src="https://stats.le-fab-lab.com/index.php?module=CoreAdminHome&action=optOut&language=fr" style="border: 0; height: 200px; width: 600px;"></iframe></p>
|
||||
|
||||
<p class="engraved"><b>Pour toutes questions/réclamations concernant vos données personnelles sur WikiLerni, <a href="/contact.html">n'hésitez pas à me contacter</a></b>.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
261
front/public/gestion-quizs.html
Normal file
261
front/public/gestion-quizs.html
Normal file
@ -0,0 +1,261 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Saisie et mise à jour des quizs">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Les quizs</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/manageQuestionnaires.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion-quizs.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center" id="infos">Les quizs</h2>
|
||||
|
||||
<form class="pure-form pure-u-1" id="search" method="POST">
|
||||
<fieldset>
|
||||
<legend>Chercher un quiz</legend>
|
||||
<input id="searchQuestionnaires" type="txt" name="searchQuestionnaires" placeholder="Votre recherche">
|
||||
<button type="submit" class="pure-button pure-button-primary">Chercher</button>
|
||||
<div id="searchResult"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned" id="questionnaires" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations du quiz</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="title">Titre</label>
|
||||
<input id="title" type="text" name="title">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="slug">Page html</label>
|
||||
<input id="slug" type="text" name="slug">.html
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="introduction">Introduction</label>
|
||||
<textarea id="introduction" name="introduction" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="keywords">Mots-clés</label>
|
||||
<textarea id="keywords" name="keywords" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="publishingAt">Date de publication</label>
|
||||
<input id="publishingAt" type="date" name="publishingAt"> <span class="information" id="helpPublishingAt"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="estimatedTime">Durée de lecture estimée</label>
|
||||
<select name="estimatedTime" id="estimatedTime">
|
||||
<option value="short">Court</option>
|
||||
<option value="medium">Moyen</option>
|
||||
<option value="long">Long</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="classification">Catégories de classement</label>
|
||||
<input id="classification" type="text" name="classification"> <span class="information" id="helpClassification">Séparer les rubriques par des virgules</span>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="deleteOk" class="pure-checkbox error" id="deleteOkLabel">
|
||||
<input type="checkbox" id="deleteOk" name="deleteOk" value="true" /> Je souhaite supprimer ce quiz
|
||||
</label>
|
||||
<input type="hidden" name="id" id="id" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
<a href="#questionnaires" class="pure-button pure-button-primary needJS" id="wantNewQuestionnaire">Nouveau questionnaire</a>
|
||||
<a href="#questionnaires" class="pure-button pure-button-primary needJS" id="previewQuestionnaire" target=="_blank">Voir le quiz</a>
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div id="linksList" class="needJS"></div>
|
||||
<div id="illustrationsList" class="needJS"></div>
|
||||
<div id="questionsList" class="needJS"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="links" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations du lien</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="url">Url</label>
|
||||
<input id="url" type="url" name="url">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="anchor">Texte du lien</label>
|
||||
<input id="anchor" type="text" name="anchor" value="Lire l'article sur Wikipédia.">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idLink" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdLink" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkLink" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseLink"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="illustrations" method="POST" enctype="multipart/form-data">
|
||||
<fieldset>
|
||||
<legend>Informations de l'illustration</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="image">Sélectionnez le fichier à utiliser</label>
|
||||
<input type="file" id="image" name="image">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="alt">Propriété "alt"</label>
|
||||
<input id="alt" type="text" name="alt">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="title">Propriété "title"</label>
|
||||
<input id="title" type="text" name="title">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="caption">Légende</label>
|
||||
<input id="caption" type="text" name="caption">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idIllustration" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdIllustration" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkIllustration" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseIllustration"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="questions" method="POST">
|
||||
<fieldset>
|
||||
<legend>La question et les réponses proposées</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="text">Question</label>
|
||||
<input id="text" type="text" name="text">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="rank">Rang</label>
|
||||
<input id="rank" type="number" name="rank" value="1"> <span class="information">Permet de fixer l'ordre d'affichage des questions.</span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="explanation">Explications</label>
|
||||
<textarea id="explanation" name="explanation" rows="5"></textarea>
|
||||
</div>
|
||||
<legend>Réponses proposées</legend>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText0" type="text" name="choiceText0" maxlength="255" maxlength="255"> <input type="checkbox" id="choiceIsCorrect0" name="choiceIsCorrect0" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice0" id="idChoice0" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText1" type="text" name="choiceText1" maxlength="255"> <input type="checkbox" id="choiceIsCorrect1" name="choiceIsCorrect1" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice1" id="idChoice1" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText2" type="text" name="choiceText2" maxlength="255"> <input type="checkbox" id="choiceIsCorrect2" name="choiceIsCorrect2" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice2" id="idChoice2" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText3" type="text" name="choiceText3" maxlength="255"> <input type="checkbox" id="choiceIsCorrect3" name="choiceIsCorrect3" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice3" id="idChoice3" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText4" type="text" name="choiceText4" maxlength="255"> <input type="checkbox" id="choiceIsCorrect4" name="choiceIsCorrect4" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice4" id="idChoice4" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText5" type="text" name="choiceText5" maxlength="255"> <input type="checkbox" id="choiceIsCorrect5" name="choiceIsCorrect5" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice5" id="idChoice5" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText6" type="text" name="choiceText6" maxlength="255"> <input type="checkbox" id="choiceIsCorrect6" name="choiceIsCorrect6" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice6" id="idChoice6" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText7" type="text" name="choiceText7" maxlength="255"> <input type="checkbox" id="choiceIsCorrect7" name="choiceIsCorrect7" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice7" id="idChoice7" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText8" type="text" name="choiceText8" maxlength="255"> <input type="checkbox" id="choiceIsCorrect8" name="choiceIsCorrect8" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice8" id="idChoice8" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText9" type="text" name="choiceText9" maxlength="255"> <input type="checkbox" id="choiceIsCorrect9" name="choiceIsCorrect9" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice9" id="idChoice9" value="">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idQuestion" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdQuestion" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkQuestion" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseQuestion"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="l-box-lrg pure-u-1" id="questionnairesList"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li><a href="/CGV-CGU.html">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
206
front/public/gestion-utilisateurs.html
Normal file
206
front/public/gestion-utilisateurs.html
Normal file
@ -0,0 +1,206 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Gestion des abonnés">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Les abonnés</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/manageUsers.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion-utilisateurs.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center" id="infos">Les abonnés</h2>
|
||||
|
||||
<form class="pure-form pure-u-1" id="search" method="POST">
|
||||
<fieldset>
|
||||
<legend>Chercher un utilisateur</legend>
|
||||
<input id="search" type="txt" name="search" placeholder="Votre recherche">
|
||||
<button type="submit" class="pure-button pure-button-primary">Chercher</button>
|
||||
<div id="searchResult"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned" id="users" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations de l'abonné</legend>
|
||||
<div id="subscribeIntro"></div>
|
||||
<div class="pure-control-group">
|
||||
<label for="name">Nom ou pseudo</label>
|
||||
<input id="name" type="text" name="name">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="email">Email</label>
|
||||
<input id="email" type="email" name="email">
|
||||
<span class="pure-form-message-inline" id="emailMessage"></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="status">Statut</label>
|
||||
<select id="status" name="status">
|
||||
<option value="user">Utilisateur</option>
|
||||
<option value="creator">Créateur</option>
|
||||
<option value="manager">Gestionnaire</option>
|
||||
<option value="admin">Administrateur</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="smtp">SMTP</label>
|
||||
<select id="smtp" name="smtp">
|
||||
<option value="0">Spirion</option>
|
||||
<option value="1">Mailjet</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="timeDifference">Décalage horaire</label>
|
||||
<input id="timeDifference" type="number" name="timeDifference" readonly>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="newPassword">Nouveau mot de passe</label>
|
||||
<input id="newPassword" type="password" name="newPassword">
|
||||
<span class="pure-form-message-inline" id="newPasswordMessage"><b class="information">Laisser vide sauf si vous souhaitez le changer.</b></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="adminComments">Commentaires</label>
|
||||
<textarea id="adminComments" name="adminComments" rows="5"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="numberOfDays">Durée totale de l'abonnement</label>
|
||||
<input id="numberOfDays" type="number" name="numberOfDays"><span class="pure-form-message-inline"><i class="information">Depuis la création de son compte.</i></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-controls">
|
||||
Jours valables pour l'abonnement
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-7"><!-- grille ne fonctionne pas ?! -->
|
||||
<label for="d2">
|
||||
<input type="checkbox" id="d2" name="d2" value="true" /> Lundi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d3">
|
||||
<input type="checkbox" id="d3" name="d3" value="true" /> Mardi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d4">
|
||||
<input type="checkbox" id="d4" name="d4" value="true" /> Mercredi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d5">
|
||||
<input type="checkbox" id="d5" name="d5" value="true" /> Jeudi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d6">
|
||||
<input type="checkbox" id="d6" name="d6" value="true" /> Vendredi
|
||||
</label>
|
||||
</li>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d7">
|
||||
<input type="checkbox" id="d7" name="d7" value="true" /> Samedi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d1">
|
||||
<input type="checkbox" id="d1" name="d1" value="true" /> Dimanche
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="noticeOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="noticeOk" name="noticeOk" value="true" /> Reçoit les quizs par email.
|
||||
</label>
|
||||
<label for="newsletterOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /> Reçoit les autres actus par email.
|
||||
</label>
|
||||
<label for="validationOk" class="pure-checkbox success" id="validationOkLabel">
|
||||
<input type="checkbox" id="validationOk" name="validationOk" /> Valider le compte.
|
||||
</label>
|
||||
<label for="deleteOk" class="pure-checkbox error" id="deleteOkLabel">
|
||||
<input type="checkbox" id="deleteOk" name="deleteOk" /> Supprimer le compte
|
||||
</label>
|
||||
<input type="hidden" name="id" id="id" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
<a href="#users" class="pure-button pure-button-primary" id="wantNewUser">Vider</a>
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div id="infosPayments" class="needJS"><h4>Payments reçus via l'API WebPortage</h4></div>
|
||||
<div id="infosGodchilds" class="needJS"><h4>Parrainages</h4></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li><a href="/CGV-CGU.html">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
78
front/public/gestion.html
Normal file
78
front/public/gestion.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Page d'accueil du gestionnaire.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni - gestion du site</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/homeManager.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1" id="message"></div>
|
||||
<div class="l-box-lrg pure-u-1" id="questionnaires"></div>
|
||||
</div>
|
||||
<p><a href="#" class="pure-button pure-button-primary" id="wantRegenerate">Régénérer le HTML.</a></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li><a href="/CGV-CGU.html">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
BIN
front/public/img/404-notfound.png
Normal file
BIN
front/public/img/404-notfound.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
BIN
front/public/img/android-icon-192x192.png
Normal file
BIN
front/public/img/android-icon-192x192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
front/public/img/apple-icon-57x57.png
Normal file
BIN
front/public/img/apple-icon-57x57.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
front/public/img/favicon-32x32.png
Normal file
BIN
front/public/img/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
front/public/img/favicon.ico
Executable file
BIN
front/public/img/favicon.ico
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
94
front/public/inscription.html
Normal file
94
front/public/inscription.html
Normal file
@ -0,0 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Formulaire d'inscription à WikiLerni.">
|
||||
<title>S'inscrire à WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/subscribe.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/signup.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/signup-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="canonical" href="https://www.wililerni.com/inscription.html">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" />
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
</div>
|
||||
|
||||
<div id="signup" class="cardboard">
|
||||
|
||||
<h1 class="cardboard">Créer votre compte WIKILERNI</h1>
|
||||
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript.</noscript>
|
||||
<form class="needJS" id="subscription" method="POST">
|
||||
<fieldset>
|
||||
<label for="name">Nom ou pseudo: </label><input id="name" type="text" name="name" placeholder="Pseudo de votre choix" class="cardboard" >
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<label for="email">Email: </label><input id="email" type="email" name="email" placeholder="Adresse e-mail" class="cardboard">
|
||||
</fieldset>
|
||||
<div id="emailMessage" class="cardboard"></div>
|
||||
|
||||
<fieldset>
|
||||
<label for="password">Mot de passe: </label><input id="password" type="password" name="password" placeholder="Mot de passe de votre choix" class="cardboard">
|
||||
</fieldset>
|
||||
<div id="passwordMessage" class="cardboard"><i>Au moins 8 caractères. <a href="#password" id="getPassword">Générer un mot de passe</a>.</i></div>
|
||||
|
||||
<fieldset>
|
||||
<label for="codeGodfather">Code/e-mail parrainage: </label><input id="codeGodfather" type="text" name="codeGodfather" placeholder="Code ou email de votre parrain." class="cardboard">
|
||||
</fieldset>
|
||||
<div id="codeGodfatherMessage" class="cardboard"><i>Facultatif.</i></div>
|
||||
|
||||
<ul class="checkbox_li">
|
||||
<li class="checkbox_li">
|
||||
<label for="cguOk" class="check"><input type="checkbox" id="cguOk" name="cguOk" value="true" /><div class="checkbox_override"></div> J'accepte <a href="/CGV-CGU.html">les Conditions Générale d'Utilisation</a> du site (requis).</label>
|
||||
</li>
|
||||
<li class="checkbox_li">
|
||||
<label for="newsletterOk" class="check"><input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /><div class="checkbox_override"></div> J'accepte de recevoir les nouveaux quizs WikiLerni par email (facultatif).</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="input_wrapper">
|
||||
<input id="submitDatas" type="submit" value="Valider" class="cardboard" />
|
||||
</div>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
|
||||
<div class="framed">
|
||||
<h2>Besoin d'aide ?</h2>
|
||||
<p class="engraved">La saisie d'un pseudonyme, d'une adresse e-mail et d'un mot de passe <b>est obligatoire</b> et <b>vous devez accepter les Conditions Générales d'Utilisation</b>.</p>
|
||||
<p class="engraved">Votre pseudonyme est complétement libre, mais servira à personnaliser certains affichages.</p>
|
||||
<p class="engraved"><b>Vous recevrez un lien sur l'adresse e-mail saisie</b> sur lequel vous devrez cliquer pour valider la création de votre compte.</p>
|
||||
<p class="engraved"><b>Votre mot de passe doit compter au moins 8 caractères.</b> Si vous manquez d'inspiration, cliquez sur le lien "Générer un mot de passe" pour en obtenir un !</p>
|
||||
<p class="engraved">Si vous connaissez une personne déjà inscrite à WikiLerni, <b>vous pouvez fournir son code parrain ou encore son adresse e-mail</b>. Dans le cas où vous optez ensuite pour un abonnement prémium, il sera alors allongé de 30 jours grâce à ce parrainage.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
45
front/public/login.html
Normal file
45
front/public/login.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Tester votre lien de connexion</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/loginLink.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
<div id="response" class="error">Si vous voyez ce message, c'est que votre lien de connexion n'est pas valide. Vous pouvez <a href="/connexion.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
45
front/public/newlogin.html
Normal file
45
front/public/newlogin.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Lien pour changer vos informations de connexion</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/newLoginValidation.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
<div id="response" class="error">Si vous voyez ce message, c'est que votre lien de validation n'est pas valide ou a expiré. Vous pouvez <a href="/compte.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
2
front/public/robots.txt
Normal file
2
front/public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
46
front/public/sortie.html
Normal file
46
front/public/sortie.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Déconnexion WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/deconnection.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
<h1 class="cardboard">Au revoir !</h1>
|
||||
<div id="response"><p class="error">Si vous voyez ce message, c'est qu'un problème a été rencontré durant la déconnexion.<br>N'hésitez pas <a href="/contact.html">à nous prévenir</a> si le problème persiste.</p></div>
|
||||
</div>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
45
front/public/stop-mail.html
Normal file
45
front/public/stop-mail.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Ne plus recevoir d'e-mail de WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/unsubscribe.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/common-mobile.css" media="screen and (max-width: 969px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page.css" media="screen and (min-width: 970px)">
|
||||
<link rel="stylesheet" href="/themes/wikilerni/css/links-page-mobile.css" media="screen and (max-width: 969px)">
|
||||
</head>
|
||||
|
||||
<body class="cardboard">
|
||||
<!-- En tête -->
|
||||
<header class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-128.png" alt="WikiLerni (logo)" title="Accéder à la page d'accueil de WikiLerni" /></a>
|
||||
<ul id="headLinks">
|
||||
<li><a href="/contact.html" rel="nofollow">Contact</a></li>
|
||||
<li><a href="/quizs/" id="indexHeadLink" title="Les derniers quizs">Parcourir</a></li>
|
||||
<li><a href="/connexion.html" id="accountHeadLink">Mon compte</a></li>
|
||||
<li><a href="/a-propos.html">À propos</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<div id="prompt" class="cardboard">
|
||||
<a href="/" title="Page d'accueil WikLerni"><img src="/themes/wikilerni/img/wikilerni-purple-2-512.png" alt="Logo WikiLerni" title="W I K I L E R N I" /></a>
|
||||
<p class="cardboard">Cultivons notre jardin !</p>
|
||||
<div id="response" class="error">Si vous voyez ce message, c'est que votre lien de désabonnement ne fonctionne pas. Vous pouvez <a href="/compte.html">accéder à votre compte</a> pour désactiver les envois.</div>
|
||||
</div>
|
||||
|
||||
<footer class="cardboard">
|
||||
<ul id="footLinks">
|
||||
<li><a href="https://framasphere.org/people/7e54b7a0b53201389eef2a0000053625" title="Blog WikiLerni sur diaspora*">Blog</a></li>
|
||||
<li><a href="/credits.html">Crédits</a></li>
|
||||
<li><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li>
|
||||
<li><a href="/donnees.html">Données personnelles</a></li>
|
||||
<li><a href="/CGV-CGU.html" rel="nofollow">CGV & CGU</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
80
front/public/themes/default/404.html
Normal file
80
front/public/themes/default/404.html
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="L'erreur est humaine !">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni : page non trouvée</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
<article class="content">
|
||||
<div class="pure-g">
|
||||
<div class="l-box pure-u-1">
|
||||
<h3 class="content-subhead">Page non trouvée !</h3>
|
||||
<p>La page que vous demandez n'a pas été trouvée !<br>
|
||||
Peut-être a-t'elle été supprimée ou déplacée ?</p>
|
||||
</div>
|
||||
<div class="l-box pure-u-1"><a href="/" class="pure-button pure-button-primary">Cliquez-ici pour accéder à la page d'accueil de WikiLerni.</a></div>
|
||||
<div class="l-box pure-u-1">
|
||||
<figure>
|
||||
<img width="512" alt="Illustration : page non trouvée" src="/img/404-notfound.png">
|
||||
<figCaption>Crédit illustration : <a title="coursetakers.ae / CC BY-SA (https://creativecommons.org/licenses/by-sa/4.0)" href="https://commons.wikimedia.org/wiki/File:Found_nothing.png">CC BY-SA coursetakers.ae</a></figCaption>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
7
front/public/themes/default/CSS/grids-responsive-min.css
vendored
Normal file
7
front/public/themes/default/CSS/grids-responsive-min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
286
front/public/themes/default/CSS/layout.css
Normal file
286
front/public/themes/default/CSS/layout.css
Normal file
@ -0,0 +1,286 @@
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- BASE STYLES --
|
||||
* Most of these are inherited from Base, but I want to change a few.
|
||||
*/
|
||||
body {
|
||||
line-height: 1.7em;
|
||||
color: #C1B654;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
label {
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
.pure-img-responsive {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- LAYOUT STYLES --
|
||||
* These are some useful classes which I will need
|
||||
*/
|
||||
.l-box {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.l-box-lrg {
|
||||
padding: 2em;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.is-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* -- PURE FORM STYLES --
|
||||
* Style the form inputs and labels
|
||||
*/
|
||||
.pure-form label {
|
||||
margin: 1em 0 0;
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.pure-form input[type] {
|
||||
border: 2px solid #ddd;
|
||||
box-shadow: none;
|
||||
font-size: 100%;
|
||||
width: 100%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- PURE BUTTON STYLES --
|
||||
* I want my pure-button elements to look a little different
|
||||
*/
|
||||
.pure-button {
|
||||
background-color: #1f8dd6;
|
||||
color: white;
|
||||
padding: 0.5em 2em;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
a.pure-button-primary {
|
||||
background: white;
|
||||
color: #8D847B;
|
||||
border-radius: 5px;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- MENU STYLES --
|
||||
* I want to customize how my .pure-menu looks at the top of the page
|
||||
*/
|
||||
|
||||
.home-menu {
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0, 0.10);
|
||||
}
|
||||
.home-menu {
|
||||
background: #D8AD32;
|
||||
}
|
||||
.pure-menu.pure-menu-fixed {
|
||||
/* Fixed menus normally have a border at the bottom. */
|
||||
border-bottom: none;
|
||||
/* I need a higher z-index here because of the scroll-over effect. */
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.home-menu .pure-menu-heading {
|
||||
color: white;
|
||||
font-weight: 400;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.home-menu .pure-menu-selected a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.home-menu a {
|
||||
color: #8F543B;
|
||||
}
|
||||
.home-menu li a:hover,
|
||||
.home-menu li a:focus {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #8D847B;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- SPLASH STYLES --
|
||||
* This is the blue top section that appears on the page.
|
||||
*/
|
||||
|
||||
.splash-container {
|
||||
background: #FCF6EC;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
/* The following styles are required for the "scroll-over" effect */
|
||||
width: 100%;
|
||||
height: 40%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed !important;
|
||||
}
|
||||
|
||||
.splash {
|
||||
/* absolute center .splash within .splash-container */
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 100px; left: 0; bottom: 0; right: 0;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* This is the main heading that appears on the blue section */
|
||||
.splash-head {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #DDE023;
|
||||
border: 3px solid #DDE023;
|
||||
padding: 1em 1.6em;
|
||||
font-weight: 100;
|
||||
border-radius: 5px;
|
||||
line-height: 0.5em;
|
||||
}
|
||||
|
||||
/* This is the subheading that appears on the blue section */
|
||||
.splash-subhead {
|
||||
color: #8F543B;
|
||||
letter-spacing: 0.05em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- CONTENT STYLES --
|
||||
* This represents the content area (everything below the blue section)
|
||||
*/
|
||||
.content-wrapper {
|
||||
/* These styles are required for the "scroll-over" effect */
|
||||
position: absolute;
|
||||
top: 39%;
|
||||
width: 100%;
|
||||
min-height: 12%;
|
||||
z-index: 2;
|
||||
background: white;
|
||||
|
||||
}
|
||||
|
||||
/* We want to give the content area some more padding */
|
||||
.content {
|
||||
padding: 1em 1em 3em;
|
||||
}
|
||||
|
||||
/* This is the class used for the main content headers (<h2>) */
|
||||
.content-head {
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
|
||||
/* This is a modifier class used when the content-head is inside a ribbon */
|
||||
.content-head-ribbon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* This is the class used for the content sub-headers (<h3>) */
|
||||
.content-subhead {
|
||||
color: #8F543B;
|
||||
}
|
||||
.content-subhead i {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
/* This is the class used for the dark-background areas. */
|
||||
.ribbon {
|
||||
background: #2d3e50;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
/* This is the class used for the footer */
|
||||
.footer {
|
||||
background: #111;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- TABLET (AND UP) MEDIA QUERIES --
|
||||
* On tablets and other medium-sized devices, we want to customize some
|
||||
* of the mobile styles.
|
||||
*/
|
||||
@media (min-width: 48em) {
|
||||
|
||||
/* We increase the body font size */
|
||||
body {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* We can align the menu header to the left, but float the
|
||||
menu items to the right. */
|
||||
.home-menu {
|
||||
text-align: left;
|
||||
}
|
||||
.home-menu ul {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* We increase the height of the splash-container */
|
||||
/* .splash-container {
|
||||
height: 500px;
|
||||
}*/
|
||||
|
||||
/* We decrease the width of the .splash, since we have more width
|
||||
to work with */
|
||||
.splash {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.splash-head {
|
||||
font-size: 250%;
|
||||
}
|
||||
|
||||
|
||||
/* We remove the border-separator assigned to .l-box-lrg */
|
||||
.l-box-lrg {
|
||||
border: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* -- DESKTOP (AND UP) MEDIA QUERIES --
|
||||
* On desktops and other large devices, we want to over-ride some
|
||||
* of the mobile and tablet styles.
|
||||
*/
|
||||
@media (min-width: 78em) {
|
||||
/* We increase the header font size even more */
|
||||
.splash-head {
|
||||
font-size: 300%;
|
||||
}
|
||||
}
|
11
front/public/themes/default/CSS/pure-min.css
vendored
Normal file
11
front/public/themes/default/CSS/pure-min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
352
front/public/themes/default/CSS/wikilerni.css
Normal file
352
front/public/themes/default/CSS/wikilerni.css
Normal file
@ -0,0 +1,352 @@
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- BASE STYLES --
|
||||
* Most of these are inherited from Base, but I want to change a few.
|
||||
*/
|
||||
body
|
||||
{
|
||||
line-height: 1.7em;
|
||||
color: #C1B654;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6,label
|
||||
{
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
.pure-img-responsive
|
||||
{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- LAYOUT STYLES --
|
||||
* These are some useful classes which I will need
|
||||
*/
|
||||
.l-box
|
||||
{
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.l-box-lrg
|
||||
{
|
||||
padding: 2em;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.is-center
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- PURE BUTTON STYLES --
|
||||
* I want my pure-button elements to look a little different
|
||||
*/
|
||||
.pure-button
|
||||
{
|
||||
background-color: #1f8dd6;
|
||||
color: white;
|
||||
padding: 0.5em 2em;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
a.pure-button-primary
|
||||
{
|
||||
background: white;
|
||||
color: #8D847B;
|
||||
border-radius: 5px;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- MENU STYLES --
|
||||
* I want to customize how my .pure-menu looks at the top of the page
|
||||
*/
|
||||
|
||||
.menu
|
||||
{
|
||||
padding: 0.5em;
|
||||
margin-bottom:0;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0, 0.10);
|
||||
background: #D8AD32;
|
||||
}
|
||||
.menu .menu-heading
|
||||
{
|
||||
padding: 0.5em 0 0.5em 0;
|
||||
}
|
||||
.menu .pure-menu-heading
|
||||
{
|
||||
color: white;
|
||||
font-weight: 400;
|
||||
font-size: 120%;
|
||||
}
|
||||
.menu .pure-menu-selected a
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
.menu a
|
||||
{
|
||||
color: #8F543B;
|
||||
}
|
||||
.menu li a:hover, .menu li a:focus
|
||||
{
|
||||
background: none;
|
||||
border: none;
|
||||
color: #8D847B;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
#main-header
|
||||
{
|
||||
background: #FCF6EC;
|
||||
min-height: 20%;
|
||||
padding-top:2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#main-header h1
|
||||
{
|
||||
width:80%;
|
||||
margin:auto;
|
||||
border: 3px solid #DDE023;
|
||||
border-radius: 5px;
|
||||
padding: 1em 1.6em;
|
||||
font-size:20px;
|
||||
font-weight: bold;
|
||||
color: #DDE023;
|
||||
font-weight: 100;
|
||||
line-height: 0.5em;
|
||||
}
|
||||
|
||||
#main-header p
|
||||
{
|
||||
color: #8F543B;
|
||||
letter-spacing: 0.05em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- PURE BUTTON STYLES --
|
||||
* I want my pure-button elements to look a little different
|
||||
*/
|
||||
.pure-button {
|
||||
background-color: #1f8dd6;
|
||||
color: white;
|
||||
padding: 0.5em 2em;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
a.pure-button-primary {
|
||||
background: white;
|
||||
color: #8D847B;
|
||||
border-radius: 5px;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#quizsPagination a
|
||||
{
|
||||
background: #E7DEDE;
|
||||
color: #7F7F7F;
|
||||
border-radius: 5px;
|
||||
font-size: 130%;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
/* We want to give the content area some more padding */
|
||||
.content
|
||||
{
|
||||
padding: 1em 1em 3em;
|
||||
}
|
||||
|
||||
/* This is the class used for the main content headers (<h2>) */
|
||||
.content-head
|
||||
{
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin: 2em 0 1em;
|
||||
}
|
||||
|
||||
/* This is a modifier class used when the content-head is inside a ribbon */
|
||||
.content-head-questionnaire
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* This is the class used for the dark-background areas. */
|
||||
.questionnaire-listed, .questionnaire-intro
|
||||
{
|
||||
background: #2d3e50;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.questionnaire-intro img
|
||||
{
|
||||
max-height:500px;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.questionnaire-listed img
|
||||
{
|
||||
max-height:200px;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
nav#pagination
|
||||
{
|
||||
clear:both;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- PURE FORM STYLES --
|
||||
* Style the form inputs and labels
|
||||
*/
|
||||
.pure-form
|
||||
{
|
||||
width:90%;
|
||||
margin-left:1em;
|
||||
}
|
||||
.pure-form label
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.pure-form input[type]
|
||||
{
|
||||
border: 2px solid #ddd;
|
||||
box-shadow: none;
|
||||
font-size: 100%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.error
|
||||
{
|
||||
color: rgb(202, 60, 60);
|
||||
}
|
||||
.success
|
||||
{
|
||||
color: rgb(28, 184, 65);
|
||||
}
|
||||
.information
|
||||
{
|
||||
color: rgb(66, 184, 221);
|
||||
}
|
||||
#helpClassification a
|
||||
{
|
||||
margin-right:1em;
|
||||
}
|
||||
|
||||
.needJS
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#links
|
||||
{
|
||||
margin:1em 0;
|
||||
}
|
||||
#response
|
||||
{
|
||||
margin:0.5em 1em;
|
||||
padding:0.5em;
|
||||
}
|
||||
|
||||
/* Bouton permettant de demander l'affichage du quiz */
|
||||
#showQuestionnaire
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
|
||||
/* Boutons inscription/connexion suite réponse quiz */
|
||||
.subcribeBtns
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
.subcribeBtns .pure-button
|
||||
{
|
||||
background-color: #1f8dd6;
|
||||
color: white;
|
||||
font-size: 1.1em;
|
||||
margin:0 0.5em;
|
||||
}
|
||||
.accountBtns .pure-button
|
||||
{
|
||||
background-color: #1f8dd6;
|
||||
color: white;
|
||||
font-size: 1.1em;
|
||||
margin:0 0.5em;
|
||||
}
|
||||
|
||||
.quizs, .help
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#main-content
|
||||
{
|
||||
padding-bottom:3em;
|
||||
}
|
||||
|
||||
.footer
|
||||
{
|
||||
background: #111;
|
||||
width: 100%;
|
||||
}
|
||||
.footer a
|
||||
{
|
||||
color:white;
|
||||
font-weight:normal;
|
||||
}
|
||||
.footer ul
|
||||
{
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.fab, .fas, .far
|
||||
{
|
||||
margin-right:0.5em;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- TABLET (AND UP) MEDIA QUERIES --
|
||||
* On tablets and other medium-sized devices, we want to customize some
|
||||
* of the mobile styles.
|
||||
*/
|
||||
@media (min-width: 48em)
|
||||
{
|
||||
body
|
||||
{
|
||||
font-size: 16px;
|
||||
}
|
||||
.menu
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
.menu ul
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
/* We remove the border-separator assigned to .l-box-lrg */
|
||||
.l-box-lrg
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
.footer
|
||||
{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
height:3em;
|
||||
}
|
||||
}
|
161
front/public/themes/default/a-propos.html
Normal file
161
front/public/themes/default/a-propos.html
Normal file
@ -0,0 +1,161 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Chaque jour, testez vos connaissances et apprenez de nouvelles choses avec WikiLerni.">
|
||||
<title>Tout savoir sur WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/index.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/a-propos.html">
|
||||
</head>
|
||||
<body>
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
</section>
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
<p>
|
||||
<a class="pure-button pure-button-primary" href="/inscription.html">Tester gratuitement</a>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<article class="content">
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box pure-u-1">
|
||||
|
||||
<h3 class="content-subhead">Qu'est-ce que WikiLerni ?</h3>
|
||||
|
||||
<p>WikiLerni vous propose de lire une sélection d'articles de Wikipédia.<br>
|
||||
Suite à chaque lecture, une série de questions vous permet de tester ce que vous avez retenu.<br>
|
||||
Toutes les réponses à ce quiz se trouvent dans l'article proposé à la lecture.<br>
|
||||
Vous pouvez sauvegarder vos résultats au quiz en créant un compte WikiLerni.<br>
|
||||
Vous pourrez ensuite répondre de nouveau aux mêmes questions plusieurs semaines, mois... après avoir lu l'article.<br>
|
||||
De quoi tester votre mémoire à plus en moins long terme !</p>
|
||||
|
||||
<h3 class="content-subhead">Que signifie "WikiLerni" ?</h3>
|
||||
|
||||
<p>Le nom "WikiLerni" est composé de deux parties :
|
||||
<ul>
|
||||
<li>« Wiki » fait évidemment référence à l'encyclopédie en ligne Wikipédia. Comme je vous sais curieux, sachez que le terme « wiki » vient lui-même du mot hawaïen « wikiwiki » signifiant « rapide », « vite » ou « informel ».</li>
|
||||
<li>« Lerni » est un verbe espéranto signifiant « apprendre » ou encore « étudier ». Vous pouvez penser à « learn » en anglais ou encore « lernen » en allemand.</li>
|
||||
</ul>
|
||||
Bref, WikiLerni vous invite à <b>apprendre de nouvelles choses avec Wikipédia !</b><br>
|
||||
Et en lisant ces quelques lignes, vous venez peut-être déjà d'apprendre quelque chose :-)</p>
|
||||
|
||||
<h3 class="content-subhead">À qui s'adresse WikiLerni ?</h3>
|
||||
|
||||
<p>À toute personne curieuse aimant apprendre de nouvelles choses !<br>
|
||||
Contrairement à d'autres sites de quiz testant votre culture générale, WikiLerni ne vous demande pas d'être déjà très "savants", même si vous l'êtes forcément, au moins dans certains domaines. Si ! Si !<br>
|
||||
Vous êtes ici pour apprendre et toutes les réponses aux questions des quizs se trouvent dans l'article qui vous est proposé à la lecture.<br>
|
||||
C'est donc une façon ludique d'apprendre de nouvelles choses sur des sujets auxquels vous ne vous seriez peut-être jamais intéressé par vous-même.</p>
|
||||
|
||||
<h3 class="content-subhead">Est-il nécessaire de créer un compte pour utiliser WikiLerni ?</h3>
|
||||
|
||||
<p>Non, vous pouvez parcourir librement WikiLerni sans avoir besoin d'être connecté au site.<br>
|
||||
Votre compte vous permettra de :
|
||||
<ul>
|
||||
<li>sauvegarder vos résultats aux quizs</li>
|
||||
<li>recevoir des suggestions de nouvelles lectures, directement par e-mail</li>
|
||||
<li>faciliter votre navigation via un moteur de recherche interne à WikiLerni</li>
|
||||
<li>et d'autres fonctionnalités à venir...</li>
|
||||
</ul></p>
|
||||
|
||||
<h3 class="content-subhead">Comment sont sélectionnés les articles proposés par WikiLerni ?</h3>
|
||||
|
||||
<p>Tout comme Wikipédia, WikiLerni se veut éclectique.<br>
|
||||
Donc il vous sera proposé des articles sur des sujets très variés : sciences, arts, histoire, littérature, mythologie, géographie, culture populaire, etc.<br>
|
||||
Il n'y aucun sujet qui ne soit pas digne d'intérêt à priori. Seront évités des articles indiqués par Wikipédia comme de faible qualité ou encore sujets à polémique.</p>
|
||||
|
||||
<p>Les articles proposés à la lecture peuvent être de longueurs variées.<br>
|
||||
Une estimation de la durée de lecture vous est indiquée sur la page du quiz ou encore dans les e-mails que vous recevez si vous êtes abonné.<br>
|
||||
Vous pourrez ainsi choisir de laisser de côté un article un peu long pour y revenir quand vous aurez plus de temps.</p>
|
||||
|
||||
<p>Pour l'instant, les articles proposés sont uniquement francophones.<br>
|
||||
Mais suivant le succès du site, des versions dans d'autres langues pourront être envisagées.<br>
|
||||
Si vous souhaitez vous-même lancer une version dans une autre langue, mais n'avez pas les compétences techniques pour le faire, n'hésitez <a href="/contact.hml">à me contacter</a> pour un éventuel partenariat.</p>
|
||||
|
||||
<h3 class="content-subhead">Quel lien entre WikiLerni et Wikipédia ?</h3>
|
||||
|
||||
<p>Puisque toutes les suggestions de lecture de WikiLerni vous amènent sur Wikipédia, le lien est évident.<br>
|
||||
Pour autant, WikiLerni n'est pas un projet porté par la fondation Wikipédia, ni par une de ses associations locales, mais est un projet indépendant.<br>
|
||||
Au-delà de ce lien pratique, WikiLerni se veut très proche de l'esprit de Wikipédia en partageant son attrait pour la culture libre et le "libre" en général.
|
||||
L'application faisant fonctionner WikiLerni est un logiciel libre, c'est-à-dire que toute personne peut l'utiliser, étudier son code, le modifier, le distribuer selon son souhait.<br>Ceci est également vrai pour le graphisme du site et les quizs eux-mêmes : texte d'introduction, questions/réponses, illustrations... Sauf exceptions indiquées.</p>
|
||||
|
||||
<h3 class="content-subhead">Est-ce que WikiLerni est gratuit ?</h3>
|
||||
|
||||
<p>Oui.. et non ! Réponse de normand venant d'un breton ? :-)<br>Vous pouvez tout à fait parcourir WikiLerni, lire les articles proposés et répondre aux quizs.<br>
|
||||
Tout cela se fait sans avoir besoin de vous abonner et donc gratuitement.<br>Par contre, si vous souhaitez garder vos résultats, recevoir par mail de nouvelles suggestions de lectures... vous devrez vous abonner au site.<br>Vous pourrez alors tester gratuitement l'abonnement pendant une période de découverte.<br>Ensuite, vous serez invité à souscrire à un abonnement, mais à un prix "libre", c'est-à-dire que différentes possibilités vous seront proposées.<br>Tout le monde n'a pas les mêmes moyens, ni le même intérêt pour le WikiLerni, donc à vous de choisir en conscience.<br>
|
||||
Vous aimez WikiLerni, mais ne pouvez vraiment pas payer pour ce service ? <a href="/contact.html">Contactez-moi</a>. Vous n'avez pas à vous justifier.<br>
|
||||
De même, si aucune des options ne vous convient ou encore si vous préférez un autre moyen de paiement (chèque, virement...), <a href="/contact.html">contactez-moi</a> pour me dire ce que vous souhaitez.<br>Des abonnements de groupe (famille, écoles, associations...) ou autres formules peuvent aussi être envisagées, dans la mesure où cela sera techniquement possible.<br>Bref, <b>nous sommes ici plus dans l'esprit d'un financement participatif que dans celui d'un abonnement classique</b>.<br>En souscrivant à un abonnement, vous permettez à WikiLerni d'exister.</p>
|
||||
|
||||
<h3 class="content-subhead">À quoi va servir l'argent de mon abonnement ?</h3>
|
||||
|
||||
<p>Cet argent va principalement servir à :<ul>
|
||||
<li>payer les frais techniques liés au site : serveurs, routeurs e-mail, paiement en ligne...</li>
|
||||
<li>développer le logiciel permettant à WikiLerni de fonctionner.</li>
|
||||
<li>consacrer du temps à sélectionner les articles Wikipédia et préparer les questions.</li>
|
||||
<li>gérer le site au quotidien : répondre à vos courriels, communiquer, etc.</li>
|
||||
</ul>Tout cela sans vous imposer de publicités ou faire commerce de vos données personnelles.</b><br>
|
||||
Par ailleurs, une partie des bénéfices nets de WikiLerni seront distribués sous forme de dons à l'<a href="https://www.wikimedia.fr/" target="_blank">association Wikimédia France</a> et aux développeurs des logiciels libres utilisés par WikiLerni.<br>Je parle de bénéfices "nets", car au-delà des frais de fonctionnement, mon activité étant déclarée, il faut y soustraire TVA, cotisations, etc.<br><br>
|
||||
<b>Pas de publicité, respect de vos données personnelles, activité déclarée en France... un autre internet serait possible ?</b></p>
|
||||
|
||||
<h3 class="content-subhead">Comment puis-je aider WikiLerni ?</h3>
|
||||
|
||||
<p>Tout d'abord en l'utilisant et <a href="/contact.html">me retournant</a> vos éventuelles remarques/suggestions.<br>
|
||||
Un bug ? Une erreur d'orthographe ? Une suggestion de fonctionnalité ? Quelque chose que vous ne comprenez pas ? N'hésitez pas à me le dire, cela m'intéresse.<br>
|
||||
Ensuite, si vous avez les moyens, vous pouvez souscrire un abonnement payant pour permettre au projet de perdurer.<br>
|
||||
Et WikiLerni n'ayant pas les moyens des grandes sociétés pour communiquer, vous pouvez aussi en parler autour de vous, en ligne ou dans la vie de tous les jours. <b>
|
||||
Vous le savez sans doute, rien ne vaut le bouche à oreille !</b><br>
|
||||
Un système de parrainage est d'ailleurs prévu pour vous récompenser : à chaque fois qu'une personne inscrite en vous désignant comme "parrain" souscrit un abonnement payant, votre propre abonnement se trouve prolongé de 30 jours.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="l-box pure-u-1"><a href="/inscription.html" class="pure-button pure-button-primary">Tester gratuitement.</a></div>
|
||||
</article>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-4">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
100
front/public/themes/default/accueil.html
Normal file
100
front/public/themes/default/accueil.html
Normal file
@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Page d'accueil de l'abonné.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/homeUser.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/accueil.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/accueil.html" class="pure-menu-heading pure-menu-link">Mon WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a class="pure-menu-link" href="/compte.html#infos" title="Email, mot de passe">Mes informations</a></li>
|
||||
<li class="pure-menu-item"><a href="/compte.html#subscribe" class="pure-menu-link">Mon abonnement</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1" id="message"></div>
|
||||
|
||||
<form class="pure-form pure-u-1" id="search" method="POST">
|
||||
<fieldset>
|
||||
<legend>Chercher un quiz</legend>
|
||||
<input id="searchQuestionnaires" type="txt" name="searchQuestionnaires" placeholder="Votre recherche">
|
||||
<input type="checkbox" id="onlyAnswers" name="onlyAnswers" /> Parmi mes réponses.
|
||||
<input id="begin" type="hidden" name="begin" value="0">
|
||||
<button type="submit" class="pure-button pure-button-primary">Chercher</button>
|
||||
<button type="button" id="random" class="pure-button pure-button-primary">Au hasard !</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="l-box-lrg pure-u-1" id="quizs">
|
||||
<h2 id="quizsTitle">Les quizs attendant votre réponse</h2>
|
||||
<div id="quizsIntro"></div>
|
||||
<div id="quizsList"></div>
|
||||
<div id="quizsPagination"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
front/public/themes/default/aurevoir.html
Normal file
79
front/public/themes/default/aurevoir.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Valider la suppression de votre compte.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Valider la suppression de votre compte</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/deleteValidation.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/aurevoir.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Valider la suppression de votre compte</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript. Nous travaillons à changer cela.</noscript>
|
||||
<div id="response">Si vous voyez ce message, c'est que votre lien de validation n'est pas valide ou a expiré. Vous pouvez <a href="/compte.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
176
front/public/themes/default/compte.html
Normal file
176
front/public/themes/default/compte.html
Normal file
@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Mettre à jour votre compte, votre abonnement...">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Mon compte</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/accountUser.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/compte.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/accueil.html" class="pure-menu-heading pure-menu-link">Mon WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a class="pure-menu-link" href="/compte.html#infos" title="Email, mot de passe">Mes informations</a></li>
|
||||
<li class="pure-menu-item"><a href="/compte.html#subscribe" class="pure-menu-link">Mon abonnement</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center" id="infos">Votre compte WikiLerni</h2>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned" id="accountUpdate" method="POST">
|
||||
<fieldset>
|
||||
<div class="pure-control-group">
|
||||
<label for="name">Nom ou pseudo</label>
|
||||
<input id="name" type="text" name="name">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="email">Email</label>
|
||||
<input id="email" type="email" name="email">
|
||||
<span class="pure-form-message-inline" id="emailMessage"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="newPassword">Nouveau mot de passe</label>
|
||||
<input id="newPassword" type="password" name="newPassword">
|
||||
<span class="pure-form-message-inline" id="newPasswordMessage"><b class="information">Laisser vide sauf si vous souhaitez le changer.</b></span>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
Par défaut un nouveau quiz vous est proposé tous les jours. Vous pouvez préciser ci-dessous les jours souhaités :
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-7"><!-- grille ne fonctionne pas ?! -->
|
||||
<label for="d2">
|
||||
<input type="checkbox" id="d2" name="d2" value="true" /> Lundi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d3">
|
||||
<input type="checkbox" id="d3" name="d3" value="true" /> Mardi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d4">
|
||||
<input type="checkbox" id="d4" name="d4" value="true" /> Mercredi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d5">
|
||||
<input type="checkbox" id="d5" name="d5" value="true" /> Jeudi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d6">
|
||||
<input type="checkbox" id="d6" name="d6" value="true" /> Vendredi
|
||||
</label>
|
||||
</li>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d7">
|
||||
<input type="checkbox" id="d7" name="d7" value="true" /> Samedi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d1">
|
||||
<input type="checkbox" id="d1" name="d1" value="true" /> Dimanche
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="noticeOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="noticeOk" name="noticeOk" value="true" /> Je souhaite recevoir les nouveaux quizs par email.
|
||||
</label>
|
||||
<label for="newsletterOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /> J'accepte de recevoir d'autres messages ponctuels de WikiLerni (nouvelles fonctionnalités ...).
|
||||
</label>
|
||||
<label for="deleteOk" class="pure-checkbox error">
|
||||
<input type="checkbox" id="deleteOk" name="deleteOk" value="true" /> Je souhaite supprimer mon compte utilisateur
|
||||
</label>
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
|
||||
<h3 id="subscribe">Votre abonnement</h3>
|
||||
<div id="subscribeIntro"></div>
|
||||
<p>Le coût de l'abonnement dépend de la durée pour laquelle vous vous engagez.</p>
|
||||
<p>Merci de sélectionnez l'offre qui vous convient et de valider les C.G.V.<br>Un bouton vous permettra ensuite d'effectuer votre paiement.</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="180Ok" name="180Ok" value="true" /> Je m'engage pour 180 jours</li>
|
||||
<li><input type="checkbox" id="365Ok" name="365Ok" value="true" /> Je m'engage pour 365 jours</li>
|
||||
<li><input type="checkbox" id="CGVOk" name="CGVOk" value="true" /> J'ai lu et accepte les <a href="/cgv.html">Conditions Générales de Vente</a>.</li>
|
||||
</ul>
|
||||
|
||||
<div id="WPBtn180" class="needJS"><script>document.write("ici apparaîtra un bouton de paiement pour les 180 jours")</script></div>
|
||||
<div id="WPBtn365" class="needJS"><script>document.write("ici apparaîtra un bouton de paiement pour les 365 jours")</script></div>
|
||||
<div id="WPNone" class="needJS"><p><b>Merci de sélectionné l'offre qui vous convient.</b></p></div>
|
||||
|
||||
<h3 id="godfather">Les utilisateurs que vous avez parrainés</h3>
|
||||
<p>Vous pouvez parrainer d'autres utilisateurs. Pour ce faire, demandez-leur de saisir lors de l'inscription votre adresse e-mail <strong id="godfatherEmail"></strong> ou encore le code suivant : <strong id="godfatherCode"></strong> (en gardant les majuscules/minuscules).</p>
|
||||
<p>À chaque fois qu'un utilisateur que vous avez parrainé <b>souscrit un abonnement payant</b>, son abonnement comme le vôtre <b>se trouve prolongé gratuitement de 30 jours</b>. Ceci reste valable tant que cet utilisateur garde son compte WikiLerni.</p>
|
||||
<p id="godchilds"><b>Pour l'instant aucune personne ne s'est inscrite en vous désignant comme "parrain".</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
108
front/public/themes/default/connexion.html
Normal file
108
front/public/themes/default/connexion.html
Normal file
@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Formulaire de connexion à WikiLerni.">
|
||||
<title>Se connecter à WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/connection.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/inscription.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Connectez-vous à WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript. Nous travaillons à changer cela.</noscript>
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned needJS" id="connection" method="POST">
|
||||
<fieldset>
|
||||
<p>Pas de compte WikiLerni ? <a href="/inscription.html">créez-le ici</a>.</p>
|
||||
<div class="pure-control-group">
|
||||
<label for="email">Email</label>
|
||||
<input id="email" type="email" name="email" placeholder="Adresse e-mail utilisée pour ce site" required>
|
||||
<span class="pure-form-message-inline" id="emailMessage"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input id="password" type="password" name="password" placeholder="Votre mot de passe">
|
||||
<span class="pure-form-message-inline" id="passwordMessage"><i class="information">Oublié ? Alors laissez vide et cochez la case ci-dessous.</i></span>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="getLoginLink" class="pure-checkbox">
|
||||
<input type="checkbox" id="getLoginLink" name="getLoginLink" value="true" /> Je souhaite recevoir un lien de connexion par e-mail.
|
||||
</label>
|
||||
<label for="keepConnected" class="pure-checkbox">
|
||||
<input type="checkbox" id="keepConnected" name="keepConnected" value="true" /> Je souhaite ne pas avoir à me connecter à chaque fois.
|
||||
</label>
|
||||
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<h4>Besoin d'aide ?</h4>
|
||||
<p>Si vous avez oublié votre mot de passe, il vous suffit de cocher la case <i>"Je souhaite recevoir un lien de connexion par e-mail."</i>. Un lien valide pendant une courte durée vous permettra de vous connecter au site.<br>Si vous ne vous souvenez pas non plus de l'adresse e-mail utilisée sur ce site ou que vous n'y avez plus accès, vous pouvez <a href="/contact.html">nous contacter</a> en fournissant des informations permettant de vous identifier.</p><p>La case <i>"Je souhaite ne pas avoir à me connecter à chaque fois."</i> vous permettra de rester connecté(e) jusqu'à 6 mois, pour peu que vous utilisiez le même navigateur internet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
266
front/public/themes/default/gestion-quizs.html
Normal file
266
front/public/themes/default/gestion-quizs.html
Normal file
@ -0,0 +1,266 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Saisie et mise à jour des quizs">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Les quizs</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/manageQuestionnaires.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion-quizs.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center" id="infos">Les quizs</h2>
|
||||
|
||||
<form class="pure-form pure-u-1" id="search" method="POST">
|
||||
<fieldset>
|
||||
<legend>Chercher un quiz</legend>
|
||||
<input id="searchQuestionnaires" type="txt" name="searchQuestionnaires" placeholder="Votre recherche">
|
||||
<button type="submit" class="pure-button pure-button-primary">Chercher</button>
|
||||
<div id="searchResult"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned" id="questionnaires" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations du quiz</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="title">Titre</label>
|
||||
<input id="title" type="text" name="title">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="slug">Page html</label>
|
||||
<input id="slug" type="text" name="slug">.html
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="introduction">Introduction</label>
|
||||
<textarea id="introduction" name="introduction" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="keywords">Mots-clés</label>
|
||||
<textarea id="keywords" name="keywords" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="publishingAt">Date de publication</label>
|
||||
<input id="publishingAt" type="date" name="publishingAt"> <span class="information" id="helpPublishingAt"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="estimatedTime">Durée de lecture estimée</label>
|
||||
<select name="estimatedTime" id="estimatedTime">
|
||||
<option value="short">Court</option>
|
||||
<option value="medium">Moyen</option>
|
||||
<option value="long">Long</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="classification">Catégories de classement</label>
|
||||
<input id="classification" type="text" name="classification"> <span class="information" id="helpClassification">Séparer les rubriques par des virgules</span>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="deleteOk" class="pure-checkbox error" id="deleteOkLabel">
|
||||
<input type="checkbox" id="deleteOk" name="deleteOk" value="true" /> Je souhaite supprimer ce quiz
|
||||
</label>
|
||||
<input type="hidden" name="id" id="id" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
<a href="#questionnaires" class="pure-button pure-button-primary needJS" id="wantNewQuestionnaire">Nouveau questionnaire</a>
|
||||
<a href="#questionnaires" class="pure-button pure-button-primary needJS" id="previewQuestionnaire" target=="_blank">Voir le quiz</a>
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div id="linksList" class="needJS"></div>
|
||||
<div id="illustrationsList" class="needJS"></div>
|
||||
<div id="questionsList" class="needJS"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="links" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations du lien</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="url">Url</label>
|
||||
<input id="url" type="url" name="url">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="anchor">Texte du lien</label>
|
||||
<input id="anchor" type="text" name="anchor" value="Lire l'article sur Wikipédia.">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idLink" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdLink" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkLink" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseLink"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="illustrations" method="POST" enctype="multipart/form-data">
|
||||
<fieldset>
|
||||
<legend>Informations de l'illustration</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="image">Sélectionnez le fichier à utiliser</label>
|
||||
<input type="file" id="image" name="image">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="alt">Propriété "alt"</label>
|
||||
<input id="alt" type="text" name="alt">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="title">Propriété "title"</label>
|
||||
<input id="title" type="text" name="title">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="caption">Légende</label>
|
||||
<input id="caption" type="text" name="caption">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idIllustration" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdIllustration" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkIllustration" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseIllustration"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
|
||||
<form class="pure-form pure-form-aligned" id="questions" method="POST">
|
||||
<fieldset>
|
||||
<legend>La question et les réponses proposées</legend>
|
||||
<div class="pure-control-group">
|
||||
<label for="text">Question</label>
|
||||
<input id="text" type="text" name="text">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="rank">Rang</label>
|
||||
<input id="rank" type="number" name="rank" value="1"> <span class="information">Permet de fixer l'ordre d'affichage des questions.</span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="explanation">Explications</label>
|
||||
<textarea id="explanation" name="explanation" rows="5"></textarea>
|
||||
</div>
|
||||
<legend>Réponses proposées</legend>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText0" type="text" name="choiceText0" maxlength="255" maxlength="255"> <input type="checkbox" id="choiceIsCorrect0" name="choiceIsCorrect0" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice0" id="idChoice0" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText1" type="text" name="choiceText1" maxlength="255"> <input type="checkbox" id="choiceIsCorrect1" name="choiceIsCorrect1" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice1" id="idChoice1" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText2" type="text" name="choiceText2" maxlength="255"> <input type="checkbox" id="choiceIsCorrect2" name="choiceIsCorrect2" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice2" id="idChoice2" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText3" type="text" name="choiceText3" maxlength="255"> <input type="checkbox" id="choiceIsCorrect3" name="choiceIsCorrect3" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice3" id="idChoice3" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText4" type="text" name="choiceText4" maxlength="255"> <input type="checkbox" id="choiceIsCorrect4" name="choiceIsCorrect4" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice4" id="idChoice4" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText5" type="text" name="choiceText5" maxlength="255"> <input type="checkbox" id="choiceIsCorrect5" name="choiceIsCorrect5" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice5" id="idChoice5" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText6" type="text" name="choiceText6" maxlength="255"> <input type="checkbox" id="choiceIsCorrect6" name="choiceIsCorrect6" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice6" id="idChoice6" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText7" type="text" name="choiceText7" maxlength="255"> <input type="checkbox" id="choiceIsCorrect7" name="choiceIsCorrect7" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice7" id="idChoice7" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText8" type="text" name="choiceText8" maxlength="255"> <input type="checkbox" id="choiceIsCorrect8" name="choiceIsCorrect8" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice8" id="idChoice8" value="">
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<input id="choiceText9" type="text" name="choiceText9" maxlength="255"> <input type="checkbox" id="choiceIsCorrect9" name="choiceIsCorrect9" value="true" /> Réponse correcte
|
||||
<input type="hidden" name="idChoice9" id="idChoice9" value="">
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<input type="hidden" name="id" id="idQuestion" value="">
|
||||
<input type="hidden" name="QuestionnaireId" id="QuestionnaireIdQuestion" value="">
|
||||
<input type="hidden" name="deleteOk" id="deleteOkQuestion" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary">Valider</button>
|
||||
</div>
|
||||
<div id="responseQuestion"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="l-box-lrg pure-u-1" id="questionnairesList"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
211
front/public/themes/default/gestion-utilisateurs.html
Normal file
211
front/public/themes/default/gestion-utilisateurs.html
Normal file
@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Gestion des abonnés">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Les abonnés</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/manageUsers.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion-utilisateurs.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center" id="infos">Les abonnés</h2>
|
||||
|
||||
<form class="pure-form pure-u-1" id="search" method="POST">
|
||||
<fieldset>
|
||||
<legend>Chercher un utilisateur</legend>
|
||||
<input id="search" type="txt" name="search" placeholder="Votre recherche">
|
||||
<button type="submit" class="pure-button pure-button-primary">Chercher</button>
|
||||
<div id="searchResult"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="message"></div>
|
||||
<form class="pure-form pure-form-aligned" id="users" method="POST">
|
||||
<fieldset>
|
||||
<legend>Informations de l'abonné</legend>
|
||||
<div id="subscribeIntro"></div>
|
||||
<div class="pure-control-group">
|
||||
<label for="name">Nom ou pseudo</label>
|
||||
<input id="name" type="text" name="name">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="email">Email</label>
|
||||
<input id="email" type="email" name="email">
|
||||
<span class="pure-form-message-inline" id="emailMessage"></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="status">Statut</label>
|
||||
<select id="status" name="status">
|
||||
<option value="user">Utilisateur</option>
|
||||
<option value="creator">Créateur</option>
|
||||
<option value="manager">Gestionnaire</option>
|
||||
<option value="admin">Administrateur</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="smtp">SMTP</label>
|
||||
<select id="smtp" name="smtp">
|
||||
<option value="0">Spirion</option>
|
||||
<option value="1">Mailjet</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="timeDifference">Décalage horaire</label>
|
||||
<input id="timeDifference" type="number" name="timeDifference" readonly>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="newPassword">Nouveau mot de passe</label>
|
||||
<input id="newPassword" type="password" name="newPassword">
|
||||
<span class="pure-form-message-inline" id="newPasswordMessage"><b class="information">Laisser vide sauf si vous souhaitez le changer.</b></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="adminComments">Commentaires</label>
|
||||
<textarea id="adminComments" name="adminComments" rows="5"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="numberOfDays">Durée totale de l'abonnement</label>
|
||||
<input id="numberOfDays" type="number" name="numberOfDays"><span class="pure-form-message-inline"><i class="information">Depuis la création de son compte.</i></span>
|
||||
</div>
|
||||
|
||||
<div class="pure-controls">
|
||||
Jours valables pour l'abonnement
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-7"><!-- grille ne fonctionne pas ?! -->
|
||||
<label for="d2">
|
||||
<input type="checkbox" id="d2" name="d2" value="true" /> Lundi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d3">
|
||||
<input type="checkbox" id="d3" name="d3" value="true" /> Mardi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d4">
|
||||
<input type="checkbox" id="d4" name="d4" value="true" /> Mercredi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d5">
|
||||
<input type="checkbox" id="d5" name="d5" value="true" /> Jeudi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d6">
|
||||
<input type="checkbox" id="d6" name="d6" value="true" /> Vendredi
|
||||
</label>
|
||||
</li>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d7">
|
||||
<input type="checkbox" id="d7" name="d7" value="true" /> Samedi
|
||||
</label>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-7">
|
||||
<label for="d1">
|
||||
<input type="checkbox" id="d1" name="d1" value="true" /> Dimanche
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="noticeOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="noticeOk" name="noticeOk" value="true" /> Reçoit les quizs par email.
|
||||
</label>
|
||||
<label for="newsletterOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /> Reçoit les autres actus par email.
|
||||
</label>
|
||||
<label for="validationOk" class="pure-checkbox success" id="validationOkLabel">
|
||||
<input type="checkbox" id="validationOk" name="validationOk" /> Valider le compte.
|
||||
</label>
|
||||
<label for="deleteOk" class="pure-checkbox error" id="deleteOkLabel">
|
||||
<input type="checkbox" id="deleteOk" name="deleteOk" /> Supprimer le compte
|
||||
</label>
|
||||
<input type="hidden" name="id" id="id" value="">
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
<a href="#users" class="pure-button pure-button-primary" id="wantNewUser">Vider</a>
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div id="infosPayments" class="needJS"><h4>Payments reçus via l'API WebPortage</h4></div>
|
||||
<div id="infosGodchilds" class="needJS"><h4>Parrainages</h4></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
83
front/public/themes/default/gestion.html
Normal file
83
front/public/themes/default/gestion.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Page d'accueil du gestionnaire.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>WikiLerni - gestion du site</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/homeManager.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/gestion.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content" class="needJS">
|
||||
|
||||
<div class="pure-menu pure-menu-horizontal">
|
||||
<a href="/gestion.html" class="pure-menu-heading pure-menu-link">Gestion WikiLerni</a>
|
||||
<ul id="classement" class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="/gestion-quizs.html" title="Publication des quizs" class="pure-menu-link" >Les quizs</a></li>
|
||||
<li class="pure-menu-item"><a href="/gestion-utilisateurs.html" title="Les comptes utilisateurs" class="pure-menu-link">Les abonné(e)s</a></li>
|
||||
<li class="pure-menu-item"><a href="/sortie.html" title="Sortie des artistes !" class="pure-menu-link">Me déconnecter</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1" id="message"></div>
|
||||
<div class="l-box-lrg pure-u-1" id="questionnaires"></div>
|
||||
</div>
|
||||
<p><a href="#" class="pure-button pure-button-primary" id="wantRegenerate">Régénérer le HTML.</a></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
1
front/public/themes/default/index.html
Normal file
1
front/public/themes/default/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="Chaque jour, testez vos connaissances et apprenez de nouvelles choses avec WikiLerni."><title>WikiLerni : qu'allez-vous apprendre aujourd'hui ?</title><base href="http://localhost:8080"><script src="/JS/polyfill.app.js" defer></script><script src="/JS/index.app.js" defer></script><link rel="stylesheet" href="/themes/default/CSS/pure-min.css"><link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css"><link rel="stylesheet" href="/themes/default/CSS/wikilerni.css"><link rel="shortcut icon" href="/img/favicon.ico"><link rel="apple-touch-icon" sizes="57x57" href="/img/apple-icon-57x57.png"><link rel="icon" type="image/png" sizes="192x192" href="/img/android-icon-192x192.png"><link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png"><link rel="canonical" href="http://localhost:8080"></head><body><header class="pure-g menu"><div class="pure-u-1 pure-u-lg-1-8 menu-heading"><a class="pure-menu-heading" href="/">WikiLerni</a></div><div class="pure-u-1 pure-u-lg-7-8"><ul class="pure-g"><li class="pure-menu-item pure-u-1 pure-u-lg-1-4"><a class="pure-menu-link" href="/">Accueil</a></li><li class="pure-menu-item pure-u-1 pure-u-lg-1-4"><a class="pure-menu-link" href="/connexion.hmt" id="accountHeadLink">Mon compte</a></li><li class="pure-menu-item pure-u-1 pure-u-lg-1-4"><a class="pure-menu-link" href="/a-propos.html">À propos</a></li><li class="pure-menu-item pure-u-1 pure-u-lg-1-4"><a class="pure-menu-link" href="/contact.html">Contact</a></li></ul></div></header><section id="main-content"><header id="main-header"><h1>WikiLerni</h1><p></p><p><a class="pure-button pure-button-primary" href="/inscription.html">Inscription</a></p></header><article class="content"><div class="pure-g"><div class="l-box pure-u-1"><h3 class="content-subhead"><em>De nature curieuse ?</em></h3><p>Avec WikiLerni vous apprenez chaque jour de nouvelles choses.<br>Des articles de Wikipédia sont sélectionnés pour vous et sont suivis d'un quiz vous permettant de tester ce que vous en avez retenu.<br>De jour en jour de nouvelles graines de savoir sont ainsi semées dans votre "jardin".</p></div><div class="l-box pure-u-1"><h3 class="content-subhead"><em>La culture en liberté</em></h3><p>Tout comme sur Wikipédia (*), le logiciel et le contenu partagé sur WikiLerni sont libres.<br>Vous pouvez les utiliser, les modifier et les diffuser selon votre souhait.<br>Sur WikiLerni, pas de publicité, ni de commercialisation de vos données personnelles.<br>Vous pouvez venir y "cultiver votre jardin" en toute tranquillité.<br><br><small><em>(*) Bien que partageant ses valeurs, WikiLerni est un projet indépendant de la fondation Wikipédia.</em></small></p></div></div><div class="l-box pure-u-1"><a class="pure-button pure-button-primary" href="/a-propos.html">En savoir plus sur WikiLerni.</a></div><div class="l-box pure-u-1"><a class="pure-button pure-button-primary" href="/inscription.html">Tester WikiLerni gratuitement.</a></div></article><div class="questionnaire-listed l-box-lrg pure-g"><div class="l-box-lrg is-center pure-u-1 pure-u-md-1-2 pure-u-lg-2-5"><img class="pure-img-responsive" src="/img/quizs/bonhomme_de_neige01_377_600-1589208854134.jpg" alt="sans fichier !" title="juste les infos"></div><div class="pure-u-1 pure-u-md-1-2 pure-u-lg-3-5"><h2 class="content-head content-head-questionnaire">Que savez-vous des éditions Gallimard ?</h2><div id="intro">Les éditions Gallimard, appelées jusqu’en 1919 les éditions de la Nouvelle Revue française et jusqu’en 1961 la librairie Gallimard, sont un groupe d'édition français. La maison d'édition est fondée par Gaston Gallimard en 1911. Le groupe Gallimard est actuellement dirigé par Antoine Gallimard.Con...</div><a class="pure-button pure-button-primary" href="/quiz/editions-gallimard.html">Allez au quiz !</a></div></div></section><footer class="footer l-box is-center"><ul class="pure-g"><li class="pure-u-1 pure-u-lg-1-5"><a href="/credits.html">Crédits</a></li><li class="pure-u-1 pure-u-lg-1-5"><a href="/mentions-legales.html" rel="nofollow">Mentions légales</a></li><li class="pure-u-1 pure-u-lg-1-5"><a href="/donnees.html">Données personnelles</a></li><li class="pure-u-1 pure-u-lg-1-5"><a href="/cgu.html" rel="nofollow">C.G.U.</a></li><li class="pure-u-1 pure-u-lg-1-5"><a href="/cgv.html" rel="nofollow">C.G.V.</a></li></ul></footer></body></html>
|
115
front/public/themes/default/inscription.html
Normal file
115
front/public/themes/default/inscription.html
Normal file
@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Formulaire d'inscription à WikiLerni.">
|
||||
<title>S'inscrire à WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/subscribe.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/inscription.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Créer votre compte WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript. Nous travaillons à changer cela.</noscript>
|
||||
<form class="pure-form pure-form-aligned needJS" id="subscription" method="POST">
|
||||
<fieldset>
|
||||
<div class="pure-control-group">
|
||||
<label for="name">Nom ou pseudo</label>
|
||||
<input id="name" type="text" name="name" placeholder="Pseudo de votre choix">
|
||||
<span class="pure-form-message-inline"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="email">Email</label>
|
||||
<input id="email" type="email" name="email" placeholder="Adresse e-mail">
|
||||
<span class="pure-form-message-inline" id="emailMessage"></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input id="password" type="password" name="password" placeholder="Mot de passe de votre choix">
|
||||
<span class="pure-form-message-inline" id="passwordMessage"><i class="information">Votre mot de passe doit compter au moins 8 caractères. <a href="#password" id="getPassword">Générer un mot de passe</a>.</i></span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
<label for="codeGodfather">Code parrainage</label>
|
||||
<input id="codeGodfather" name="codeGodfather" placeholder="Code ou email de votre parrain.">
|
||||
<span class="pure-form-message-inline" id="codeGodfatherMessage"><i class="information">Facultatif.</i></span>
|
||||
</div>
|
||||
<div class="pure-controls">
|
||||
<label for="cguOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="cguOk" name="cguOk" value="true" /> J'accepte <a href="/cgu.html">les Conditions Générales d'Utilisation du site</a> (requis).
|
||||
</label>
|
||||
<label for="newsletterOk" class="pure-checkbox">
|
||||
<input type="checkbox" id="newsletterOk" name="newsletterOk" value="true" /> J'accepte de recevoir les nouveaux quizs WikiLerni par email (facultatif).
|
||||
</label>
|
||||
<button type="submit" class="pure-button pure-button-primary" id="submitDatas">Valider</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<h4>Pourquoi s'inscrire ?</h4>
|
||||
<p>Cela prend quelques instants et n'engage à rien, car c'est totalement gratuit les quinze premiers jours. Libre à vous ensuite de vous abonner pour quelques euros par an. Sinon, il vous suffira de ne pas donner suite à la notification vous proposant de vous abonner.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
front/public/themes/default/login.html
Normal file
79
front/public/themes/default/login.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Validation création compte WikiLerni.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Tester votre lien de connexion</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/loginLink.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/login.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Test de votre lien de connexion</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript. Nous travaillons à changer cela.</noscript>
|
||||
<div id="response">Si vous voyez ce message, c'est que votre lien de connexion n'est pas valide. Vous pouvez <a href="/connexion.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
front/public/themes/default/newlogin.html
Normal file
79
front/public/themes/default/newlogin.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Validation de vos nouveaux identifiants.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Valider vos nouveaux identifiants</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/newLoginValidation.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/newlogin.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Validation de vos nouveaux identifiants</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript. Nous travaillons à changer cela.</noscript>
|
||||
<div id="response">Si vous voyez ce message, c'est que votre lien de validation n'est pas valide ou a expiré. Vous pouvez <a href="/compte.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
78
front/public/themes/default/sortie.html
Normal file
78
front/public/themes/default/sortie.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Page de déconnexion.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Déconnexion</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/deconnection.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/deconnection.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Au revoir !</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="response">Si vous voyez ce message, c'est qu'un problème a été rencontré durant la déconnexion.<br>N'hésitez pas à nous prévenir si le problème persiste.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
78
front/public/themes/default/stop-mail.html
Normal file
78
front/public/themes/default/stop-mail.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Stopper les envois d'e-mail venant de WikiLerni.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Ne plus recevoir d'e-mail</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/unsubscribe.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/stop-mail.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Stopper les e-mail de WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<div id="response">Si vous voyez ce message, c'est que votre lien de désabonnement ne fonctionne pas. Vous pouvez <a href="/compte.html">accéder à votre compte</a> pour désactiver les envois.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
79
front/public/themes/default/validation.html
Normal file
79
front/public/themes/default/validation.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Validation création compte WikiLerni.">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Valider votre compte WikiLerni</title>
|
||||
<script src="/JS/polyfill.app.js" defer></script>
|
||||
<script src="/JS/subscribeValidation.app.js" defer></script>
|
||||
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/pure-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/grids-responsive-min.css">
|
||||
<link rel="stylesheet" href="/themes/default/CSS/wikilerni.css">
|
||||
<link rel="canonical" href="https://www.wililerni.com/validation.html">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="pure-g menu">
|
||||
<div class="pure-u-1 pure-u-lg-1-8 menu-heading">
|
||||
<a class="pure-menu-heading" href="/">WikiLerni</a>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-lg-7-8">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/">Accueil</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/connexion.html" id="accountHeadLink">Mon compte</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/a-propos.html">À propos</a>
|
||||
</li>
|
||||
<li class="pure-menu-item pure-u-1 pure-u-lg-1-4">
|
||||
<a class="pure-menu-link" href="/contact.html">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="main-content">
|
||||
<header id="main-header">
|
||||
<h1>WikiLerni</h1>
|
||||
<p>Cultivons notre jardin !</p>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<h2 class="content-head is-center">Validation de votre compte WikiLerni</h2>
|
||||
<div class="pure-g">
|
||||
<div class="l-box-lrg pure-u-1">
|
||||
<noscript>Désolé, mais pour l'instant, l'utilisation de WikiLerni nécessite l'activation du JavaScript.</noscript>
|
||||
<div id="response">Si vous voyez ce message, c'est que votre lien de validation n'est pas valide ou a expiré. Vous pouvez <a href="/connexion.html">en demander un nouveau en cliquant ici</a>.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer l-box is-center">
|
||||
<ul class="pure-g">
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Crédits</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/mentions-legales.html">Mentions légales</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/donnees.html">Données personnelles</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgu.html">C.G.U.</a>
|
||||
</li>
|
||||
<li class="pure-u-1 pure-u-lg-1-5">
|
||||
<a href="/cgv.html">C.G.V.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
67
front/public/themes/wikilerni/css/account-mobile.css
Normal file
67
front/public/themes/wikilerni/css/account-mobile.css
Normal file
@ -0,0 +1,67 @@
|
||||
#account fieldset
|
||||
{
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#account label
|
||||
{
|
||||
width: 49%;
|
||||
margin-right: 1%;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#account label.check
|
||||
{
|
||||
text-align: left;
|
||||
width:100%;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
#account
|
||||
{background-color: #FF8800;
|
||||
width: 85%;
|
||||
margin: auto;
|
||||
padding-top: 2.5em;
|
||||
margin-top: -2.5em;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
padding-bottom: 2.5em;
|
||||
margin-bottom: -2.5em;
|
||||
text-align: center;}
|
||||
|
||||
#account h1
|
||||
{width: 105%;
|
||||
background-color: #FF8800;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
margin-left: -2.5%;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.5);}
|
||||
|
||||
#account p,
|
||||
#account ul
|
||||
{margin: 1em;
|
||||
text-align: justify;}
|
||||
|
||||
#account .error, #account .info, #account .success
|
||||
{
|
||||
margin: 1em;
|
||||
width: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 660px) {
|
||||
#account label
|
||||
{width: 100%;
|
||||
text-align: center;
|
||||
display: inline-block;}
|
||||
|
||||
#account fieldset input
|
||||
{display: block;
|
||||
margin: auto;}
|
||||
}
|
49
front/public/themes/wikilerni/css/account.css
Normal file
49
front/public/themes/wikilerni/css/account.css
Normal file
@ -0,0 +1,49 @@
|
||||
#account fieldset { width: 80%; }
|
||||
#account label
|
||||
{
|
||||
width: 49%;
|
||||
margin-right: 1%;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
}
|
||||
#account label.check
|
||||
{
|
||||
text-align: left;
|
||||
width:100%;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#account
|
||||
{background-color: #FF8800;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
padding-top: 2.5em;
|
||||
margin-top: -2.5em;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
padding-bottom: 2.5em;
|
||||
margin-bottom: -2.5em;
|
||||
text-align: center;}
|
||||
|
||||
#account h1
|
||||
{width: 105%;
|
||||
background-color: #FF8800;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
margin-left: -2.5%;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.5);}
|
||||
|
||||
#account p,
|
||||
#account ul
|
||||
{margin: 1em;
|
||||
text-align: justify;}
|
||||
|
||||
#account .error, #account .info, #account .success
|
||||
{
|
||||
margin: 1em;
|
||||
width: auto;
|
||||
border-radius: 5px;
|
||||
}
|
308
front/public/themes/wikilerni/css/common-mobile.css
Normal file
308
front/public/themes/wikilerni/css/common-mobile.css
Normal file
@ -0,0 +1,308 @@
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Light/Millimetre-Light_web.woff);
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Regular/Millimetre-Regular_web.woff);
|
||||
font-weight: regular;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Bold/Millimetre-Bold_web.woff);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
body
|
||||
{margin: 0px;
|
||||
overflow-x: hidden;
|
||||
background-color: #8c599c;}
|
||||
|
||||
body,
|
||||
a,
|
||||
input
|
||||
{font-family: Millimetre;
|
||||
font-weight: regular;
|
||||
color: rgba(255,255,255,1);
|
||||
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.75);}
|
||||
|
||||
input, #headLinks a, #footLinks a, a.button,
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a
|
||||
{
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color: rgba(0,0,0,0.66);
|
||||
text-shadow: 0px 1px 0px rgba(255,255,255,0.75);
|
||||
}
|
||||
a.button:hover
|
||||
{
|
||||
color:white;
|
||||
text-shadow:none;
|
||||
}
|
||||
|
||||
header,
|
||||
footer
|
||||
{background-color: #FF8800;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.75);
|
||||
box-shadow: 0px 0px 10px black;
|
||||
font-size: 1.5em;
|
||||
width: 100%;
|
||||
height:100px;
|
||||
margin-top: 1em;
|
||||
transform: rotate(0.66deg);}
|
||||
|
||||
footer
|
||||
{font-size: 1em;}
|
||||
|
||||
/*
|
||||
header img
|
||||
{max-height:80px;
|
||||
margin-left:10px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;}*/
|
||||
|
||||
header img
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
header ul
|
||||
{
|
||||
width:100%;
|
||||
}
|
||||
|
||||
header ul, footer ul
|
||||
{list-style-type: none;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
line-height: 50px;}
|
||||
|
||||
header ul li
|
||||
{float: right;
|
||||
display: block;}
|
||||
|
||||
footer ul li
|
||||
{margin-top: 10px;
|
||||
display:inline-block;}
|
||||
|
||||
footer ul
|
||||
{width: 100%;}
|
||||
|
||||
header ul li::after,
|
||||
footer ul li::after
|
||||
{width: 1px;
|
||||
height: 80px;
|
||||
display: block;
|
||||
float: right;
|
||||
content: '';
|
||||
margin-left: 1em;
|
||||
margin-top: -20px;
|
||||
background: linear-gradient(to top, rgba(255,255,255,0.25), rgba(255,255,255,0.0));}
|
||||
|
||||
header ul li::before,
|
||||
footer ul li::before
|
||||
{width: 1px;
|
||||
height: 80px;
|
||||
display: block;
|
||||
float: right;
|
||||
content: '';
|
||||
margin-top: -20px;
|
||||
margin-right: 1em;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.25), rgba(0,0,0,0.0));}
|
||||
|
||||
header ul li:first-child::after,
|
||||
footer ul li:last-child::after
|
||||
{display: none;}
|
||||
|
||||
header ul li:first-child::before,
|
||||
footer ul li:last-child::before
|
||||
{display: none;}
|
||||
|
||||
header ul li:first-child,
|
||||
footer ul li:first-child
|
||||
{margin-right: 1em;}
|
||||
|
||||
footer
|
||||
{transform: rotate(-0.66deg);
|
||||
clear: both;
|
||||
text-align: center;}
|
||||
|
||||
fieldset
|
||||
{border: 0px;
|
||||
text-align: left;}
|
||||
|
||||
.needJS
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
label
|
||||
{width: 50%;}
|
||||
|
||||
.engraved
|
||||
{
|
||||
color: white;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, 1);
|
||||
font-family: verdana;
|
||||
}
|
||||
|
||||
.framed
|
||||
{border: 1px solid rgba(0, 0, 0, 0.33);
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,0.5), inset 0px 1px 0px rgba(255,255,255,0.33);
|
||||
display: inline-block;
|
||||
margin: 1em;}
|
||||
|
||||
.cardboard
|
||||
{
|
||||
background-opacity: 0.75;
|
||||
background-image: url('../img/background-texture.png');
|
||||
}
|
||||
|
||||
#explanations
|
||||
{
|
||||
padding: 0.7em;
|
||||
}
|
||||
|
||||
#explanations p
|
||||
{
|
||||
margin:1.3em;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
/* This allow the motion of the button while overing without displacing the content of the page */
|
||||
.input_wrapper
|
||||
{
|
||||
height: 40px;
|
||||
display: inline-block;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
input[type=submit], input[type=text], input[type=email], input[type=password], .button
|
||||
{
|
||||
background-color: #8c599c;
|
||||
padding: 10px;
|
||||
border: 0px;
|
||||
border-radius: 3px;
|
||||
margin-top:-10px;
|
||||
color: white;
|
||||
font-family: sans;
|
||||
font-weight: bold;
|
||||
font-size: 0.6em;
|
||||
position: relative;
|
||||
transition: 0.125s ease all;
|
||||
margin-top: 0px;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.66), inset 0px -1px 0px rgba(0, 0, 0,0.66), 0px 3px 8px rgba(0,0,0,0.66);
|
||||
}
|
||||
|
||||
input[type=submit]:hover,
|
||||
.button:hover
|
||||
{margin-top: 2px;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.66), inset 0px -1px 0px rgba(0, 0, 0,0.66), 0px 0px 5px rgba(0,0,0,0.66);}
|
||||
|
||||
input[type=text], input[type=password], input[type=email] {
|
||||
box-shadow: inset 0px 1px 0px rgba(0,0,0,0.66), inset 0px -1px 0px rgba(255,255,255,0.66), inset 0px 3px 8px rgba(0,0,0,0.66);}
|
||||
|
||||
input[type=checkbox]
|
||||
{width:15px;
|
||||
height:15px;
|
||||
margin-left: 0px;
|
||||
margin-right: -15px;
|
||||
opacity:0.0;}
|
||||
|
||||
/* The following is a trick to force browser to let me redefine checkbox style */
|
||||
.checkbox_override
|
||||
{width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
border-top: 1px solid rgba(0,0,0,0.75);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.5);
|
||||
display: inline-block;}
|
||||
|
||||
input:hover ~ .checkbox_override
|
||||
{background-color: rgba(0, 0, 0, 0.125);}
|
||||
|
||||
input:checked ~ .checkbox_override {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.75);
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
/*#ERROR:target, #SUCCESS:target, #INFO:target,*/
|
||||
p.error, p.success, p.info,
|
||||
div.error, div.success, div.info
|
||||
{
|
||||
width: calc(100% - 20px);
|
||||
height: auto;
|
||||
padding: 1em;
|
||||
opacity: 1;
|
||||
margin-left: 0px;
|
||||
line-height: 1.25em;
|
||||
background-image: url('../img/background-texture.png');
|
||||
}
|
||||
|
||||
.info {background-color: #8c599c;}
|
||||
.success {background-color: #00c684;}
|
||||
.error {background-color: red;}
|
||||
|
||||
@media screen and (max-width: 570px) {
|
||||
header ul
|
||||
{line-height: 66px;}
|
||||
|
||||
header
|
||||
{font-size: 1em;}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
footer
|
||||
{font-size: 0.75em;}
|
||||
|
||||
header ul li::after,
|
||||
footer ul li::after
|
||||
{display: none;}
|
||||
|
||||
header ul li,
|
||||
footer ul li
|
||||
{display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;}
|
||||
|
||||
header ul li::before,
|
||||
footer ul li::before
|
||||
{display: none;}
|
||||
|
||||
header
|
||||
{
|
||||
height:60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
header
|
||||
{font-size: 0.75em;}
|
||||
|
||||
footer ul
|
||||
{line-height: 25px;}
|
||||
|
||||
header ul
|
||||
{line-height: 75px;}
|
||||
}
|
||||
|
||||
#zerozozio
|
||||
{
|
||||
margin:1em;
|
||||
text-align:right;
|
||||
}
|
||||
#zerozozio a, span
|
||||
{
|
||||
padding:0 0.3em;
|
||||
}
|
247
front/public/themes/wikilerni/css/common.css
Normal file
247
front/public/themes/wikilerni/css/common.css
Normal file
@ -0,0 +1,247 @@
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Light/Millimetre-Light_web.woff);
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Regular/Millimetre-Regular_web.woff);
|
||||
font-weight: regular;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Millimetre;
|
||||
src: url(../webfonts/Bold/Millimetre-Bold_web.woff);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
body
|
||||
{margin: 0px;
|
||||
overflow-x: hidden;
|
||||
background-color: #8c599c;}
|
||||
|
||||
body, a, input
|
||||
{
|
||||
font-family: Millimetre;
|
||||
font-weight: regular;
|
||||
color: rgba(255,255,255,1);
|
||||
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
input, #headLinks a, #footLinks a, a.button,
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a
|
||||
{
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color: rgba(0,0,0,0.66);
|
||||
text-shadow: 0px 1px 0px rgba(255,255,255,0.75);
|
||||
}
|
||||
a.button:hover
|
||||
{
|
||||
color:white;
|
||||
text-shadow:none;
|
||||
}
|
||||
|
||||
header,
|
||||
footer
|
||||
{background-color: #FF8800;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.75);
|
||||
box-shadow: 0px 0px 10px black;
|
||||
font-size: 1.5em;
|
||||
width: 100%;
|
||||
height:100px;
|
||||
margin-top: 1em;
|
||||
transform: rotate(0.66deg);}
|
||||
|
||||
header img
|
||||
{max-height:80px;
|
||||
margin-left:10px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;}
|
||||
|
||||
header ul, footer ul
|
||||
{list-style-type: none;
|
||||
display: inline-block;
|
||||
float: right;
|
||||
line-height: 50px;}
|
||||
|
||||
header ul li
|
||||
{float: right;
|
||||
display: block;}
|
||||
|
||||
footer ul li
|
||||
{display:inline-block;}
|
||||
|
||||
footer ul
|
||||
{width: 100%;}
|
||||
|
||||
header ul li::after,
|
||||
footer ul li::after
|
||||
{width: 1px;
|
||||
height: 80px;
|
||||
display: block;
|
||||
float: right;
|
||||
content: '';
|
||||
margin-left: 1em;
|
||||
margin-top: -20px;
|
||||
background: linear-gradient(to top, rgba(255,255,255,0.25), rgba(255,255,255,0.0));}
|
||||
|
||||
header ul li::before,
|
||||
footer ul li::before
|
||||
{width: 1px;
|
||||
height: 80px;
|
||||
display: block;
|
||||
float: right;
|
||||
content: '';
|
||||
margin-top: -20px;
|
||||
margin-right: 1em;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.25), rgba(0,0,0,0.0));}
|
||||
|
||||
header ul li:first-child::after,
|
||||
footer ul li:last-child::after
|
||||
{display: none;}
|
||||
|
||||
header ul li:first-child::before,
|
||||
footer ul li:last-child::before
|
||||
{display: none;}
|
||||
|
||||
header ul li:first-child,
|
||||
footer ul li:first-child
|
||||
|
||||
{margin-right: 1em;}
|
||||
|
||||
footer
|
||||
{transform: rotate(-0.66deg);
|
||||
clear: both;
|
||||
text-align: center;}
|
||||
|
||||
fieldset
|
||||
{border: 0px;}
|
||||
|
||||
.needJS
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.engraved
|
||||
{
|
||||
color: white;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, 1);
|
||||
font-family: verdana;
|
||||
}
|
||||
|
||||
.framed
|
||||
{
|
||||
border: 1px solid rgba(0, 0, 0, 0.33);
|
||||
border-radius: 5px;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,0.5), inset 0px 1px 0px rgba(255,255,255,1);
|
||||
background-image: url('../img/background-texture.png');
|
||||
display: inline-block;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
#explanations
|
||||
{
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#explanations p
|
||||
{
|
||||
margin:1.3em;
|
||||
}
|
||||
|
||||
.cardboard, .error, .success, .info
|
||||
{
|
||||
background-opacity: 0.75;
|
||||
background-image: url('../img/background-texture.png');
|
||||
}
|
||||
|
||||
/* This allow the motion of the button while overing without displacing the content of the page */
|
||||
.input_wrapper
|
||||
{
|
||||
height: 40px;
|
||||
display: inline-block;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
input[type=submit], input[type=text], input[type=email], input[type=password], .button
|
||||
{background-color: #8c599c;
|
||||
padding: 10px;
|
||||
border: 0px;
|
||||
border-radius: 3px;
|
||||
margin-top:-10px;
|
||||
color: white;
|
||||
font-family: sans;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
transition: 0.125s ease all;
|
||||
margin-top: 0px;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.66), inset 0px -1px 0px rgba(0, 0, 0,0.66), 0px 3px 8px rgba(0,0,0,0.66);}
|
||||
|
||||
input[type=submit]:hover, .button:hover
|
||||
{
|
||||
margin-top: 2px;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,0.66), inset 0px -1px 0px rgba(0, 0, 0,0.66), 0px 0px 5px rgba(0,0,0,0.66);
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=email] {
|
||||
box-shadow: inset 0px 1px 0px rgba(0,0,0,0.66), inset 0px -1px 0px rgba(255,255,255,0.66), inset 0px 3px 8px rgba(0,0,0,0.66);}
|
||||
|
||||
input[type=checkbox]
|
||||
{width:15px;
|
||||
height:15px;
|
||||
margin-left: 0px;
|
||||
margin-right: -16px;
|
||||
opacity:0.0;}
|
||||
|
||||
/* The following is a trick to force browser to let me redefine checkbox style */
|
||||
.checkbox_override
|
||||
{width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
border-top: 1px solid rgba(0,0,0,0.75);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.5);
|
||||
display: inline-block;}
|
||||
|
||||
input:hover ~ .checkbox_override
|
||||
{background-color: rgba(0, 0, 0, 0.125);}
|
||||
|
||||
input:checked ~ .checkbox_override {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.75);
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
p.error, p.success, p.info,
|
||||
div.error, div.success, div.info
|
||||
{
|
||||
width: calc(100% - 20px);
|
||||
height: auto;
|
||||
padding: 1em;
|
||||
opacity: 1;
|
||||
margin-left: 0px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.error {background-color: red;}
|
||||
.info {background-color: #8c599c;}
|
||||
.success {background-color: #00c684;}
|
||||
|
||||
#zerozozio
|
||||
{
|
||||
margin:1em;
|
||||
text-align:right;
|
||||
}
|
||||
#zerozozio a, span
|
||||
{
|
||||
padding:0 0.3em;
|
||||
}
|
160
front/public/themes/wikilerni/css/home-mobile.css
Normal file
160
front/public/themes/wikilerni/css/home-mobile.css
Normal file
@ -0,0 +1,160 @@
|
||||
#home
|
||||
{width: 80%;
|
||||
margin: auto;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
margin-top: -1.5em;
|
||||
padding-top: 1.5em;
|
||||
background-color: #FF8800;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.75);}
|
||||
|
||||
#home h1,
|
||||
#home h2
|
||||
{text-align: center;}
|
||||
|
||||
#home p
|
||||
{margin-left:1em;
|
||||
margin-right: 1em;}
|
||||
|
||||
#home form
|
||||
{border-top: 1px solid rgba(0, 0, 0, 0.5);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.5);
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.5);
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
padding-bottom: 1em;
|
||||
display: block;
|
||||
padding-top: 1em;
|
||||
text-align: center;
|
||||
margin-bottom: 1em;}
|
||||
|
||||
#home form input[type=text]
|
||||
{width: calc(49% - 20px);
|
||||
margin-right: 1%;}
|
||||
|
||||
#home form input[type=submit]
|
||||
{width: 40%;}
|
||||
|
||||
#home form .line
|
||||
{
|
||||
margin-top: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#logo
|
||||
{width: 50%;
|
||||
margin: auto;
|
||||
display: block;}
|
||||
|
||||
#home .error, #home .info, #home .success
|
||||
{
|
||||
margin: 1em;
|
||||
width: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Sur tablette la troisième colonne vient se placer en dessous de la première ou de la deuxième (la plus courte des deux) */
|
||||
#triple-column
|
||||
{
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.column-1, .column-3, .column-2
|
||||
{
|
||||
width: 48%;
|
||||
float: left;
|
||||
margin-left:1.5%;
|
||||
}
|
||||
|
||||
.quiz
|
||||
{
|
||||
width: 100%;
|
||||
margin-bottom: 1em;
|
||||
background-color: #FF8800;
|
||||
border-radius: 5px;
|
||||
border-top: 1px solid rgba(255,255,255,0.66);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.66);
|
||||
box-shadow: 0px 0px 5px black;
|
||||
}
|
||||
.quiz h3
|
||||
{
|
||||
text-align: center;
|
||||
margin: 1em;
|
||||
}
|
||||
.quiz p
|
||||
{
|
||||
margin: 2em;
|
||||
text-align: justify;
|
||||
}
|
||||
.quiz p:last-child
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
.quiz-image-wrapper
|
||||
{
|
||||
width: 95%;
|
||||
background-size: cover;
|
||||
border-radius: 5px;
|
||||
border-top: 1px solid rgba(0,0,0,0.66);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.66);
|
||||
box-shadow: inset 0px 5px 5px rgba(0,0,0,0.33);
|
||||
background-repeat: no-repeat;
|
||||
margin: auto;
|
||||
}
|
||||
.quiz-image-wrapper img
|
||||
{
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav#pagination
|
||||
{
|
||||
clear:both;
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
margin:0.5em;
|
||||
}
|
||||
nav#pagination div
|
||||
{
|
||||
flex: 0 0 50%;
|
||||
text-align:center;
|
||||
}
|
||||
nav#pagination a
|
||||
{
|
||||
background-image: url('../img/background-texture.png');
|
||||
}
|
||||
|
||||
@media screen and (max-width: 520px)
|
||||
{
|
||||
/* Sur mobile, les colonnes se placent les unes sous les autres */
|
||||
#triple-column
|
||||
{
|
||||
display: block;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.column-1, .column-2, .column-3
|
||||
{
|
||||
width: 98%;
|
||||
float: left;
|
||||
margin-right: 1%;
|
||||
}
|
||||
|
||||
#home form
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
#home form input[type=text]
|
||||
{
|
||||
width: calc(100% - 20px);
|
||||
margin-right: 0%;
|
||||
}
|
||||
#home form input[type=submit]
|
||||
{
|
||||
width: 100%;
|
||||
margin-top: 1em;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
131
front/public/themes/wikilerni/css/home.css
Normal file
131
front/public/themes/wikilerni/css/home.css
Normal file
@ -0,0 +1,131 @@
|
||||
#home
|
||||
{width: 50%;
|
||||
margin: auto;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 5px black;
|
||||
margin-top: -1.5em;
|
||||
padding-top: 1.5em;
|
||||
background-color: #FF8800;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.75);}
|
||||
|
||||
#home h1,
|
||||
#home h2
|
||||
{text-align: center;}
|
||||
|
||||
#home p
|
||||
{margin-left:1em;
|
||||
margin-right: 1em;}
|
||||
|
||||
#home form
|
||||
{border-top: 1px solid rgba(0, 0, 0, 0.5);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.5);
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.5);
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
padding-bottom: 1em;
|
||||
display: block;
|
||||
padding-top: 1em;
|
||||
text-align: center;
|
||||
margin-bottom: 1em;}
|
||||
|
||||
#home form input[type=text]
|
||||
{width: calc(66% - 20px);
|
||||
margin-right: 1%;}
|
||||
|
||||
#home form input[type=submit]
|
||||
{width: 32%;}
|
||||
|
||||
#home form input[type=submit]
|
||||
{width: 32%;}
|
||||
|
||||
#home form .line
|
||||
{
|
||||
margin-top:0.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#logo
|
||||
{width: 33%;
|
||||
margin: auto;
|
||||
display: block;}
|
||||
|
||||
|
||||
#home .error, #home .info, #home .success
|
||||
{
|
||||
margin: 1em;
|
||||
width: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Les colonnes de l'enfer ! */
|
||||
#triple-column
|
||||
{
|
||||
width: 95%;
|
||||
margin: auto;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.column-1,
|
||||
.column-2,
|
||||
.column-3
|
||||
{
|
||||
float: left;
|
||||
width: 32%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.column-1, .column-2
|
||||
{
|
||||
margin-right: 1.33%;
|
||||
}
|
||||
.quiz
|
||||
{
|
||||
width: 100%;
|
||||
margin-bottom:1em;
|
||||
background-color: #FF8800;
|
||||
border-radius: 5px;
|
||||
border-top: 1px solid rgba(255,255,255,0.66);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.66);
|
||||
box-shadow: 0px 0px 5px black;
|
||||
}
|
||||
.quiz h3
|
||||
{
|
||||
text-align: center;
|
||||
margin:1em;
|
||||
}
|
||||
.quiz p
|
||||
{
|
||||
margin: 2em;
|
||||
text-align: left;
|
||||
}
|
||||
.quiz p:last-child
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
.quiz-image-wrapper
|
||||
{
|
||||
width: 95%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 5px;
|
||||
border-top: 1px solid rgba(0,0,0,0.66);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.66);
|
||||
box-shadow: inset 0px 5px 5px rgba(0,0,0,0.33);
|
||||
margin: auto;
|
||||
}
|
||||
.quiz-image-wrapper img
|
||||
{
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav#pagination
|
||||
{
|
||||
clear:both;
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
margin:0.5em;
|
||||
}
|
||||
nav#pagination div
|
||||
{
|
||||
flex: 0 0 50%;
|
||||
text-align:center;
|
||||
}
|
28
front/public/themes/wikilerni/css/links-page-mobile.css
Normal file
28
front/public/themes/wikilerni/css/links-page-mobile.css
Normal file
@ -0,0 +1,28 @@
|
||||
#prompt, #login
|
||||
{background-color: #FF8800;
|
||||
width: 75%;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
margin-top: -1em;
|
||||
padding-top:1.5em;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.8);
|
||||
box-shadow: 0px 0px 5px rgba(0,0,0,0.75);}
|
||||
|
||||
#prompt img
|
||||
{width: 33%;}
|
||||
|
||||
#prompt p
|
||||
{
|
||||
background-color: #FF8800;
|
||||
box-shadow: 0px 0px 5px rgba(0,0,0,0.75);
|
||||
width: 102%;
|
||||
margin-left:-1%;
|
||||
border-radius: 5px;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
font-size:0.8em;
|
||||
letter-spacing: 0.3em;
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.66);
|
||||
}
|
27
front/public/themes/wikilerni/css/links-page.css
Normal file
27
front/public/themes/wikilerni/css/links-page.css
Normal file
@ -0,0 +1,27 @@
|
||||
#prompt, #login
|
||||
{background-color: #FF8800;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
margin-top: -1em;
|
||||
padding-top:1.5em;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.8);
|
||||
box-shadow: 0px 0px 5px rgba(0,0,0,0.75);}
|
||||
|
||||
#prompt img
|
||||
{width: 33%;}
|
||||
|
||||
#prompt p, #login h1
|
||||
{
|
||||
background-color: #FF8800;
|
||||
box-shadow: 0px 0px 5px rgba(0,0,0,0.75);
|
||||
width: 102%;
|
||||
margin-left:-1%;
|
||||
border-radius: 5px;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
letter-spacing: 0.5em;
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.66);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user