This commit is contained in:
Emmanuel Viennet 2021-05-02 15:55:53 +02:00
commit 6bb6f29e5b
15 changed files with 1019 additions and 0 deletions

View File

@ -8,6 +8,7 @@ Avec Anaconda:
conda install ruamel
conda install ruamel.yaml
pip install docx2python
pip install Jinja2
Sans Anaconda, remplacer `conda` par `pip`.
@ -37,6 +38,11 @@ par exemple:
cd python
python export_yaml_to_latex.py -a
### Génération du Html
cd html
python export_yaml_to_html.py
### Génération de PDF
cd latex
@ -47,6 +53,7 @@ Le résultat est `pn_formation.pdf`.
## Organisation des fichiers
html/export fichiers html générés par export_yaml_to_html.py à partir des yaml
python/import fichiers docx à traiter
python/export fichier yaml générés par export_docx_to_yaml.py à partir des docx
yaml/ressources versions éditées manuellement ??

19
html/ACTemplate.html Normal file
View File

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block title %}{{data["ac"]}}{% endblock %}
{% block content %}
{% include "navigation.html" %}
<div class="content">
<h1>{{data["code"]}}</h1>
<p>{{data["titre"]}}</p>
<h1 class="title">Liste des SAÉs mobilisés</h1>
<ul>
{% for sae in data["sae"] %}
<li>{{sae["code"]}} - {{sae["titre"]}}</li>
{% endfor %}
</ul>
</div>
{% include "navigation.html" %}
{% endblock %}

View File

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% block title %}{{rt}}{% endblock %}
{% block content %}
{% include "navigation.html" %}
<table class="table is-bordered is-hoverable is-fullwidth">
<tbody>
{% for categorie, valeur in data.items() %}
<tr>
<th>{{categorie.capitalize()}}</th>
<td>
{%- if categorie == "composantes" or categorie == "situations" -%}
<div class="content">
<ul>
{% for valeur in valeur %}
<li>{{valeur}}</li>
{% endfor %}
</ul>
</div>
{% elif categorie == "niveaux" -%}
<div class="content">
<ul>
{% for nom, acs in valeur.items() %}
<li>{{nom}}</li>
<ul>
{% for ac in acs %}
{% if ac[:2] == "AC" %}
<li><a class="tag is-info" href="{{ac}}.html">{{ac}}</a> - {{acs[ac]}}</li>
{% else %}
<li>{{ac}}</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
</ul>
</div>
{% else -%}
<div class="content">{{valeur}}</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include "navigation.html" %}
{% endblock %}

