Creation container pour l'API reviews

This commit is contained in:
2023-01-11 11:31:33 +01:00
parent 81dd02943a
commit b5e34fd898
21 changed files with 128 additions and 2 deletions

View File

@@ -0,0 +1,24 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View File

@@ -0,0 +1,10 @@
# Nom d'utilisateur de la base de donnée
DB_USER=
# Mot de passe pour la base de donnée
DB_PASSWORD=
# Addresse du serveur de la base de donnée
DB_HOST=
# Nom de la base de donnée
DB_NAME=
# Port sur lequel ouvrir le serveur
PORT=

View File

@@ -0,0 +1,9 @@
FROM node:lts-alpine
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
RUN npm install --production --silent && mv node_modules ../
COPY . .
EXPOSE 8080
RUN chown -R node /usr/src/app
USER node
CMD ["node", "index.js"]

View File

@@ -0,0 +1,33 @@
# Serveur de traitement des données
Ce serveur s'occupe de fournir une API web pour pourvoir ajouter des avis sur la borne, réxupérer des avis, calculer et fournir les statistiques sur ces avis
# Installation
* Pour faire fonctinoner le serveur sur vos machines il y a 3 choses a faire
1. Installer node js : https://nodejs.org/en/download/
2. Ouvrir un terminal et aller dans ce dossier (code/server) et tapper `npm install` pour installer les pacakges nécessaires
3. copier le fichier `.env_template` et le nommer `.env` et remplir les variables (cela est fait pour le pas mettre les mots de passes sur le gitlab, faites attention de ne jamais commit le fichier .env !!)
4. pour lancer le serveur faire `node index.js`
# Utilisation
## Avis laissés sur la borne (hors réseaux sociaux)
### Routes GET :
- `/borne/get_last_reviews?limit=LIM` : renvoie les LIM derniers avis sur la borne
- `/borne/get_review?id=ID` : renvoie les infos sur l'avis d'in ID
- `/borne/get_criteres` : renvoie les criteres de notations valide pour les notes autres
- `/borne/notes_autres?critere=CRIT&limit=LIM` : renvoie les LIM dernières notes sur le critère CRIT
- `/borne/notes_autres?id=ID&limit=LIM` : renvoie toutes les notes spécifiques liées à l'avis ID
### Routes POST
- `/add_review` : Ajoute une review et un auteur, paramètres POST :
* [OBLIGATOIRE] `note` : note principale de la review entre 0 et 10 compris
* [OBLIGATOIRE] `source` : nom de la source de l'avis, doit être `borne` ou `website` pour resp la borne et le site
* `auteur_age` : age de l'auteur
* `auteur_sexe` : sexe de l'auteur (valeurs valide 'f', 'h', 'a')
* `commentaire` : Commentaire laissé avec l'avis
* `notes autres` : sous la forme
```json
{
"critere1": 8,
"critere2": 2,
"critere3": 0
}
```

View File