42
html/InfoTemplate.html Normal file
View File

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}{{data.code}} - {{data.nom}}{{data.titre}}{% endblock %}
{% block content %}
{% include "navigation.html" %}
<table class="table is-bordered is-hoverable is-fullwidth">
<tbody>
{% for categorie, valeur in data.items() %}
<tr>
<th>{% if rename and rename[categorie] %}{{rename[categorie]}}{% else %}{{categorie.capitalize()}}{% endif %}</th>
<td>
{#- Gestion des tableaux #}
{% if categorie == "motscles" -%}
<div class="tags">{% for mot in valeur %}<span class="tag is-info">{{mot}}</span>{% endfor %}</div>
{#- Gestion des saes #}
{% elif categorie == "sae" or categorie == "ressources" -%}
<div class="tags">{% for val in valeur %}<a class="tag is-info" href='{{val.replace("É","E")}}.html'>{{val}}</a>{% endfor %}</div>
{#- Gestion des ACS #}
{% elif categorie == "acs" -%}
<div class="tags">{% for rt,acs in valeur.items() %}{% for ac in acs %}<a class="tag is-info" href="{{ac}}.html">{{ac}}</a>{% endfor %}{% endfor %}</div>
{#- Gestion des coeffs #}
{% elif categorie == "coeffs" -%}
<div class="tags">{% for rt, coeff in valeur.items() %}<a class="tag is-info" href="{{rt}}.html">{{rt}} : {{coeff}}</a>{% endfor %}</div>
{#- Gestion des exemples #}
{% elif categorie == "exemples" -%}
{% for exemple in valeur %}<a href='{{exemple.exemple["code"].replace("É","E") + "_exemple" + loop.index|string}}.html'>Exemple{{loop.index}}</a>{% if not loop.last %} - {% endif %}{% endfor %}
{#- Gestion des prerequis #}
{% elif categorie == "prerequis" -%}
{% if valeur != "Aucun" %}<div class="tags">{% for rt in valeur %}<span class="tag is-info">{{rt}}</span>{% endfor %}</div>
{%- else %}{{valeur}}{% endif %}
{#- Gestion des autres catégories #}
{% else -%}
<div class="content">{{valeur}}</div>
{%- endif -%}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include "navigation.html" %}
{% endblock %}

13
html/ListACsTemplate.html Normal file
View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Liste des {{title}}{% endblock %}
{% block content %}
<div class="content">
<ul><h1>Liste des {{title}}</h1>
{% for sem, liste in data.items() %}
{% for ac in liste %}
<li><a href='{{ac["code"] + ".html"}}'>{{ac["code"]}} - {{ac["titre"]}}</a></li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% block title %}Liste des Ressources du semestre {{sem}}{% endblock %}
{% block content %}
<div class="content">
<ul><h1>Liste des ressources du semestre {{sem}}</h1>
{% for ressource in data %}
<li><a href='{{ressource.ressource["code"] + ".html"}}'>{{ressource.ressource["code"]}} - {{ressource.ressource["nom"]}}</a></li>
{% endfor %}
</ul>
</div>
{% endblock %}

13
html/ListTemplate.html Normal file
View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Liste des {{title}}{% endblock %}
{% block content %}
<div class="content">
<ul><h1>Liste des {{title}}</h1>
{% for sem, liste in data.items() %}
{% for page in liste %}
<li><a href='{{page.getInfo()["code"].replace("É","E") + ".html"}}'>{{page.getInfo()["code"]}} - {{page.getInfo()["titre"]}}{{page.getInfo()["nom"]}}</a></li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endblock %}

80
html/base.html Normal file
View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html class="has-navbar-fixed-top">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="https://unpkg.com/lunr/lunr.js"></script>
{% block head %}{% endblock %}
</head>
<body>
<!-- Barre de navigation -->
<nav class="navbar is-primary is-spaced is-fixed-top py-0">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item is-size-5" href="https://scodoc.org/">ScoDoc</a>
<!-- Menu deroulant affiché uniquement sur mobile -->
<div class="navbar-burger">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="navbar-menu">
<div class="navbar-start">
<!-- Liste des catégories -->
<a class="navbar-item" href="index.html">Accueil</a>
<a class="navbar-item" href="ACs.html">ACs</a>
<a class="navbar-item" href="SAE.html">SAÉs</a>
<a class="navbar-item" href="ressources.html">Ressources</a>
<a class="navbar-item" href="ressourcesS1.html">Semestre 1</a>
<a class="navbar-item" href="ressourcesS2.html">Semestre 2</a>
<a class="navbar-item" href="index.html">Semestre 3</a>
<a class="navbar-item" href="index.html">Semestre 4</a>
<a class="navbar-item" href="index.html">Semestre 5</a>
<a class="navbar-item" href="index.html">Semestre 6</a>
</div>
<div class="navbar-end">
<a class="navbar-item" href="graph.html">Graphique</a>
<div class="navbar-item">
<!-- Bouton pour afficher un boite de dialogue pour la recherche -->
<button id="rechercheBouton" class="button is-rounded is-primary">
<span class="icon">
<i class="fas fa-search"></i>
</span>
<span>Rechercher</span>
</button>
</div>
</div>
</div>
</div>
</nav>
<!-- Boite de dialogue pour la recherche -->
<div id="rechercheBoite" class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title has-text-centered">Rechercher</p>
<button id="rechercheBoite-fermer" class="modal-close"></button>
</header>
<section class="modal-card-body">
<input id="rechercher" type="text" class="input mb-4" placeholder="Rechercher..." >
<div id="rechercheResultats" class="content"></div>
</section>
</div>
</div>
<!-- Contenu de la page -->
<div class="container">
<div class="box">
{% block content %}
{% endblock %}
</div>
</div>
<!-- Script JQuery -->
<script type="text/javascript" src="js/base.js"></script>
</body>
</html>

77
html/baseTemplate.js Normal file
View File

@ -0,0 +1,77 @@
$("document").ready(function() {
// Affichage mobile du menu | affiche/cache le menu contenant la liste des catégories
// en appuyant sur le burger/les trois traits
$(".navbar-burger").click(function() {
$(".navbar-burger").toggleClass("is-active");
$(".navbar-menu").toggleClass("is-active");
// Détails visuel du bouton recherche
$("#rechercheBouton").toggleClass("is-rounded is-fullwidth is-primary")
});
// Bouton suivant et précédent qui s'affiche en loading lorsque l'utilisateur change de page
$("a.button").click(function() {
$(this).addClass("is-loading");
});
// Redirige vers la page tapé dans la barre de recherche | recheche brut, possible d'amélioration avec
// auto-complétion, créer une page web "page n'existe pas", recherche par motsclés, page avec une liste des
// pages web possibles en fonction de ce que entre l'utilisateur
// ex: "R101" -> ./HTML/R101.html
$("#rechercheBouton").click(function() {
$("#rechercheBoite").addClass("is-active")
});
// Gestion de la fermeture de la boite de recherche
$(".modal-background").click(function() {
$("#rechercheBoite").removeClass("is-active")
});
$("#rechercheBoite-fermer").click(function() {
$("#rechercheBoite").removeClass("is-active")
});
$("#rechercher").keyup(function(e) {
var recherche = $(this).val().trim();
if(recherche.length != 0) {
recherche = "+" + recherche.replace(/\s+/g," +");
console.log(recherche)
var resultats = idx.search(recherche);
if(resultats.length != 0) {
$("#rechercheResultats").empty();
resultats.forEach(function(res) {
$("#rechercheResultats").append('<a href="' + documents[res.ref]["url"] + '"><p class="title">' + documents[res.ref]["titre"] + '</p></a>')
$("#rechercheResultats").append('<p class="subtitle">' + documents[res.ref]["code"] + '</p>')
});
} else {$("#rechercheResultats").html('<p class="has-text-centered">Pas de résultats</p>')}
} else {
$("#rechercheResultats").html('<p class="has-text-centered">Pas de résultats</p>')
}
});
});
// Documents avec toutes les informations nécessaire pour la recherche
var documents = {{documents}}
var idx = lunr(function() {
this.ref("code")
this.field("code", { boost: 10})
this.field("motscles")
this.field("diminutif", { boost: 10})
this.field("titre")
this.field("description")
this.field("contenu")
this.field("contexte")
for(var cle in documents) {
this.add(documents[cle])
}
})
// Permet l'affichage du LaTeX avec comme balise délimiteur "$"
// Le menu contextuel de MathJax a été désactivé
MathJax = {
tex: {
inlineMath: [['$', '$']]
},
options: {
enableMenu: false
}
};

386
html/export_yaml_to_html.py Normal file
View File

@ -0,0 +1,386 @@
import os
import sys
import argparse
import glob
sys.path.insert(0,"../python")
from config import Config
from jinja2 import Template, Environment, FileSystemLoader
# Description des arguments possibles du programme
parser = argparse.ArgumentParser(description="Conversion des YAML en HTML")
parser.add_argument(
"-r",
"--root",
default="..",
help="repertoire de base (racine) pour chercher les fichiers de données"
)
args = parser.parse_args()
Config.ROOT = args.root
import ressource
from ressource import *
# Chemins des différents dossiers
REPERTOIRE_TEMP = Config.ROOT + "/python/export"
REPERTOIRE_RESSOURCES_DEFINITIVES = Config.ROOT + "/yaml/ressources"
REPERTOIRE_SAE_DEFINITIVES = Config.ROOT + "/yaml/saes"
REPERTOIRE_COMPETENCES_DEFINITIVES = Config.ROOT + "/yaml/competences"
REPERTOIRE_ACS = Config.ROOT + "/python/pn"
REPERTOIRE_HTML = Config.ROOT + "/html/export"
REPERTOIRE_JS = REPERTOIRE_HTML + "/js"
CHEMIN_TEMPLATE = Config.ROOT + "/html"
# Créer le dossier html/export et html/export/js s'il n'existe pas
if not os.path.exists(REPERTOIRE_HTML):
os.makedirs(REPERTOIRE_HTML)
if not os.path.exists(REPERTOIRE_JS):
os.makedirs(REPERTOIRE_JS)
# Chargement des ressources : depuis les versions définitives du répertoire yaml d'abord,
# puis dans python/export si manquantes
fichiers_definitifs = [ os.path.split(x)[1] for x in glob.glob(REPERTOIRE_RESSOURCES_DEFINITIVES+'/*.yml') ] #nom fichier dans yaml/ressources
fichiers_temp = [ os.path.split(x)[1] for x in glob.glob(REPERTOIRE_TEMP+'/*.yml') ] #nom fichier dans python/export
fichiers_ressources = [REPERTOIRE_RESSOURCES_DEFINITIVES + "/" + f for f in fichiers_definitifs] # chemins de fichier ressources YAML
for f in fichiers_temp:
if f not in fichiers_definitifs and f.startswith("R"):
fichiers_ressources.append(REPERTOIRE_TEMP + "/" + f)
fichiers_ressources = sorted(fichiers_ressources) # tri par ordre alphabétique
ressources = {"S1": [], "S2": []}
for fichieryaml in fichiers_ressources:
r = Ressource(fichieryaml) # lecture du fichier
sem = "S" + str(r.ressource["semestre"])
ressources[sem].append(r)
# tri par code croissant
for sem in ressources:
ressources[sem] = sorted(ressources[sem], key=lambda r: r.ressource["code"])
# Chargement des saé et des exemples
fichiers_definitifs = [ os.path.split(x)[1] for x in glob.glob(REPERTOIRE_SAE_DEFINITIVES+'/*.yml') ]
fichiers_temp = [ os.path.split(x)[1] for x in glob.glob(REPERTOIRE_TEMP+'/*.yml') ]
fichiers_saes = [REPERTOIRE_SAE_DEFINITIVES + "/" + f for f in fichiers_definitifs if "exemple" not in f]
fichiers_exemples = [REPERTOIRE_SAE_DEFINITIVES + "/" + f for f in fichiers_definitifs if "exemple" in f]
for f in fichiers_temp:
if f not in fichiers_definitifs and f.startswith("S"):
if "exemple" not in f:
fichiers_saes.append(REPERTOIRE_TEMP + "/" + f)
elif "exemple" in f:
fichiers_exemples.append(REPERTOIRE_TEMP + "/" + f)
fichiers_saes = sorted(fichiers_saes) # tri par ordre alphabétique
fichiers_exemples = sorted(fichiers_exemples)
saes = {"S1": [], "S2": []}
for fichieryaml in fichiers_saes:
s = SAE(fichieryaml)
sem = "S" + str(s.sae["semestre"])
saes[sem].append(s)
for sem in saes:
saes[sem] = sorted(saes[sem], key=lambda s: s.sae["code"])
exemples = {"S1" : {}, "S2" : {} }
for fichieryaml in fichiers_exemples:
e = ExempleSAE(fichieryaml)
sem = "S" + str(e.exemple["semestre"])
sae = e.exemple["code"]
if sae not in exemples[sem]:
exemples[sem][sae] = []
exemples[sem][sae].append(e)
#Liste de string pour renommer certaines catégories (les autres qui n'ont pas besoins ont la première lettre en majuscule)
rename = {
"heures_encadrees": "Heures encadrées",
"heures_formation": "Heures formation",
"heures_tp": "Heures TP",
"tp": "Heures TP",
"coeffs": "Coef.",
"acs": "ACs",
"motscles": "Mots clés",
"sae": "SAÉ",
"prerequis": "Prérequis",
"problematique": "Problématique",
"modalite": "Modalité"
}
# Création de l'environnement pour charger les templates
env = Environment(trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(CHEMIN_TEMPLATE))
# Template de la page index et génération de la page
template_index = env.get_template("indexTemplate.html")
template_index.stream().dump(REPERTOIRE_HTML + "/index.html")
# Template de chaque pages ressources, saes, exemples (doit contenir datas,rename,precedent,suivant)
template = env.get_template("InfoTemplate.html")
# Template de chaque pages de compétences (doit contenir data,rt,precedent,suivant)
template_Competence = env.get_template("CompetenceTemplate.html")
# Template de chaque pages de ACs (doit contenir data, precedent, suivant)
template_AC = env.get_template("ACTemplate.html")
# Template de la liste des ACs
template_List_ACs = env.get_template("ListACsTemplate.html")
# Template de la liste des ressources par semestre (doit contenir data,sem)
template_List_Ressource = env.get_template("ListRessourceTemplate.html")
# Template de la liste des acs ou saes ou ressources (doit contenir data,titre)
template_List = env.get_template("ListTemplate.html")
def motscles(mc):
""" Retourne un tableau de mots clés en prenant en compte les parenthèses """
motscles = []
mot = ""
i = 0
while i < len(mc):
if mc[i] == "(":
while mc[i] != ")":
mot += mc[i]
i += 1
elif mc[i] == "," and mc[i+1] == " ":
motscles.append(mot)
mot = ""
i += 2
mot += mc[i]
i += 1
motscles.append(mot)
return motscles
def formatHTML(string):
""" Retourne un string avec les balises <ul> , <li> et <p> correctement placé, code plus compliqué pour ce qu'il fait"""
texte = "\n" # \n permet d'améliorer la lisibilité dans les fichiers html
phrases = list(filter(None,string.split("\n")))
i = 0
while i < len(phrases):
if "* " in phrases[i]: # première balise li détecté
texte += "<ul>\n"
while i < len(phrases) and "*" in phrases[i]: # Tant qu'il y a des * on continue de créer des balises li
texte += " <li>" + phrases[i][2:] + "</li>\n"
if i+1 < len(phrases):
if phrases[i+1][:3] == " *": # Si il y a une liste dans un li
texte += " <ul>\n"
while i + 1 < len(phrases) and phrases[i+1][:2] == " ": # Tant qu'on est dans la liste
if "*" in phrases[i+1]:
texte += " <li>" + phrases[i+1][4:] + "</li>\n"
else:
texte = texte[:-6]
while i + 1 < len(phrases) and phrases[i+1][:2] == " ": # Si il y a des retour chariot
texte += phrases[i+1][3:]
i += 1
i -= 1
i += 1
texte += " </ul>\n"
elif phrases[i+1][:2] == " ": # Retour à la ligne d'un li
texte = texte[:-6]
while i + 1 < len(phrases) and phrases[i+1][:2] == " ":
texte += phrases[i+1][1:]
i += 1
texte += "</li>\n"
i += 1
texte += "</ul>\n"
i -= 1
else:
texte += "<p>" + phrases[i] + "</p>\n"
i += 1
return texte[:-1] # On enlève le dernier \n
def defineSearchTerm(dictio, url, documents):
""" Retourne un dictionnaire d'une ressource compatible Lunr pour la recherche de cet élément """
document = {}
document["code"] = dictio["code"]
document["url"] = url
if "titre" in dictio: document["titre"] = dictio["titre"]
else: document["titre"] = dictio["nom"]
if "motscles" in dictio: document["motscles"] = dictio["motscles"]
if "diminutif" in dictio: document["diminutif"] = dictio["diminutif"]
if "description" in dictio: document["description"] = dictio["description"]
if "contexte" in dictio: document["contexte"] = dictio["contexte"]
if "contenu" in dictio: document["contenu"] = dictio["contenu"]
documents[document["code"]] = document
# Créer un fichier contenant la liste des saes
datas = {"data" : saes, "title": "SAEs"} # "data" contient un tableau des saes
template_List.stream(datas).dump(REPERTOIRE_HTML + "/SAE.html")
# Créer un fichier contenant la liste des ressources
datas = {"data" : ressources, "title": "Ressources"}
template_List.stream(datas).dump(REPERTOIRE_HTML + "/ressources.html")
documents = {} # Définition d'un liste de document contenant les informations nécessaires pour la recherche
SAE_mobilise_AC = {} # Dictionnaire de ACs contenant la liste des SAE qui les mobilisent
relations = {"nodes": [], "links": []} # Dictionnaires des relations entre les ressources pour le graphe
# Création des pages individuelles ressources, saes, exemples
for indexSem, sem in enumerate(ressources):
# ____________________ Ressources ____________________
for indexRessource, ressource in enumerate(ressources[sem]):
data = {}
for categorie, valeur in ressource.getInfo().items():
data[categorie] = valeur
# Mise en page des textes en HTML
data["contenu"] = formatHTML(data["contenu"])
data["contexte"] = formatHTML(data["contexte"])
# Sépare les motclés pour former des tags
data["motscles"] = motscles(data["motscles"])
datas = {"data": data, "rename": rename} # Rename contient le dico pour renommer les catégories ressources[list(ressources.keys())[indexSem - 1]]
# Ajoute les liens pour les boutons "Suivant" et "Précédent"
# On doit prendre en compte le premier ressource et la dernière ressource du dernier semestre
if indexRessource > 0: datas["precedent"] = "R" + str(int(data["code"][1:])-1) + ".html"
elif indexSem > 0: datas["precedent"] = "R" + ressources["S"+str(indexSem)][-1].getInfo()["code"][1:] + ".html"
if indexRessource < len(ressources[sem]) - 1: datas["suivant"] = "R" + str(int(data["code"][1:])+1) + ".html"
elif indexSem < len(ressources) - 1: datas["suivant"] = "R" + str((indexSem+2)*100+1) + ".html"
url = data["code"] + ".html" # Ajout de l'url pour la recherche
defineSearchTerm(data, url, documents) # Ajout des informations de ressource pour la recherche dans une liste
# Créer un fichier html depuis un TemplateStream créer à partir du template et des données dans "datas" qui remplace les variables pour Jinja2
template.stream(datas).dump(REPERTOIRE_HTML + "/" + url)
# Ajout des informations nécessaires pour créer le graphique (node et link)
relations["nodes"].append({"id": data["code"], "sem": sem, "type": "Ressource"})
for sae in data["sae"]:
relations["links"].append({"source": data["code"], "target": sae, "sem": sem, "type": "RessourceToSAE"})
for rt in data["acs"]:
for ac in data["acs"][rt]:
if not any(ac in node["id"] for node in relations["nodes"]): relations["nodes"].append({"id": ac, "sem": 0, "type": "AC"})
relations["links"].append({"source": data["code"], "target": ac, "sem": sem, "type": "RessourceToAC"})
#Créer un fichier contenant la liste des ressources du semestre
data = {"data" : ressources[sem],"sem" : sem} # "data" contient un tableau des ressources du semestre
template_List_Ressource.stream(data).dump(REPERTOIRE_HTML + "/ressources" + str(sem) + ".html")
# ____________________ SAEs ____________________
for indexSAE, sae in enumerate(saes[sem]):
data = {}
for categorie, valeur in sae.sae.items():
data[categorie] = valeur
# On regarde si des exemples du sae existent, si True, on les ajoute dans "data"
if(sae.sae["code"] in exemples[sem]) :
data["exemples"] = exemples[sem][sae.sae["code"]]
data["description"] = formatHTML(data["description"])
data["livrables"] = formatHTML(data["livrables"])
data["motscles"] = motscles(data["motscles"])
datas = {"data":data, "rename": rename}
if indexSAE > 0: datas["precedent"] = "SAE" + str(int(data["code"][3:])-1) + ".html"
elif indexSem > 0: datas["precedent"] = "SAE" + saes["S"+str(indexSem)][-1].getInfo()["code"][3:] + ".html" # saes[list(saes.keys())[indexSem - 1]][-1].sae["code"][3:] -> "code" du dernier sae du semestre précédent
if indexSAE < len(saes[sem]) - 1: datas["suivant"] = "SAE" + str(int(sae.getInfo()["code"][3:])+1) + ".html"
elif indexSem < len(saes) - 1: datas["suivant"] = "SAE" + str((indexSem+2)*10+1) + ".html"
url = data["code"].replace("É","E") + ".html"
defineSearchTerm(data, url, documents)
template.stream(datas).dump(REPERTOIRE_HTML + "/" + url)
# Créer la liste des SAEs mobilisés par des AC
for rt, acs in sae.getInfo()["acs"].items():
for ac in acs:
if not ac in SAE_mobilise_AC: SAE_mobilise_AC[ac] = []
SAE_mobilise_AC[ac].append(sae.getInfo())
# Ajout des informations nécessaires pour créer le graphique (node et link)
if not any(data["code"] in node["id"] for node in relations["nodes"]):
relations["nodes"].append({"id": data["code"], "type": "SAE"})
for rt in data["acs"]:
for ac in data["acs"][rt]:
if not any(ac in node["id"] for node in relations["nodes"]): relations["nodes"].append({"id": ac, "sem": 0, "type": "AC"})
relations["links"].append({"source": data["code"], "target": ac, "sem": sem, "type": "SAEToAC"})
# ____________________ Exemples SAE ____________________
for sae in exemples[sem]:
num = 1 # Nommage des fichiers exemple sae
for indexExemple, exemple in enumerate(exemples[sem][sae]):
data = {}
for categorie, valeur in exemple.exemple.items():
data[categorie] = valeur
data["description"] = formatHTML(data["description"])
data["modalite"] = formatHTML(data["modalite"])
datas = {"data":data, "rename": rename}
if indexExemple > 0: datas["precedent"] = "SAE" + data["code"][-2:] + "_exemple" + str(num-1) + ".html"
if indexExemple < len(exemples[sem][sae]) - 1: datas["suivant"] = "SAE" + data["code"][-2:] + "_exemple" + str(num+1) + ".html"
num += 1
url = data["code"].replace("É","E") + "_exemple" + str(num) + ".html"
template.stream(datas).dump(REPERTOIRE_HTML + "/" + url)
# Création d'une liste de AC pour créer une page listant les ACs
ListACs = {"RT1":[], "RT2":[], "RT3":[]}
# Chargement des ACs
fichieryaml = REPERTOIRE_ACS +'/acs.yml'
acs = ACs(fichieryaml)
# Chargement des Compétences
fichieryaml = REPERTOIRE_COMPETENCES_DEFINITIVES + '/RT123.yml'
competences = Competences(fichieryaml)
# Création des pages individuelles ACs, Compétences
for indexRt, rt in enumerate(acs.getInfo()):
# ____________________ ACs ____________________
for i, (ac, desc) in enumerate(acs.getInfo()[rt].items()):
data = {}
data["code"] = ac
data["titre"] = desc
data["sae"] = SAE_mobilise_AC[ac]
datas = {"data":data}
ListACs[rt].append(data)
if i > 0: datas["precedent"] = list(acs.getInfo()[rt].keys())[i-1] + ".html"
elif indexRt > 0: datas["precedent"] = list(acs.getInfo()["RT" + str(int(rt[-1])-1)].keys())[-1] + ".html"
if i < len(acs.getInfo()[rt]) - 1: datas["suivant"] = list(acs.getInfo()[rt].keys())[i+1] + ".html"
elif indexRt < len(acs.getInfo()) - 1: datas["suivant"] = list(acs.getInfo()["RT" + str(int(rt[-1])+1)].keys())[0] + ".html"
url = ac + ".html"
defineSearchTerm(data, url, documents)
template_AC.stream(datas).dump(REPERTOIRE_HTML + "/" + url)
# ____________________ Compétences ____________________
data = {}
for categorie, valeur in competences.getInfo()[rt].items():
data[categorie] = valeur
data["description"] = formatHTML(data["description"])
datas = {"data": data, "rt": rt}
if indexRt > 0: datas["precedent"] = "RT" + str(indexRt) + ".html"
if indexRt < len(competences.getInfo()) - 1: datas["suivant"] = "RT" + str(indexRt + 2) + ".html"
url = rt + ".html"
template_Competence.stream(datas).dump(REPERTOIRE_HTML + "/" + url)
data["code"] = rt # On le créer ici pour pas ajouter une ligne au tableau de la page mais pour la recherche
defineSearchTerm(data, url, documents)
# Créer un fichier contenant la liste des ACs
datas = {"data": ListACs, "title": "ACs"}
template_List_ACs.stream(datas).dump(REPERTOIRE_HTML + "/ACs.html")
# Envoie des informations des documents pour la recherche
template_recherche = env.get_template("baseTemplate.js")
template_recherche.stream(documents=documents).dump(REPERTOIRE_JS + "/base.js")
# Créer un fichier contenant le graphe des relations entres les toutes les ressources
datas = {"data": relations}
template_graph = env.get_template("graphTemplate.html")
template_graphJS = env.get_template("graphTemplate.js")
template_graph.stream().dump(REPERTOIRE_HTML + "/graph.html")
template_graphJS.stream(datas).dump(REPERTOIRE_JS + "/graph.js")

37
html/graphTemplate.html Normal file
View File

@ -0,0 +1,37 @@
{% extends "base.html" %}
{% block title %}Relation des ressources{% endblock %}
{% block head %}
<script src="https://d3js.org/d3.v5.js"></script>
{% endblock %}
{% block content %}
<div class="field is-horizontal">
<div class="control">
<label class="checkbox">
<input id="Semestre1" class="semestre" value="S1" type="checkbox" checked>
Semestre 1
</label>
<label class="checkbox">
<input id="Semestre2" class="semestre" value="S2" type="checkbox" checked>
Semestre 2
</label>
</div>
</div>
<div class="field is-horizontal">
<div class="control">
<label class="checkbox">
<input id="Ressources" class="categorie" type="checkbox" checked>
Ressources
</label>
<label class="checkbox">
<input id="SAEs" class="categorie" type="checkbox" checked>
SAEs
</label>
<label class="checkbox">
<input id="ACs" class="categorie" type="checkbox" checked>
ACs
</label>
</div>
</div>
<svg style="border: 1px solid black; margin: auto;"></svg>
<script src="js/graph.js"></script>
{% endblock %}

140
html/graphTemplate.js Normal file
View File

@ -0,0 +1,140 @@
drag = simulation => {
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
const graph = {{data}}
var nodes = graph["nodes"]
var links = graph["links"]
const nodetypes = Array.from(new Set(nodes.map(node => node.type)))
const linktypes = Array.from(new Set(links.map(link => link.type)))
const color = d3.scaleOrdinal(nodetypes.concat(linktypes),d3.schemeCategory10)
var height = 800, width = 800;
var svg = d3.select("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height])
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-400))
.force("link", d3.forceLink(links).id(node => node.id).distance(50))
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", ticked);
var link = svg.append("g")
.attr("stroke-width", 1.5)
.attr("class","links")
.selectAll("line")
var node = svg.append("g")
.attr("stroke-width", 1)
.attr("stroke", "black")
.attr("class", "nodes")
.selectAll("g")
redraw();
$("document").ready(function() {
$("input").click(function() {
var sem = ["default"];
$(".semestre:checked").each(function() { sem.push($(this).val()) });
var RessourceChecked = $("#Ressources").prop("checked");
var SAEChecked = $("#SAEs").prop("checked");
var ACChecked = $("#ACs").prop("checked");
nodes = [];
links = [];
if(RessourceChecked) {
graph["nodes"].forEach(node => {
if(node.type == "Ressource" && sem.includes(node.sem)) { nodes.push(node); }
});
}
if(SAEChecked) {
graph["nodes"].forEach(node => {
if(node.type == "SAE") { nodes.push(node); }
});
if (RessourceChecked) {
graph["links"].forEach(link => { if(link.type == "RessourceToSAE" && sem.includes(link.sem)) {links.push(link);} })
}
}
if(ACChecked) {
graph["nodes"].forEach(node => {if(node.type == "AC"){nodes.push(node);}});
if(RessourceChecked) {graph["links"].forEach(link => {if(link.type == "RessourceToAC" && sem.includes(link.sem)){links.push(link);}})}
if(SAEChecked) {graph["links"].forEach(link => {if(link.type == "SAEToAC" && sem.includes(link.sem)){links.push(link);}})}
}
redraw();
});
});
function redraw() {
link = link.data(links)
.join("line")
.attr("stroke", d => color(d.type));
node.selectAll("text").remove();
node.selectAll("rect").remove();
node = node.data(nodes)
.join("g")
.attr("class","node")
.call(drag(simulation))
node.append("rect")
.attr("width", 20)
.attr("height", 10)
.attr("x", -10)
.attr("y", -5)
.attr("rx", 5)
.attr("ry", 5)
.attr("fill", function(d) { return color(d.type); })
node.append("text")
.attr("style", "user-select: none")
.attr("dx", 7)
.attr("dy", 12)
.append("a")
.attr("href", d => d.id.replace("É", "E") + ".html")
.text(d => d.id)
simulation.nodes(nodes);
simulation.force("links", d3.forceLink(links).id(node => node.id).distance(100));
simulation.alpha(0.5).restart();
}
function ticked() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("transform", d => `translate(${d.x},${d.y})`);
}

88
html/indexTemplate.html Normal file
View File

@ -0,0 +1,88 @@
{% extends "base.html" %}
{% block title %}Accueil{% endblock %}
{% block content %}
<div class="content">
<h1 class="has-text-centered title is-1">Titre aléatoire</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed nulla massa. Fusce non felis quis est volutpat volutpat vel non purus. Pellentesque dignissim vel magna eget ornare. Nulla accumsan condimentum eros non interdum. Sed at sagittis mauris, nec mollis turpis. Sed facilisis eros quis velit suscipit molestie. Aenean lobortis nulla id tristique placerat. Fusce non convallis lectus, eget interdum sapien. Fusce feugiat laoreet dui, ac laoreet elit molestie quis. Aliquam erat volutpat. Vivamus libero eros, feugiat eu dolor eget, hendrerit finibus dui. Etiam eget sapien consequat, condimentum nibh vitae, posuere velit. In at massa enim. Praesent malesuada ligula augue, non eleifend turpis molestie vel. Nam efficitur congue rhoncus.</p>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child box">
<a href="ressourcesS1.html"><h1 class="has-text-centered title">Semestre 1</h1></a>
<hr>
<div class="content">
<ul>
<li>UE 11: Bases de l'informatique</li>
<li>UE 12: Bases de culture scientifique, sociale et humaine</li>
</ul>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<a href="ressourcesS2.html"><h1 class="has-text-centered title">Semestre 2</h1></a>
<hr>
<div class="content">
<ul>
<li>UE 21: Informatique</li>
<li>UE 22: Culture scientifique, sociale et humaine</li>
</ul>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child box">
<a href=""><h1 class="has-text-centered title">Semestre 3</h1></a>
<hr>
<div class="content">
<ul>
<li>UE 31: Informatique avancée</li>
<li>UE 32: Culture scientifique, sociale et humaine avancées</li>
<li>UE 33: Méthodologie et Projets</li>
</ul>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<a href=""><h1 class="has-text-centered title">Semestre 4</h1></a>
<hr>
<div class="content">
<ul>
<li>UE 41: Compléments d'informatique</li>
<li>UE 42: Compléments de culture scientifique, sociale et humaine</li>
<li>UE 43: Stage</li>
</ul>
</div>
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child box">
<a href=""><h1 class="has-text-centered title">Semestre 5</h1></a>
<hr>
<div class="content">
<ul>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<a href=""><h1 class="has-text-centered title">Semestre 6</h1></a>
<hr>
<div class="content">
<ul>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}

22
html/navigation.html Normal file
View File

@ -0,0 +1,22 @@
<nav class="level is-mobile">
<div class="level-left">
<div class="level-item">
<a class="button is-primary{% if not precedent %} is-static"{% else %} is-outlined" href="{{precedent}}"{% endif %}>
<span class="icon is-small">
<i class="fas fa-arrow-left"></i>
</span>
<span>Précédent</span>
</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-primary{% if not suivant %} is-static"{% else %} is-outlined" href="{{suivant}}"{% endif %}>
<span>Suivant</span>
<span class="icon is-small">
<i class="fas fa-arrow-right"></i>
</span>
</a>
</div>
</div>
</nav>

View File

@ -169,6 +169,9 @@ class Ressource:
# Insère les abbréviations
return chaine
def getInfo(self):
return self.ressource
def contient_abbr(chaine):
"""Détecte les abréviations présentes dans la chaine
@ -317,6 +320,9 @@ class SAE:
chaine = nettoie_latex(chaine)
return chaine
def getInfo(self):
return self.sae
class ExempleSAE:
"""Modélise un exemple de SAE lorsqu'elle est extraite d'un yaml"""
@ -388,6 +394,37 @@ class ExempleSAE:
return chaine
class Competences:
""" Modélise une liste de compétences lorsqu'elle est extraite d'un dictionnaire """
__LOGGER = logging.getLogger(__name__)
def __init__(self, fichieryaml):
with open(fichieryaml, "r", encoding="utf8") as fid:
yaml = ruamel.yaml.YAML()
try:
self.competences = yaml.load(fid.read())
except:
Competences.__LOGGER.warning(f"Pb de chargement de {fichieryaml}")
def getInfo(self):
return self.competences
class ACs:
""" Modélise une liste de acs lorsqu'elle est extraite d'un fichier yaml """
__LOGGER = logging.getLogger(__name__)
def __init__(self, fichieryaml):
with open(fichieryaml, "r", encoding="utf8") as fid:
yaml = ruamel.yaml.YAML(typ="safe")
try:
self.acs = yaml.load(fid.read())
except:
ACs.__LOGGER.warning(f"Pb de chargement de {fichieryaml}")
def getInfo(self):
return self.acs
def md_to_latex(contenu):
"""Réalise la conversion markdown to latex avec pypandoc"""