@@ -0,0 +1,200 @@
import conn from '../database.js';
/**
* Renvoie les derniers avis laissés sur la borne trié par ordre chronologque décroissant
* @param {Number} limit Nombre d'avis a afficher
* @returns Une liste d'objets de la forme {id: id de l'avis, date: date de l'avis, note_principale: note sur 10, commentaire: avis textuel, nom_source, sexe_auteur, age_auteur}
*/
const getLastReviews = (limit=10) => {
return new Promise((resolve, reject) => {
let sql = `SELECT borne_avis.id,date,note_principale,commentaire,sources.nom as nom_source, borne_auteurs.sexe as sexe_auteur, borne_auteurs.age as age_auteur
FROM borne_avis
JOIN sources ON sources.id = source_id
JOIN borne_auteurs ON borne_auteurs.id = id_auteur
ORDER BY borne_avis.id DESC LIMIT ?`;
conn.query(sql, [limit], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res)
}
})
})
}
/**
* Renvoie les informations sur un avis avec un ID spécifique
* @param {Number} id Id de la review
* @returns Un objet de la forme des objets dans la table borne_avis ayant l'id id s'il existe, renvoie une erreur sinon
*/
const getReviewFromId = (id) => {
return new Promise((resolve, reject) => {
let sql = `SELECT * FROM borne_avis WHERE id = ? LIMIT 1`;
conn.query(sql, [id], (err, res) => {
if(err) {
reject(err);
}else {
if(res.length != 1) {
reject(new Error("Avis avec cet ID non trouvé"))
}else {
resolve(res[0])
}
if(res.length != 1) {
reject(new Error("Avis avec cet ID non trouvé"))
}else {
resolve(res[0])
}
}
})
})
}
/**
* Renvoie tout les critères de notation valides
* @returns Une liste d'objets de la forme {id,nom}
*/
const getCriteres = () => {
return new Promise((resolve, reject) => {
let sql = `SELECT * FROM borne_criteres`;
conn.query(sql, [limit], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res)
}
})
})
}
/**
* Renvoie les "limit" notes les plus récentes laissées pour un critère spécifié
* @param {String} critere Nom de critère
* @param {Number} limit Nombre max de note a afficher
* @returns une liste d'objets de la forme {id,date,critere,note,avis_id:id de l'avis lié a cette note}
*/
const getNotesAutresFromCritere = (critere,limit=10) => {
return new Promise((resolve, reject) => {
let sql = `SELECT borne_notes_autre.id as id,date,borne_criteres.nom as critere, note, avis_id
FROM borne_notes_autre
JOIN borne_criteres ON borne_criteres.id = critere_id
WHERE borne_criteres.nom = ?
ORDER BY borne_notes_autre.id DESC LIMIT ? ;`;
conn.query(sql, [critere,limit], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res)
}
})
})
}
/**
* Renvoie toutes les notes sur des critères spécifiques laissée pour un avis spécifique
* @param {Number} reviewId Id de l'avis
* @returns une liste d'objets de la forme {id,critere:nom du critère, note:note sur 10}
*/
const getNotesAutresFromReview = (reviewId) => {
return new Promise((resolve, reject) => {
let sql = `SELECT borne_notes_autre.id as id,borne_criteres.nom as critere, note
FROM borne_notes_autre
JOIN borne_criteres on borne_criteres.id = critere_id
WHERE avis_id = ?
ORDER BY borne_notes_autre.id DESC`;
conn.query(sql, [reviewId], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res)
}
})
})
}
/**
* Renvoie les dernières statistiques
* @param {String} interval Interval de temps de la statistique, valeurs possibles : "jour","mois","semaine","annee"
* @param {Number} limit Nombre max de stats a renvoyer
* @returns Une liste d'objet ou chaque objet correspond a une stat sur une periode donnée (par ex une stat hebdo datée du 07/01 correspond a une stat sur la semaine du 01/01 au 07/01), ces objets sont de la forme
*/
const getStats = (interval, limit=10) => {
return new Promise((resolve, reject) => {
if(!["jour","mois","semaine","annee"].includes(interval)) {
reject(new Error("Invalid time interval"));
return;
}
let sql = `SELECT * FROM stats_general_${interval} ORDER BY id DESC LIMIT ?;`;
conn.query(sql, [limit], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res)
}
})
})
}
/*
Ces fonction sont des handlers pour les routes express, elles sont appelées par les routes et renvoient les données au format JSON
*/
export const handleGetLastReviews = (req, res) => {
getLastReviews(req.query.limit)
.then((reviews) => {
res.send(reviews);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}
export const handleGetReview = (req, res) => {
getReviewFromId(req.query.id)
.then((review) => {
res.send(review);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}
export const handleGetCriteres = (req, res) => {
getCriteres()
.then((criteres) => {
res.send(criteres);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}
export const handleGetNotesAutres = (req, res) => {
if(req.query.critere) {
getNotesAutresFromCritere(req.query.critere, req.query.limit)
.then((notes) => {
res.send(notes);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}else if(req.query.id) {
getNotesAutresFromReview(req.query.id)
.then((notes) => {
res.send(notes);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}else {
res.status(500).send("Error: no critere or id specified");
}
}
export const handleGetStats = (req, res) => {
getStats(req.query.interval, req.query.limit)
.then((stats) => {
res.send(stats);
})
.catch((err) => {
res.status(500).send("Error: " + err.message);
});
}

View File

@@ -0,0 +1,84 @@
import { Auteur, Review } from './structures.js';
import conn from '../database.js';
import {getSourceId} from '../utils.js';
/**
* Ajoute un nouvel auteur de commentaire a la BDD
* @param {Auteur} author L'auteur a ajouter
* @returns une Promise qui renvoie l'id de l'utilisateur
*/
const addAuteur = (author) => {
return new Promise((resolve,reject) => {
const sql = "INSERT INTO borne_auteurs (age, sexe) VALUES (?);"
conn.query(sql, [[author.age, author.sexe]], (err, res) => {
if(err) {
reject(err)
}else {
resolve(res.insertId);
}
})
})
}
//Ajoute une note sur un critère spécifique dans la BDD
const addSpecificRating = (reviewId, label, value) => {
return new Promise((resolve, reject) => {
const sql = "INSERT INTO borne_notes_autre(critere_id, avis_id, note) VALUES ((SELECT id FROM borne_criteres WHERE borne_criteres.nom = ?), ?, ?)"
conn.query(sql, [label,reviewId, value], (err, res) => {
if(err) {
reject(err);
}else {
resolve(res.insertId);
}
})
})
}
/**
* Ajoute un avis a la base de donnée
* @param {Review} review la review a ajouter
* @param {Number} authorId l'ID de l'auteur de l'avis dans la BDD
* @param {Number} sourceId l'ID de la source de l'avis dans la BDD
* @returns une Promise qui renvoie l'id de l'avis
*/
const addReview = (review, authorId, sourceId) => {
return new Promise((resolve, reject) => {
const sql = "INSERT INTO borne_avis (id_auteur, note_principale, commentaire, source_id) VALUES (?);"
conn.query(sql, [[authorId, review.note, review.commentaire, sourceId]], (err, res) => {
if(err) {
reject(err)
}else {
resolve(res.insertId);
}
})
})
}
/**
* Traite une requête POST qui contient les valeurs nécessaires pour ajouter un nouvel avis dans la BDD
* Essaie d'ajouter l'avis et l'auteur dans la BDD, sinon renvoie l'erreur avec un code 500
* @param {*} req requete
* @param {*} res reponse
*/
export const addReviewFromRequest = async (req,res) => {
try {
let notes_autre = {}
try{
notes_autre = JSON.parse(req.body.notes_autre);
}catch(err){};
const author = new Auteur(req.body.auteur_age,req.body.auteur_sexe);
const review = new Review(author, req.body.note, req.body.source, req.body.commentaire, notes_autre)
let authorId = await addAuteur(author);
let sourceId = await getSourceId(review.source);
let reviewId = await addReview(review, authorId, sourceId );
for(let label in review.notesAutre) {
await addSpecificRating(reviewId, label, review.notesAutre[label]);
}
res.send("success")
}catch(err) {
res.status(500).send("Error : " + err.message)
}
}

View File

@@ -0,0 +1,52 @@
//Liste des valeurs valides pour le sexe d'un utilisateur
const validSexes = ["h","f","a"];
//Classe pour représenter un avis laissé sur la borne que ce soit par l'interface web ou par un geste
export class Review {
/**
* Constructeur
* @param {Auteur} auteur L'auteur de l'avis
* @param {Number} note La note principale entre 0 et 10 compris
* @param {String} source La source de l'avis, doit être une entrée dans la table soruces de la bdd
* @param {String} commentaire Le commentaire lié a l'avis
* @param {Object} notesAutre Les notes secondaires laissées, sous la forme d'un object ou les clés sont les labels de chaque notes et les valeurs sont des notes entre 0 et 10 compris
*/
constructor(auteur, note, source, commentaire=null, notesAutre={}) {
this.auteur = auteur;
this.note = note;
this.source = source;
this.commentaire = commentaire;
this.notesAutre = notesAutre;
//On vérifie si toutes les données sont correctes
if(note < 0 || note > 10) {
throw new Error("Note principale invalide");
}
for(let nom in notesAutre) {
if(notesAutre[nom] < 0 || notesAutre[nom] > 10) {
throw new Error("Note " + notesAutre[nom] +"/10 invalide");
}
}
}
}
//Classe qui représente l'auteur d'un avis
export class Auteur {
/**
* Constructeur
* @param {Number} age L'age de l'auteur
* @param {String} sexe Le sexe de la personne (doit être dans l'array validSexes défini au début de ce fichier)
*/
constructor(age=null, sexe=null) {
this.age = age;
this.sexe = sexe;
//Verification des données
if(sexe != undefined && !validSexes.includes(sexe) ) {
throw new Error("Sexe invalide");
}
if(age != undefined && age <= 0) {
throw new Error("Age invalide");
}
}
}

View File

@@ -0,0 +1,15 @@
import * as dotenv from 'dotenv'
import mysql from 'mysql2';
dotenv.config();
const conn = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
multipleStatements: true,
});
conn.connect();
export default conn;

View File

@@ -0,0 +1,29 @@
import requests
#Exemple ajout d'un commentaire depuis la borne (site ou geste)
avis = {
"note": 8,
"source": "borne",
#Optionel
"auteur_age": 20,
"notes_autre": '{"proprete":8,"calme":10}',
"auteur_sexe": 'f',
"commentaire": "Commentaire"
}
# res = requests.post("http://localhost:8080/add_review", data=avis)
# print(res.text)
#Exemple ajout d'un commentaire trouvé sur les réseaux sociaux
avis = {
"auteur_nom": "michel",
"source": "instagram",
"note": 8,
"date": "2022-12-24",
#Optionel
"commentaire": "J'ai beaucoup aimé !",
"lien": "https://instagram.com/si_insta_avait_des_liens_vers_des_commentaires_faudrait_le_mettre_ici",
"auteur_lien": "https://instagram.com/michel",
}
res = requests.post("http://localhost:8080/add_social_review", data=avis)
print(res.text)

28
code/reviews_api/index.js Normal file
View File

@@ -0,0 +1,28 @@
import * as dotenv from 'dotenv';
import express from 'express';
import bodyParser from 'body-parser';
import { addReviewFromRequest } from './borne/post_handler.js';
import { addSocialReviewFromRequest } from './reseaux_sociaux/post_handler.js';
import { startCronJobs } from './stats/update_stats.js';
import * as borneHandler from './borne/get_handler.js';
const app = express();
console.log(process.env);
app.use(bodyParser.urlencoded({extended:true}))
dotenv.config()
app.post('/add_review', (req,res) => addReviewFromRequest(req,res));
app.post('/add_social_review', (req,res) => addSocialReviewFromRequest(req,res));
app.get('/borne/get_last_reviews', borneHandler.handleGetLastReviews);
app.get('/borne/get_review', borneHandler.handleGetReview);
app.get('/borne/get_criteres', borneHandler.handleGetCriteres);
app.get('/borne/notes_autres', borneHandler.handleGetNotesAutres);
app.get('/borne/get_stats', borneHandler.handleGetStats);
startCronJobs();
app.listen(process.env.PORT, () => {
console.log("Server démaré sur le port " + process.env.PORT)
})

1278
code/reviews_api/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Telereview",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.1",
"cron": "^2.1.0",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"mysql2": "^2.3.3"
}
}

View File

@@ -0,0 +1,85 @@
import { ReseauxAuteur, ReseauxReview } from './structures.js';
import conn from '../database.js';
import {getSourceId} from '../utils.js';
/**Récupérer l'id d'un auteur particulier dans la base de donnée s'il existe
* @param {ReseauxAuteur} author L'auteur dont on veut l'id*
* @returns Une Promise qui donne l'id de l'utilisateur ou null si il n'existe pas
*/
const getAuteurId = (author) => {
return new Promise(async (resolve,reject) => {
const sql = "SELECT id FROM reseaux_sociaux_auteurs WHERE nom_utilisateur = ? AND source_id = ? AND lien = ?;"
let sourceId = await getSourceId(author.source);
let query = conn.query(sql, [author.nom, sourceId, author.lien], (err, res) => {
if(err) {
reject(new Error(err.message))
}else {
if(res.length > 0) {
resolve(res[0].id);
}else {
resolve(null);
}
}
})
})
}
/**
* ajoute un auteur de commentaire sur les réseaux sociaux a la bdd
* @param {ReseauxAuteur} author
* @returns Une Promise qui donne l'id de l'utilisateur
*/
const addAuteur = (author, sourceId) => {
return new Promise((resolve,reject) => {
const sql = "INSERT INTO reseaux_sociaux_auteurs (nom_utilisateur, source_id, lien) VALUES (?);"
conn.query(sql, [[author.nom,sourceId, author.lien]], (err, res) => {
if(err) {
reject(new Error(err.message))
}else {
resolve(res.insertId);
}
})
})
}
/**
* Ajoute un avis dans la BDD
* @param {ReseauxReview} review L'avis a ajouter
* @param {Number} authorId ID de l'auteur dans la bdd
* @param {Number} sourceId ID Du réseau social source dans la bdd
* @returns une Promise qui renvoie l'ID de la review
*/
const addReview = (review, authorId, sourceId) => {
return new Promise((resolve, reject) => {
const sql = "INSERT INTO reseaux_sociaux_avis (source_id, note, commentaire, auteur_id, lien_source, date) VALUES (?);"
conn.query(sql, [[sourceId, review.note, review.commentaire, authorId, review.lien, review.date]], (err, res) => {
if(err) {
reject(new Error(err.message))
}else {
resolve(res.insertId);
}
})
})
}
/**
* Traite une requête POST pour ajouter un avis récupéré sur les réseaux sociaux
* @param {*} req
* @param {*} res
*/
export const addSocialReviewFromRequest = async (req,res) => {
try {
const author = new ReseauxAuteur(req.body.auteur_nom, req.body.source, req.body.auteur_lien);
const review = new ReseauxReview(author, req.body.source, req.body.date, req.body.note, req.body.commentaire, req.body.lien)
let sourceId = await getSourceId(review.source);
let authorId = await getAuteurId(author);
if(authorId == null) {
authorId = await addAuteur(author, sourceId);
}
await addReview(review, authorId, sourceId);
res.send("success")
}catch(err) {
res.status(500).send("Error : " + err.message)
}
}

View File

@@ -0,0 +1,39 @@
import { Review } from "../borne/structures.js";
export class ReseauxReview extends Review{
/**
*
* @param {ReseauxAuteur} auteur Auteur de l'avis
* @param {String} source La source de l'avis
* @param {String} date La date de l'avis au format YYYY-MM-DD
* @param {Number} note Nombre entre 0 et 10, la note attribuée
* @param {String} commentaire Le commentaire laissé par l'utilisateur
* @param {String} lien Lien vers le commentaire
*/
constructor(auteur, source, date, note=null, commentaire=null, lien=null,) {
super(auteur,note,source,commentaire);
this.lien = lien;
this.date = date;
if((typeof lien !== "string" && lien != null)) {
throw new Error("Lien invalide");
}
}
}
export class ReseauxAuteur {
/**
*
* @param {String} nom Nom de l'utilisateur
* @param {String} source Réseau social de provenance de l'utilisateur
* @param {String} lien Lien vers le profil de l'utilisateur
*/
constructor(nom, source, lien=null) {
this.nom = nom;
this.source = source;
this.lien = lien;
if((typeof this.nom !== "string") || (typeof this.source !== "string")){
throw new Error("Auteur invalide");
}
}
}

View File

@@ -0,0 +1,50 @@
/*
Dans cette requête il faut replacer DAY_COUNT_DELAY par le nombre de jours sur lequel calculer les stats, STATS_GENERAL_TABLE_NAME par la table dans laquelle mettre les stats globales (par exemple stats_general_jour si les valeurs sont calculées sur 1 jour) et pareil pour STATS_AUTRES_TABLE_NAME
C'est un peu bizzare comme technique mais j'ai pas trouvé de meilleur solution
*/
SET @date_limite = DATE_ADD(NOW(), INTERVAL -DAY_COUNT_DELAY DAY);
/*
On récupère les notes notes moyennes sur la periode, en séparant global, borne et site
*/
SELECT @moyenne_globale:=AVG(note_principale)
FROM borne_avis
WHERE borne_avis.date > @date_limite;
SELECT @moyenne_borne:=AVG(note_principale)
FROM borne_avis
JOIN sources ON sources.id = borne_avis.source_id
WHERE borne_avis.date > @date_limite AND sources.nom = "borne";
SELECT @moyenne_site:=AVG(note_principale)
FROM borne_avis
JOIN sources ON sources.id = borne_avis.source_id
WHERE borne_avis.date > @date_limite AND sources.nom = "website";
/*
On récupère la distribution de sexes
*/
SELECT @stats_f:=COUNT(*) FROM borne_avis
JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id
WHERE sexe='f' AND date > @date_limite;
SELECT @stats_h:=COUNT(*) FROM borne_avis
JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id
WHERE sexe='h' AND date > @date_limite;
SELECT @stats_a:=COUNT(*) FROM borne_avis
JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id
WHERE sexe='a' AND date > @date_limite;
SET @dist_sexe = CONCAT(@stats_f,",",@stats_h,",",@stats_a);
INSERT INTO STATS_GENERAL_TABLE_NAME (moyenne_globale, moyenne_borne, moyenne_site, dist_sexe) VALUES (@moyenne_globale, @moyenne_borne, @moyenne_site, @dist_sexe);
INSERT INTO STATS_AUTRES_TABLE_NAME (critere_id, note)
SELECT critere_id, AVG(note) as moyenne FROM borne_notes_autre
WHERE borne_notes_autre.date > @date_limite
GROUP BY critere_id
/*
TODO : Calcul de la distribution d'age
*/

View File

@@ -0,0 +1,69 @@
import conn from '../database.js';
import fs from "fs";
import { CronJob } from 'cron';
/**
* Calcules les stats sur une periode donnée et les stocke dans la BDD
* @param {Number} timePeriod Periode de temps sur laquelle calculer les données. Par exemple 7 si on veut faire les stats des 7 derniers jours
* @param {String} generalTableName Nom de la table dans laquelle mettre les statistiques générales (tables valides : stats_general_jour stats_general_semaine stats_general_mois stats_general_annee)
* @param {*} otherTableName Nom de la table dans laquelle mettre les statistiques spécifiques (tables valides : stats_autres_jour stats_autres_autres_autres_mois stats_general_annee)
* @returns Une Promise qui résout si la requête a fonctionnée
*/
const computeStats = async (timePeriod, generalTableName, otherTableName) => {
return new Promise((resolve, reject) => {
let sql = fs.readFileSync("stats/update_request.sql").toString();
sql = sql
.replace(new RegExp("DAY_COUNT_DELAY",'g'), timePeriod.toString())
.replace(new RegExp("STATS_GENERAL_TABLE_NAME", 'g'), generalTableName)
.replace(new RegExp('STATS_AUTRES_TABLE_NAME', 'g'), otherTableName)
conn.query(sql, (err, res) => {
if(err) {
reject(err)
}else {
resolve();
}
});
})
}
export const startCronJobs = () => {
//Update les stats journalières tout les jours a minuit
new CronJob(
'0 0 * * * * ',
() => {
computeStats(1,"stats_general_jour","stats_autres_jour");
},
null,
true
)
//update les stats de la semaine tous les lundis a minuit
new CronJob(
'0 0 * * 1 * ',
() => {
computeStats(7,"stats_general_semaine","stats_autres_jour");
},
null,
true
)
//update les stats mensuelles les 1er du mois a minuit
new CronJob(
'0 0 1 * * * ',
() => {
computeStats(30, "stats_general_mois","stats_autres_mois");
},
null,
true
)
//update les stats annuelles les premire de l'an a minuit
new CronJob(
'0 0 1 1 * * ',
() => {
computeStats(365, "stats_general_annee","stats_autres_annee");
},
null,
true
)
console.log("All cronjobs initiated")
}

19
code/reviews_api/utils.js Normal file
View File

@@ -0,0 +1,19 @@
import conn from './database.js';
/**
* Renvoie l'ID dans la BDD d'une source de donnée
* @param {String} source la source dont on veut récup l'id
* @returns une promise qui renvoie l'id de la source
*/
export const getSourceId = (source) => {
return new Promise((resolve, reject) => {
const sql = "SELECT id from sources WHERE nom = ?";
conn.query(sql, [source], (err, res) => {
if(res.length == 0) {
reject(new Error("Invalid source"))
}else {
resolve(res[0].id);
}
})
})
}

View File

@@ -0,0 +1,6 @@
while ! wget $DB_HOST:3306;
do
sleep 1
echo "Waiting for database connection..."
done
node index.js