mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 07:41:14 +00:00
move old pdf to the repo github wiki
This commit is contained in:
parent
c1acadbf3d
commit
223aa37161
Binary file not shown.
1
docs/archives/TO_Skia_LoJ/.gitignore
vendored
1
docs/archives/TO_Skia_LoJ/.gitignore
vendored
@ -1 +0,0 @@
|
||||
_minted-Rapport/
|
Binary file not shown.
Binary file not shown.
@ -1,13 +0,0 @@
|
||||
CC=pdflatex
|
||||
|
||||
all: rapport clean
|
||||
|
||||
rapport: Rapport.tex
|
||||
@echo "Compiling "$<
|
||||
$(CC) -shell-escape $<
|
||||
$(CC) -shell-escape $<
|
||||
|
||||
clean:
|
||||
@echo "Cleaning folder"
|
||||
rm *.aux; rm *.log; rm *.out; rm *.toc; rm *.snm; rm *.nav; rm *.lof
|
||||
|
Binary file not shown.
@ -1,490 +0,0 @@
|
||||
%%
|
||||
%
|
||||
% Skia
|
||||
% skia@libskia.so
|
||||
%
|
||||
%%
|
||||
|
||||
\documentclass[a4paper]{report}
|
||||
|
||||
%packages
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[francais]{babel}
|
||||
\usepackage{graphicx}\graphicspath{{pix/}}
|
||||
\usepackage{float}
|
||||
\usepackage{scrextend}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{color}
|
||||
\usepackage{fancyhdr}
|
||||
%Options: Sonny, Lenny, Glenn, Conny, Rejne, Bjarne, Bjornstrup
|
||||
\usepackage[Bjornstrup]{fncychap}
|
||||
\usepackage{minted}
|
||||
\usepackage[colorlinks=true,linkcolor=black]{hyperref}
|
||||
\usepackage{pdfpages}
|
||||
%\usepackage{titlesec, blindtext, color}
|
||||
|
||||
%pdf metadata
|
||||
\hypersetup{
|
||||
unicode=true,
|
||||
colorlinks=true,
|
||||
citecolor=black,
|
||||
filecolor=black,
|
||||
linkcolor=black,
|
||||
urlcolor=black,
|
||||
pdfauthor={Skia <skia@libskia.so>},
|
||||
pdftitle={},
|
||||
pdfcreator={pdftex},
|
||||
pdfsubject={},
|
||||
pdfkeywords={},
|
||||
}
|
||||
|
||||
|
||||
\definecolor{keywords}{RGB}{200,0,90}
|
||||
\definecolor{comments}{RGB}{50,50,253}
|
||||
\definecolor{red}{RGB}{160,0,0}
|
||||
\definecolor{brown}{RGB}{160,100,100}
|
||||
\definecolor{green}{RGB}{0,200,0}
|
||||
\definecolor{darkgreen}{RGB}{0,130,0}
|
||||
\definecolor{gray}{RGB}{100,100,100}
|
||||
|
||||
|
||||
%inner meta
|
||||
\title{Sith: Développement de nouvelles applications}
|
||||
\author{Florent \textsc{Jacquet}\\
|
||||
Guillaume \textsc{Renaud}}
|
||||
\date{Dernière version: \today}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% \maketitle
|
||||
\includepdf[pages={1}]{Couvertures.pdf}
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\chapter*{Remerciements}
|
||||
\section*{Guillaume \textsc{Renaud}}
|
||||
\par Je remercie tout d'abord Monsieur Frédéric \textsc{Lassabe} qui nous a permis d'effectuer cette TO52 lors de notre cursus à
|
||||
l'UTBM, nous permettant ainsi de mêler nôtre travail scolaire à nôtre envie de participer à l'amélioration de la vie
|
||||
associative de l'UTBM.
|
||||
|
||||
\par Je tiens aussi à remercier Florent \textsc{Jacquet} qui m'a aidé tout au long de ce travail et à qui j'ai pu poser mes
|
||||
différentes questions pour apprendre et comprendre plus rapidement que si j'avais été seul.
|
||||
|
||||
\section*{Florent \textsc{Jacquet}}
|
||||
\par Je remercie également Frédéric \textsc{Lassabe} , non seulement pour la TO, mais également pour la précédente TW. Sans ces
|
||||
deux UV hors emploi du temps, jamais un projet comme ce site de l'AE n'aurait pu voir le jour. Cela a demandé beaucoup
|
||||
d'investissement, et il est plus qu'appréciable de pouvoir obtenir quelques crédits en retour.
|
||||
|
||||
\par Je tiens également à remercier l'ensemble de l'équipe info de l'AE qui s'est motivée ce semestre à organiser des
|
||||
réunions hebdomadaires afin de reprendre le projet du mieux possible. C'est maintenant à eux que va être confié le
|
||||
projet, et il est agréable de constater qu'ils n'ont pas attendu le dernier moment pour se pencher sur la question.
|
||||
|
||||
|
||||
\chapter*{Introduction}
|
||||
\addcontentsline{toc}{chapter}{Introduction}
|
||||
\par Après le développement de la base du nouveau site de l'AE, le projet \emph{Sith}, au Printemps 2016, la mise en
|
||||
production a pu avoir lieu avec succès fin Août 2016.
|
||||
|
||||
\par Mais le site était encore très incomplet, et il était nécessaire d'y ajouter un grand nombre de fonctionnalités
|
||||
moins critiques, celles-ci n'ayant pas de rapport avec l'argent, mais tout de même très utiles pour le fonctionnement
|
||||
de l'AE.
|
||||
|
||||
\par Parmis elles, se trouvait notamment une application de gestion des stocks, qui a été confiée à Guillaume, puisqu'elle
|
||||
concernait en premier lieu le \emph{Bureau des Festivités} et qu'il en était le président. Il était donc parmis les
|
||||
mieux placé pour évaluer le besoin et développer l'outil, d'autant qu'il fallait le concevoir depuis le début, ces
|
||||
fonctions n'étant pas du tout présentes dans l'ancien site.
|
||||
|
||||
\par Du reste, Florent a eu la responsabilité de développer les autres applications, ou bien de gérer leur développement
|
||||
lors qu'il était fait par quelqu'un d'autre.
|
||||
|
||||
\chapter{Eboutic}
|
||||
\label{sec:eboutic}
|
||||
\par Développeur principal: Florent
|
||||
|
||||
\section{But}
|
||||
\label{sub:but}
|
||||
\par Fournir une boutique en ligne, avec paiement sécurisé, compatible avec l'API de paiement du Crédit Agricole.
|
||||
\begin{itemize}
|
||||
\item Gérer les cotisations
|
||||
\item Gérer les rechargements de compte AE
|
||||
\item Gérer différents groupes de vente
|
||||
\end{itemize}
|
||||
|
||||
\section{Principaux problèmes}
|
||||
\label{sec:principaux_problemes}
|
||||
|
||||
\subsection{Interaction avec l'API}
|
||||
\label{sub:interaction_avec_l_api}
|
||||
\par C'est la principale contrainte de cette application. On doit interagir avec les serveurs du Crédit Agricole, et
|
||||
pour cela, ces derniers n'aident pas beaucoup.
|
||||
|
||||
\par Ils fournissent un PDF peu clair\footnote{disponible dans le dossier \url{doc/Etransaction/} des sources du site}
|
||||
expliquant l'implémentation d'un site marchand, en plus des nombreux autres PDF de documentation disponibles à l'adresse
|
||||
\url{https://e-transactions.avem-groupe.com/pages/global.php?page=telechargement}.
|
||||
|
||||
\par Une implémentation de référence uniquement en PHP, et contenant que peut de fonctionnalités par rapport à ce
|
||||
que dit le PDF peut aussi être obtenue, mais n'est guère utile excepté pour la vérification cryptographique de la
|
||||
signature de la réponse. Mais encore, il faut arriver à traduire les fonctions propres à PHP, et ce n'est pas toujours
|
||||
une mince affaire, mais fort heureusement, les algorithmes sont encore assez standards et l'on trouve vite de l'aide
|
||||
quant à ces fonctions.
|
||||
|
||||
\par De plus, certaines informations concernants les numéros d'identification de marchand son incohérents
|
||||
d'une documentation à l'autre, et le plus simple à ce niveau est encore de contacter le support.
|
||||
|
||||
\subsection{Accès concurrentiels}
|
||||
\label{sub:acces_concurrentiels}
|
||||
\par En production, le projet Sith tourne à l'aide d'\textbf{uWSGI}, qui s'occupe lui de gérer les différents processus du
|
||||
logiciel. Cela se traduit par des accès concurrentiels à la base de donnée lors de l'appel de deux pages simultanément
|
||||
qui ont besoin d'accèder aux mêmes ressources.
|
||||
|
||||
\par Le problème n'en est la plupart du temps pas un, mais il devient très critique lorsque la page appelée permet par
|
||||
exemple de recharger un compte AE. Il ne faut alors surtout faire l'opération en double.
|
||||
|
||||
\par Pour protéger ces accès en double, on peut alors utiliser des transactions, et \textbf{Django} fournit une
|
||||
abstraction très pratique: \verb-with transaction.atomic():-.
|
||||
|
||||
\par L'Eboutic, avec sa réponse de la banque, est très sujette à ces accès concurrents, et cela a posé quelques
|
||||
problèmes dans les débuts. La plupart ont été résolu, mais il arrive encore dans les comptoirs d'avoir une vente en
|
||||
double, sans pour autant avoir le débit du compte qui soit doublé. Cela ne pose pas foncièrement de problèmes, puisque
|
||||
le solde du compte est tout de même valide, et c'est un problème très compliqué à debugger, puisqu'il survient très
|
||||
rarement, mais il faudrait tout de même arriver à le résoudre un jour.
|
||||
|
||||
|
||||
\chapter{Le SAS}
|
||||
\label{sec:le_sas}
|
||||
\par Développeur principal: Florent
|
||||
|
||||
\section{But}
|
||||
\label{sub:but}
|
||||
\par Fournir un système de galerie de photo:
|
||||
\begin{itemize}
|
||||
\item Upload en ligne via un formulaire pour tous les cotisants.
|
||||
\item Modération pour l'équipe du SAS.
|
||||
\item Système d'identification des membres pour retrouver rapidement ses photos.
|
||||
\item Affichage des photos dans les différents album et sur la page "photo" du profil d'un utilisateur.
|
||||
\end{itemize}
|
||||
|
||||
\section{Principaux problèmes}
|
||||
\label{sec:principaux_problemes}
|
||||
|
||||
\subsection{Gestion des fichiers}
|
||||
\label{sub:gestion_des_fichiers}
|
||||
\par L'envoie en grande quantité de photos nécéssite une gestion des fichiers solide, en même temps qu'un formulaire
|
||||
d'envoie efficace, capable d'envoyer plusieurs dizaines de photos en une seule action de l'utilisateur.
|
||||
|
||||
\par L'envoie est donc fait à l'aide de requêtes AJAX pour envoyer les photos une par une et éviter alors le timeout.
|
||||
|
||||
\par Concernant les fichiers une fois envoyé, ils sont en réalité traités par la classe \verb#SithFile# qui gère tous
|
||||
les fichiers du site. Cela ne fait qu'une seule classe à développer, de même qu'un seul système de fichier avec une
|
||||
seule arborescence, ce qui est beaucoup plus robuste.
|
||||
|
||||
\par La difficulté a aussi été de permettre le déplacement des fichiers, par couper-coller, tout en faisant de même dans
|
||||
le système de fichier réel, afin d'avoir une arborescence cohérente même en cas de perte de la base de données.
|
||||
|
||||
\subsection{Optimisation des pages}
|
||||
\label{sub:optimisation_des_pages}
|
||||
\par La génération d'un grand nombre de requêtes SQL est un des principaux problèmes de ralentissement d'un site. Le
|
||||
SAS, avec ses très nombreuses photos, qui requierent une validation des droits, a posé un gros problème à ce niveau.
|
||||
|
||||
\par Certaines pages ont pu mettre jusqu'à plus de 10 secondes à générer, ce qui est inconcevable pour une galerie de
|
||||
photos, mais ce temps à pu être réduit à moins de 3 secondes.
|
||||
|
||||
\par L'astuce à été d'utiliser des actions utilisateurs, comme l'upload de nouvelles photos, pour faire plus de
|
||||
traitement que nécessaire, afin de mettre en "cache" une grande partie des actions, comme par exemple la génération des
|
||||
miniatures des albums.
|
||||
|
||||
\par Une autre technique pour gagner du temps est de mettre en cache certaines requêtes en forcant les \emph{QuerySet}
|
||||
à s'évaluer dans une \emph{list} \textbf{Python} que l'on stocke afin d'obtenir sa longueur, au lieu de lancer d'abord
|
||||
un \emph{count}, puis une itération des résultats, qui en utilisant directement l'ORM, conduit à réaliser deux
|
||||
requêtes SQL.
|
||||
|
||||
\par Enfin, le passage à \textbf{HTTP/2} permettrait d'améliorer encore les performances côté utilisateur puisqu'il n'y
|
||||
aurait plus qu'un seul \emph{socket} d'ouvert pour transférer toutes les photos d'une page par exemple, sans avoir
|
||||
pour autant à toucher au code.
|
||||
|
||||
|
||||
\chapter{Les élections}
|
||||
\label{sec:les_elections}
|
||||
\par Développeur principal: Antoine
|
||||
|
||||
\section{But}
|
||||
\label{sub:but}
|
||||
\par Fournir un système d'élections:
|
||||
\begin{itemize}
|
||||
\item Gestion des différentes élections comprenants à chaque fois une liste de postes pour lesquels les gens
|
||||
candidatent, ainsi qu'une gestion des listes, pour pouvoir classifier et répartir les candidatures.
|
||||
\item Gestion d'une page de vote, permettant aux gens autorisés de pouvoir voter.
|
||||
\item Affichage des résultats une fois le vote terminé.
|
||||
\item Pas compatible avec la législation française: trop contraignant et pas utile, puisque validation officiel en
|
||||
AG.
|
||||
\end{itemize}
|
||||
|
||||
\section{Principaux problèmes}
|
||||
\label{sec:principaux_problemes}
|
||||
|
||||
\subsection{Automatisation d'un widget particulier pour les formulaires}
|
||||
\label{sub:automatisation_d_un_widget_particulier_pour_les_formulaires}
|
||||
\par La demande est venue du \textbf{BdF} qui a voulu autoriser pour certains poste un nombre de vote supérieur à 1.
|
||||
Cela signifie que l'on passe d'un choix simple, type \verb#radio# à un choix multiple, type \verb#checkbox#, tout cela
|
||||
étant paramètrable dans l'élection.
|
||||
|
||||
\par Ce genre de choix n'étant pas disponible dans \textbf{Django} de base, il a fallut développer le \emph{widget} à
|
||||
utiliser dans le formulaire qui permette cette configuration tout en validant bien les données reçues par rapport au
|
||||
modèle, et éviter ainsi de pouvoir "tricher" en envoyant des requêtes erronées.
|
||||
|
||||
\subsection{Revue du code d'un autre développeur}
|
||||
\label{sub:revue_du_code_d_un_autre_developpeur}
|
||||
\par \emph{Antoine} étant le principal développeur de cette application, un gros travail de revue de code a dû être
|
||||
effectuer afin de garantir une certaine cohérence avec le reste du projet.
|
||||
|
||||
\par C'est un travail très long et fastidieux, car il faut bien revérifier chaque ligne, sur chaque fichier, tout en
|
||||
faisant des commentaire lorsque quelque chose ne va pas. \textbf{Gitlab} a, à ce niveau, grandement facilité la tâche, à
|
||||
l'aide de ses outils de \emph{merge request} assez avancés.
|
||||
|
||||
\par En plus du code en lui-même, il a fallut porter une attention particulière aux migrations. Ces fichiers générés
|
||||
automatiquement par \textbf{Django} sont responsables du maintient d'une base de donnée cohérente malgré les évolutions
|
||||
des modèles. Même si le code parait donc valide, il est impératif de surveiller que la chaîne de dépendance des dites
|
||||
migrations ne soit pas cassée, au risque de problèmes potentiels au moment de la mise en production, ce qui entraînent à
|
||||
coup sûr un \emph{downtime}.
|
||||
|
||||
\chapter{Les stocks}
|
||||
\label{sub:les_stocks}
|
||||
\par Développeur principal: Guillaume
|
||||
\vskip 2em
|
||||
|
||||
\par Cette application s'occupe de la gestion des stocks des comptoirs de type « BAR ». Elle permet de suivre les
|
||||
quantités restantes afin de pouvoir déterminer de manière automatisée quels sont les produits qu'il faut acheter et en
|
||||
quelle quantité.
|
||||
|
||||
\section{Liste des modèles}
|
||||
\label{sec:liste_des_modeles}
|
||||
|
||||
\subsection{Stock}
|
||||
\par Un Stock possède un nom et est lié à la classe Counter. Ainsi, chaque Comptoir peut avoir son propre Stock.
|
||||
|
||||
\subsection{StockItem}
|
||||
\par Un StockItem possède un nom, une quantité unitaire, une quantité effective, une quantité minimale et est lié à la
|
||||
classe Stock ainsi qu'à la classe ProductType. De cette manière, chaque élément appartient à un Stock et il est
|
||||
catégorisé de la même manière que les Products (qui sont les objets utilisés pour la vente dans les comptoirs).
|
||||
|
||||
\subsection{ShoppingList}
|
||||
\par Une ShoppingList possède un nom, une date, un booléen (fait ou à faire), un commentaire et est liée à un Stock.
|
||||
Chaque ShoppingList est donc liée à un Stock ce qui permet d'avoir des listes de courses spécifique à chaque comptoir.
|
||||
|
||||
\subsection{ShoppingListItem}
|
||||
\par Un ShoppingListItem possède un nom, une quantité demandée, une quantité achetée et est lié à la classe StockItem, à
|
||||
la classe ShoppingList et à la classe ProductType. Cela permet de pouvoir faire plusieurs listes de courses différentes
|
||||
en même temps et d'en garder un historique.
|
||||
|
||||
\section{Fonctionnement}
|
||||
\label{sec:fonctionnement}
|
||||
|
||||
\par Au départ, si le comptoir de type « BAR » n'a pas de stock, la seule chose qu'il est possible de faire est d'en
|
||||
créer un. Ensuite, il va falloir créer les objets StockItem en indiquant pour chacun les quantités qu'il y a dans le
|
||||
stock.
|
||||
|
||||
\par De plus, la personne (généralement le Responsable du lieu de vie) qui aura la responsabilité d'informatiser les
|
||||
stocks devra aussi définir la quantité unitaire, effective et minimale.
|
||||
\par Par exemple, les Cheeseburger vendus aux différents comptoirs sont achetés par boite de 6, la quantité unitaire
|
||||
sera donc 6, la quantité effective correspondra au nombre de boites restantes dans le stock (c'est à dire dans la
|
||||
réserve du lieu de vie, une boite sortie du stock est considérée comme consommée) et enfin, la quantité minimale servira
|
||||
de valeur seuil.
|
||||
\par Une fois l'état de la réserve retranscrit dans le site, il reste encore gérer les stocks de manière quotidienne.
|
||||
Pour ce faire, l'application se décompose en 3 parties :
|
||||
\begin{itemize}
|
||||
\item Création automatique des listes de courses
|
||||
\item Approvisionnement du stock
|
||||
\item Prise d'éléments dans le stock
|
||||
\end{itemize}
|
||||
|
||||
\par Lorsque l'on accède à la partie qui s'occupe de la gestion des listes de courses, il y a un bouton permettant de
|
||||
créer une liste de courses en fonction de l'état des stocks à cet instant, puis un premier tableau contenant les listes
|
||||
de courses qu'il faut faire et enfin un second tableau servant d'historique des listes de courses déjà effectuées.
|
||||
\par Pour chaque liste de course ainsi créée, qu'elle soit « faite » ou « à faire », il est possible de cliquer sur son
|
||||
nom pour voir le détail de ce qu'elle comprend.
|
||||
|
||||
\subsection{Création automatique des listes de courses}
|
||||
\par En cliquant sur le bouton permettant de créer une nouvelle liste de courses, il faut remplir un formulaire. Les
|
||||
informations à donner dans ce formulaire sont le nom de la liste de course (par exemple, une liste spéciale pour
|
||||
Leclerc), ensuite, apparaissent tous les StockItem ayant une quantité effective inférieure au seuil fixé par leur
|
||||
quantité minimale. Il faut donc donner pour chacun de ces éléments une quantité à acheter. Enfin, un dernier champ de
|
||||
commentaire peut être compléter, il sert à demander l'achat d'éléments qui n'apparaissent pas dans le Stock, par
|
||||
exemple, des couteaux, fourchettes ou encore tasses...
|
||||
\par Lors de la validation de ce formulaire, la liste de courses est créée et est ajoutée au tableau contenant les
|
||||
listes de courses à faire.
|
||||
|
||||
\subsection{Approvisionnement du stock}
|
||||
\par Au retour des courses, il faut ranger les produits achetés dans la réserve. À ce moment-là, il faut aussi mettre à
|
||||
jour le stock. Une opération « Mettre à jour le stock » est disponible pour chaque liste de courses du tableau « À
|
||||
faire ».
|
||||
\par En effectuant cette action, il va falloir indiquer les quantités effectivement achetées. En effet, les quantités
|
||||
demandées ne sont pas forcément celles achetées, c'est donc les quantités effectives qu'il faut ajouter au stock. Une
|
||||
fois ce formulaire validé, la liste de couses passera de l'état « à faire » à l'état « faite ».
|
||||
|
||||
\subsection{Prise d'éléments dans le stock}
|
||||
\par La réserve étant accessible aux barmen afin qu'ils puissent réapprovisionner les réfrigérateurs à tout moment,
|
||||
l'interface permettant de prendre des éléments dans le stock a été ajoutée dans les onglets de l'interface des ventes
|
||||
(là où le barman inscrit le code du compte du client qui souhaite commander quelque chose). Ainsi, en revenant de la
|
||||
réserve, le barman doit indiquer le nombre de chaque produit qu'il a rapporté.
|
||||
\par Dans un souci de simplicité pour le gérant du lieu de vie, ce formulaire de prise des éléments dans le stock est
|
||||
aussi accessible depuis son interface de gestion.
|
||||
|
||||
|
||||
\section{Améliorations à apporter}
|
||||
\label{sec:amelioration_a_apporter}
|
||||
|
||||
\begin{itemize}
|
||||
\item Il n'est pas encore possible de modifier les quantités demandées pour un ou plusieurs des produits d'une liste
|
||||
de course. Il faudrait rendre cela possible car actuellement, il faut supprimer la liste de courses et la
|
||||
refaire en changeant les quantités souhaitées.
|
||||
\item Il faudrait améliorer la manière dont on ajoute les éléments non définis en tant que StockItem dans la liste
|
||||
de course. Un objet ShoppingListItem avec une référence « Null » vers la classe StockItem pourrait être créé à
|
||||
la place de compléter le champ de commentaires.
|
||||
\item Dans les améliorations sur le long terme, il faudrait que la décrémentation des quantités de chaque élément
|
||||
dans le stock soit automatique. En repensant une partie de l'architecture de l'application, on pourrait faire en
|
||||
sorte que chaque vente faite au comptoir face diminuer les quantités restantes (cela remplacerait le formulaire
|
||||
de « Prise d'éléments dans le stock », mais cela ne serait pas applicable à tous les produits mis en vente. Par
|
||||
exemple, pour les cacahuètes que nous vendons au bol et non par paquet)
|
||||
\item Avec le système de notifications qui a été mis en place sur le site, on pourrait faire en sorte que le ou les
|
||||
responsables des lieux de vie reçoivent une notification lorsque la liste de courses contient plus de 5 éléments
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\chapter{La laverie}
|
||||
\label{sec:la_laverie}
|
||||
\par Développeur principal: Florent
|
||||
|
||||
\section{But}
|
||||
\label{sub:but}
|
||||
\par Cette application doit fournir un système de gestion de laverie. Cela comprend:
|
||||
\begin{itemize}
|
||||
\item Un système de planning et de réservation de créneaux
|
||||
\item Un système de vente de jetons de laverie, lié aux comptoirs et au compte AE, permettant aux permanenciers de
|
||||
cliquer les jetons en même temps qu'ils vérifient l'état de la cotisation.
|
||||
\item Un système d'inventaire, pour gérer les différentes machines dans les différents lieux, et gérer également le
|
||||
retour des jetons après utilisation.
|
||||
\end{itemize}
|
||||
|
||||
\section{Principaux problèmes}
|
||||
\label{sec:principaux_problemes}
|
||||
|
||||
\subsection{Génération de plannings}
|
||||
\label{sub:generation_de_plannings}
|
||||
\par Il y a là beaucoup de cas à prendre en compte. Lorsque que quelqu'un veut réserver directement un "Lavage +
|
||||
Séchage", un simple "Lavage", ou un simple "Séchage", il faut toujours vérifier la disponibilité des créneaux en
|
||||
fonction du nombre de machine de chaque type présent dans la laverie en question \footnote{Belfort ou Sevenans, en
|
||||
l'occurrence}, et cela représente vite un grand nombre de combinaisons à vérifier.
|
||||
|
||||
\par De plus, la réservation doit rester ergonomique, et s'afficher dans un format le plus lisible possible pour un
|
||||
humain. Là dessus, un tableau est le plus approprié, avec chaque jour représenté par une colonne, et chaque créneau par
|
||||
une ligne.\\
|
||||
Mais cela ne représente malheureusement pas la temporalité, et la génération du tableau devient alors plutôt compliquée,
|
||||
et d'autant plus si l'on veut qu'il soit sémantiquement correct en HTML.
|
||||
|
||||
\subsection{Gestion des timezones}
|
||||
\label{sub:gestion_des_timezones}
|
||||
\par La gestion et le stockage des crénaux implique l'utilisation de champs de type \verb#DateTime#. \textbf{Django} les
|
||||
gère très bien, particulièrement au niveau des \emph{timezones}, où ce dernier n'hésite pas à lancer un warning lorsque
|
||||
l'objet \emph{date} passé ne contient pas d'information de fuseau horaire.
|
||||
|
||||
\par Mais avec notre décalage d'une heure par rapport au temps UTC, tous les horaires se retrouvent décalés, et gérer
|
||||
cela convenablement sans sortir d'avertissement a été plutôt compliqué. La solution a été de forcer un peu partout la
|
||||
\emph{timezone} à UTC, afin de ne pas créer de décalage, mais en conservant tout de même l'information de fuseau
|
||||
horaire, et sans tout casser lors du passage à l'heure d'hiver.
|
||||
|
||||
|
||||
\chapter{La communication}
|
||||
\label{sec:la_communication}
|
||||
\par Développeur principal: Florent
|
||||
|
||||
\section{But}
|
||||
\label{sub:but}
|
||||
\par Cette application a plusieurs but:
|
||||
\begin{itemize}
|
||||
\item Donner la possibilité au responsable communication d'éditer les différents textes, messages, et pages
|
||||
statiques du site.
|
||||
\item Fournir un système de news.
|
||||
\item Fournir un système de newsletter: le Weekmail.
|
||||
\end{itemize}
|
||||
|
||||
\section{Principaux problèmes}
|
||||
\label{sec:principaux_problemes}
|
||||
|
||||
\subsection{Envoie de mails}
|
||||
\label{sub:envoie_de_mails}
|
||||
\par Un outil de \emph{newsletter} nécessite l'envoie de mail. C'est là quelque chose de relativement compliqué à
|
||||
tester, d'autant plus lorsqu'il s'agit de mailing-list contenant l'intégralité des étudiants de l'UTBM.
|
||||
|
||||
\par \textbf{Django} fournit toutefois un outil très pratique: il contient plusieurs \emph{backend} d'emails, dont entre
|
||||
autre un \emph{SMTP}, et un \emph{console}. Le \emph{SMTP} est bien évidemment utilisé en production pour envoyer
|
||||
effectivement les mails, mais il est compliqué à utiliser en développement, car il suppose que le développeur a à sa
|
||||
disposition un serveur de ce type. On utilise alors le backend \emph{console}, qui affiche simplement dans le thread
|
||||
d'execution de \textbf{Django} une version texte de l'email envoyé, avec d'une part les entêtes, d'autre part le corps
|
||||
de message.
|
||||
|
||||
\par Mais autant pour tester l'envoie d'un mail unique à une adresse unique, cela fonctionne parfaitement bien, ce n'est
|
||||
toutefois pas suffisant pour tester un envoie massif à plusieurs mailings, avec en plus encore d'autres adresses en
|
||||
\emph{Bcc} pour les gens ne faisant pas partie des mailings "classiques", mais souhaitant quand même recevoir le
|
||||
\textbf{Weekmail}.
|
||||
|
||||
\subsection{Amélioration de l'outil de recherche}
|
||||
\label{sub:amelioration_de_l_outil_de_recherche}
|
||||
\par Pour la gestion de l'AE, il est nécessaire de pouvoir rechercher et trouver efficacement n'importe quel membre, en
|
||||
tapant au choix son nom, prénom, ou surnom, voire une combinaison de ces trois champs.
|
||||
|
||||
\par Mais une fonction de recherche aussi complexe est très difficile a mettre en place efficacement sans un traitement
|
||||
préalable, d'où la nécessité d'indexer les entrées à chercher. Un indexeur étant très complexe, mais également très
|
||||
courant, il n'a pas été difficile de trouver une application déjà existante fournissant ces fonctionnalités.
|
||||
|
||||
\par Le choix s'est porté sur \textbf{Haystack}, en l'utilisant avec l'indexeur \textbf{Whoosh}, plutôt efficace pour
|
||||
des bases raisonnables, et surtout écrit en pure \textbf{Python}, donc ne nécessitant pas d'installation compliquée en
|
||||
parallèle du site.
|
||||
|
||||
\par Le résultat est plutôt satisfaisant, mais il faudrait encore améliorer les résultats en utilisant les fonctions de
|
||||
\emph{boost} pour certains champs. De plus, une certaine lenteur se fait encore sentir avec certaines recherches trop
|
||||
communes ou générales.
|
||||
|
||||
|
||||
\chapter{Conclusions personnelles}
|
||||
\section{Florent}
|
||||
\label{sec:skia}
|
||||
\par Développer de nouvelles application m'a permis d'apréhender d'autres problématiques, comme la gestion des fichiers
|
||||
dans le SAS, ou bien des contraintes de concurrence et d'atomicité sur l'Eboutic.
|
||||
|
||||
\par Mais la plus grosse partie de mon travail ce semestre a surtout été de superviser une équipe de développement
|
||||
naissante, de relire les "Merge request", et de m'assurer de la cohérence du code des contributeurs avec le reste du
|
||||
projet.
|
||||
|
||||
\par J'ai églament pu approfondir mon utilisation de Gitlab à travers ses outils de gestion de projet, de revue de code,
|
||||
et de gestion des permissions sur les différentes branches.
|
||||
|
||||
\section{Guillaume}
|
||||
\label{sec:lo_j}
|
||||
\par Je suis très heureux d'avoir pu participer à ce projet de TO52 sur le développement de modules sur le site de
|
||||
l'Association des Étudiants. J'ai pu apprendre à travailler avec un nouvel environnement informatique tout en
|
||||
contribuant au développement d'outils pour l'association dont je suis Président, le Bureau des Festivités.
|
||||
|
||||
\subsection{Django}
|
||||
\par Ayant déjà travaillé avec le framework Spring et Java durant mon stage ST40, j'ai pu m'appuyer sur des notions
|
||||
générales afin d'apprendre et de comprendre le fonctionnement du Python et de Django que je ne connaissais pas du tout.
|
||||
|
||||
\par Mon apprentissage a été assez long au départ, car il y avait beaucoup d'informations à intégrer. Django est un
|
||||
framework très pratique qui permet d'effectuer de nombreuses tâches assez rébarbatives de manière automatique certes,
|
||||
mais encore faut-il comprendre ce qu'il se passe en arrière-plan. C'est cet apprentissage qui m'a pris le plus de temps.
|
||||
|
||||
\par Mon deuxième point de difficulté a été les formulaires. Là encore, Django est très pratique dès lors qu'il s'agit
|
||||
de faire un formulaire avec tous les champs d'un même Model. Cependant, il m'a fallu de l'aide et du temps pour
|
||||
comprendre comment faire pour ajouter d'autres champs en plus de ceux du Model au formulaire et pour comprendre comment
|
||||
récupérer les valeurs associées à chacun d'eux.
|
||||
|
||||
\subsection{Git}
|
||||
\par J'ai eu aussi à apprendre le fonctionnement de Git que j'avais déjà pu manipuler quelque peu mais il me manquait
|
||||
quand même beaucoup d'éléments.
|
||||
|
||||
\par Aujourd'hui, je pense pouvoir dire que j'ai progressé dans ce domaine mais il me reste encore bien des choses à
|
||||
apprendre pour être capable de l'utiliser de manière efficace.
|
||||
|
||||
\includepdf[pages={2}]{Couvertures.pdf}
|
||||
|
||||
\end{document}
|
||||
|
@ -1,18 +0,0 @@
|
||||
LATEX := pdflatex
|
||||
TARGET := slide.pdf
|
||||
|
||||
.PHONY: all clean distclean
|
||||
|
||||
all: $(TARGET) clean
|
||||
|
||||
%.pdf: %.tex
|
||||
echo "Building pdf"
|
||||
$(LATEX) --shell-escape $<
|
||||
rm -f $@
|
||||
$(LATEX) --shell-escape $<
|
||||
|
||||
clean:
|
||||
rm -f *.log *.nav *.snm *.aux *.out *.toc *.pyg
|
||||
|
||||
distclean: clean
|
||||
rm -f $(TARGET)
|
@ -1,133 +0,0 @@
|
||||
%%
|
||||
%% This is file `beamercolorthememetropolis.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% beamercolorthememetropolis.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{beamercolorthememetropolis}[2016/02/21 Metropolis color theme]
|
||||
\RequirePackage{pgfopts}
|
||||
\pgfkeys{
|
||||
/metropolis/color/block/.cd,
|
||||
.is choice,
|
||||
transparent/.code=\metropolis@block@transparent,
|
||||
fill/.code=\metropolis@block@fill,
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/color/background/.cd,
|
||||
.is choice,
|
||||
dark/.code=\metropolis@colors@dark,
|
||||
light/.code=\metropolis@colors@light,
|
||||
}
|
||||
\newcommand{\metropolis@color@setdefaults}{
|
||||
\pgfkeys{/metropolis/color/.cd,
|
||||
background=light,
|
||||
block=transparent,
|
||||
}
|
||||
}
|
||||
\definecolor{mDarkBrown}{HTML}{604c38}
|
||||
\definecolor{mDarkTeal}{HTML}{23373b}
|
||||
\definecolor{mLightBrown}{HTML}{EB811B}
|
||||
\definecolor{mLightGreen}{HTML}{14B03D}
|
||||
\newcommand{\metropolis@colors@dark}{
|
||||
\setbeamercolor{normal text}{%
|
||||
fg=black!2,
|
||||
bg=mDarkTeal
|
||||
}
|
||||
}
|
||||
\newcommand{\metropolis@colors@light}{
|
||||
\setbeamercolor{normal text}{%
|
||||
fg=mDarkTeal,
|
||||
bg=black!2
|
||||
}
|
||||
}
|
||||
\setbeamercolor{alerted text}{%
|
||||
fg=mLightBrown
|
||||
}
|
||||
\setbeamercolor{example text}{%
|
||||
fg=mLightGreen
|
||||
}
|
||||
\setbeamercolor{titlelike}{use=normal text, parent=normal text}
|
||||
\setbeamercolor{author}{use=normal text, parent=normal text}
|
||||
\setbeamercolor{date}{use=normal text, parent=normal text}
|
||||
\setbeamercolor{institute}{use=normal text, parent=normal text}
|
||||
\setbeamercolor{structure}{use=normal text, fg=normal text.fg}
|
||||
\setbeamercolor{palette primary}{%
|
||||
use=normal text,
|
||||
fg=normal text.bg,
|
||||
bg=normal text.fg
|
||||
}
|
||||
\setbeamercolor{frametitle}{%
|
||||
use=palette primary,
|
||||
parent=palette primary
|
||||
}
|
||||
\setbeamercolor{progress bar}{%
|
||||
use=alerted text,
|
||||
fg=alerted text.fg,
|
||||
bg=alerted text.fg!50!black!30
|
||||
}
|
||||
\setbeamercolor{title separator}{
|
||||
use=progress bar,
|
||||
parent=progress bar
|
||||
}
|
||||
\setbeamercolor{progress bar in head/foot}{%
|
||||
use=progress bar,
|
||||
parent=progress bar
|
||||
}
|
||||
\setbeamercolor{progress bar in section page}{
|
||||
use=progress bar,
|
||||
parent=progress bar
|
||||
}
|
||||
\newcommand{\metropolis@block@transparent}{
|
||||
\setbeamercolor{block title}{%
|
||||
use=normal text,
|
||||
fg=normal text.fg,
|
||||
bg=
|
||||
}
|
||||
\setbeamercolor{block body}{
|
||||
bg=
|
||||
}
|
||||
}
|
||||
\newcommand{\metropolis@block@fill}{
|
||||
\setbeamercolor{block title}{%
|
||||
use=normal text,
|
||||
fg=normal text.fg,
|
||||
bg=normal text.bg!80!fg
|
||||
}
|
||||
\setbeamercolor{block body}{
|
||||
use={block title, normal text},
|
||||
bg=block title.bg!50!normal text.bg
|
||||
}
|
||||
}
|
||||
\setbeamercolor{block title alerted}{%
|
||||
use={block title, alerted text},
|
||||
bg=block title.bg,
|
||||
fg=alerted text.fg
|
||||
}
|
||||
\setbeamercolor{block title example}{%
|
||||
use={block title, example text},
|
||||
bg=block title.bg,
|
||||
fg=example text.fg
|
||||
}
|
||||
\setbeamercolor{block body alerted}{use=block body, parent=block body}
|
||||
\setbeamercolor{block body example}{use=block body, parent=block body}
|
||||
\setbeamercolor{footnote}{fg=normal text.fg!90}
|
||||
\setbeamercolor{footnote mark}{fg=.}
|
||||
\metropolis@color@setdefaults
|
||||
\ProcessPgfPackageOptions{/metropolis/color}
|
||||
\mode<all>
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `beamercolorthememetropolis.sty'.
|
@ -1,283 +0,0 @@
|
||||
%%
|
||||
%% This is file `beamerfontthememetropolis.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% beamerfontthememetropolis.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{beamerfontthememetropolis}[2016/02/21 Metropolis font theme]
|
||||
\RequirePackage{etoolbox}
|
||||
\RequirePackage{ifxetex}
|
||||
\RequirePackage{ifluatex}
|
||||
\RequirePackage{pgfopts}
|
||||
\ifboolexpr{bool {xetex} or bool {luatex}}{
|
||||
\RequirePackage[no-math]{fontspec}
|
||||
\newcounter{fontsnotfound}
|
||||
\newcommand{\checkfont}[1]{%
|
||||
\suppressfontnotfounderror=1%
|
||||
\font\x = "#1" at 10pt
|
||||
\selectfont
|
||||
\ifx\x\nullfont%
|
||||
\stepcounter{fontsnotfound}%
|
||||
\fi%
|
||||
\suppressfontnotfounderror=0%
|
||||
}
|
||||
|
||||
\newcommand{\iffontsavailable}[3]{%
|
||||
\setcounter{fontsnotfound}{0}%
|
||||
\expandafter\forcsvlist\expandafter%
|
||||
\checkfont\expandafter{#1}%
|
||||
\ifnum\value{fontsnotfound}=0%
|
||||
#2%
|
||||
\else%
|
||||
#3%
|
||||
\fi%
|
||||
}
|
||||
\iffontsavailable{Fira Sans Light,%
|
||||
Fira Sans Light Italic,%
|
||||
Fira Sans,%
|
||||
Fira Sans Italic}%
|
||||
{%
|
||||
\setsansfont[ItalicFont={Fira Sans Light Italic},%
|
||||
BoldFont={Fira Sans},%
|
||||
BoldItalicFont={Fira Sans Italic}]%
|
||||
{Fira Sans Light}%
|
||||
}{%
|
||||
\iffontsavailable{Fira Sans Light OT,%
|
||||
Fira Sans Light Italic OT,%
|
||||
Fira Sans OT,%
|
||||
Fira Sans Italic OT}%
|
||||
{%
|
||||
\setsansfont[ItalicFont={Fira Sans Light Italic OT},%
|
||||
BoldFont={Fira Sans OT},%
|
||||
BoldItalicFont={Fira Sans Italic OT}]%
|
||||
{Fira Sans Light OT}%
|
||||
}{%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Could not find Fira Sans fonts%
|
||||
}
|
||||
}
|
||||
}
|
||||
\iffontsavailable{Fira Mono, Fira Mono Bold}{%
|
||||
\setmonofont[BoldFont={Fira Mono Medium}]{Fira Mono}%
|
||||
}{%
|
||||
\iffontsavailable{Fira Mono OT, Fira Mono Bold OT}{%
|
||||
\setmonofont[BoldFont={Fira Mono Medium OT}]{Fira Mono OT}%
|
||||
}{%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Could not find Fira Mono fonts%
|
||||
}
|
||||
}
|
||||
}
|
||||
\AtBeginEnvironment{tabular}{%
|
||||
\addfontfeature{Numbers={Monospaced}}%
|
||||
}
|
||||
}{%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
You need to compile with XeLaTeX or LuaLaTeX to use the Fira fonts%
|
||||
}
|
||||
}
|
||||
\setbeamerfont{title}{size=\Large,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont{author}{size=\small}
|
||||
\setbeamerfont{date}{size=\small}
|
||||
\setbeamerfont{section title}{size=\Large,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont{block title}{size=\normalsize,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont{block title alerted}{size=\normalsize,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont*{subtitle}{size=\large}
|
||||
\setbeamerfont{frametitle}{size=\large,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont{caption}{size=\small}
|
||||
\setbeamerfont{caption name}{series=\bfseries}
|
||||
\setbeamerfont{description item}{series=\bfseries}
|
||||
\setbeamerfont{page number in head/foot}{size=\scriptsize}
|
||||
\setbeamerfont{bibliography entry author}{size=\normalsize,%
|
||||
series=\normalfont}
|
||||
\setbeamerfont{bibliography entry title}{size=\normalsize,%
|
||||
series=\bfseries}
|
||||
\setbeamerfont{bibliography entry location}{size=\normalsize,%
|
||||
series=\normalfont}
|
||||
\setbeamerfont{bibliography entry note}{size=\small,%
|
||||
series=\normalfont}
|
||||
\setbeamerfont{standout}{size=\Large,%
|
||||
series=\bfseries}
|
||||
\pgfkeys{
|
||||
/metropolis/font/titleformat title/.cd,
|
||||
.is choice,
|
||||
regular/.code={%
|
||||
\let\metropolis@titleformat\@empty%
|
||||
\setbeamerfont{title}{shape=\normalfont}%
|
||||
},
|
||||
smallcaps/.code={%
|
||||
\let\metropolis@titleformat\@empty%
|
||||
\setbeamerfont{title}{shape=\scshape}%
|
||||
},
|
||||
allsmallcaps/.code={%
|
||||
\let\metropolis@titleformat\lowercase%
|
||||
\setbeamerfont{title}{shape=\scshape}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat title=allsmallcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
allcaps/.code={%
|
||||
\let\metropolis@titleformat\uppercase%
|
||||
\setbeamerfont{title}{shape=\normalfont}
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat title=allcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/font/titleformat subtitle/.cd,
|
||||
.is choice,
|
||||
regular/.code={%
|
||||
\let\metropolis@subtitleformat\@empty%
|
||||
\setbeamerfont{subtitle}{shape=\normalfont}%
|
||||
},
|
||||
smallcaps/.code={%
|
||||
\let\metropolis@subtitleformat\@empty%
|
||||
\setbeamerfont{subtitle}{shape=\scshape}%
|
||||
},
|
||||
allsmallcaps/.code={%
|
||||
\let\metropolis@subtitleformat\lowercase%
|
||||
\setbeamerfont{subtitle}{shape=\scshape}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat subtitle=allsmallcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
allcaps/.code={%
|
||||
\let\metropolis@subtitleformat\uppercase%
|
||||
\setbeamerfont{subtitle}{shape=\normalfont}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat subtitle=allcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/font/titleformat section/.cd,
|
||||
.is choice,
|
||||
regular/.code={%
|
||||
\let\metropolis@sectiontitleformat\@empty%
|
||||
\setbeamerfont{section title}{shape=\normalfont}%
|
||||
},
|
||||
smallcaps/.code={%
|
||||
\let\metropolis@sectiontitleformat\@empty%
|
||||
\setbeamerfont{section title}{shape=\scshape}%
|
||||
},
|
||||
allsmallcaps/.code={%
|
||||
\let\metropolis@sectiontitleformat\MakeLowercase%
|
||||
\setbeamerfont{section title}{shape=\scshape}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat section=allsmallcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
allcaps/.code={%
|
||||
\let\metropolis@sectiontitleformat\MakeUppercase%
|
||||
\setbeamerfont{section title}{shape=\normalfont}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat section=allcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/font/titleformat frame/.cd,
|
||||
.is choice,
|
||||
regular/.code={%
|
||||
\let\metropolis@frametitleformat\@empty%
|
||||
\setbeamerfont{frametitle}{shape=\normalfont}%
|
||||
},
|
||||
smallcaps/.code={%
|
||||
\let\metropolis@frametitleformat\@empty%
|
||||
\setbeamerfont{frametitle}{shape=\scshape}%
|
||||
},
|
||||
allsmallcaps/.code={%
|
||||
\let\metropolis@frametitleformat\MakeLowercase%
|
||||
\setbeamerfont{frametitle}{shape=\scshape}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat frame=allsmallcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
allcaps/.code={%
|
||||
\let\metropolis@frametitleformat\MakeUppercase%
|
||||
\setbeamerfont{frametitle}{shape=\normalfont}
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat frame=allcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/font/.cd,
|
||||
titleformattitle/.code=\pgfkeysalso{titleformat title=#1},
|
||||
titleformatsubtitle/.code=\pgfkeysalso{titleformat subtitle=#1},
|
||||
titleformatsection/.code=\pgfkeysalso{titleformat section=#1},
|
||||
titleformatframe/.code=\pgfkeysalso{titleformat frame=#1},
|
||||
}
|
||||
\newcommand{\metropolis@font@setdefaults}{
|
||||
\pgfkeys{/metropolis/font/.cd,
|
||||
titleformat title=regular,
|
||||
titleformat subtitle=regular,
|
||||
titleformat section=regular,
|
||||
titleformat frame=regular,
|
||||
}
|
||||
}
|
||||
\def\metropolis@titleformat#1{#1}
|
||||
\def\metropolis@subtitleformat#1{#1}
|
||||
\def\metropolis@sectiontitleformat#1{#1}
|
||||
\def\metropolis@frametitleformat#1{#1}
|
||||
\patchcmd{\beamer@title}%
|
||||
{\def\inserttitle{#2}}%
|
||||
{\def\inserttitle{\metropolis@titleformat{#2}}}%
|
||||
{}%
|
||||
{\PackageError{beamerfontthememetropolis}{Patching title failed}}
|
||||
\patchcmd{\beamer@subtitle}%
|
||||
{\def\insertsubtitle{#2}}%
|
||||
{\def\insertsubtitle{\metropolis@subtitleformat{#2}}}%
|
||||
{}%
|
||||
{\PackageError{beamerfontthememetropolis}{Patching subtitle failed}}
|
||||
\patchcmd{\sectionentry}
|
||||
{\def\insertsectionhead{#2}}
|
||||
{\def\insertsectionhead{\metropolis@sectiontitleformat{#2}}}
|
||||
{}
|
||||
{\PackageError{beamerfontthememetropolis}{Patching section title failed}}
|
||||
\patchcmd{\beamer@section}
|
||||
{\def\insertsectionhead{\hyperlink{Navigation\the\c@page}{#1}}}
|
||||
{\def\insertsectionhead{\hyperlink{Navigation\the\c@page}{%
|
||||
\metropolis@sectiontitleformat{#1}}}}
|
||||
{}
|
||||
{\PackageError{beamerfontthememetropolis}{Patching section title failed}}
|
||||
\patchcmd{\beamer@@frametitle}
|
||||
{\beamer@ifempty{#2}{}{%
|
||||
\gdef\insertframetitle{{#2\ifnum\beamer@autobreakcount>0\relax{}\space%
|
||||
\usebeamertemplate*{frametitle continuation}\fi}}%
|
||||
\gdef\beamer@frametitle{#2}%
|
||||
\gdef\beamer@shortframetitle{#1}%
|
||||
}}
|
||||
{\beamer@ifempty{#2}{}{%
|
||||
\gdef\insertframetitle{{\metropolis@frametitleformat{#2}\ifnum%
|
||||
\beamer@autobreakcount>0\relax{}\space%
|
||||
\usebeamertemplate*{frametitle continuation}\fi}}%
|
||||
\gdef\beamer@frametitle{#2}%
|
||||
\gdef\beamer@shortframetitle{#1}%
|
||||
}}
|
||||
{}
|
||||
{\PackageError{beamerfontthememetropolis}{Patching frame title failed}}
|
||||
\metropolis@font@setdefaults
|
||||
\ProcessPgfPackageOptions{/metropolis/font}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `beamerfontthememetropolis.sty'.
|
@ -1,281 +0,0 @@
|
||||
%%
|
||||
%% This is file `beamerinnerthememetropolis.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% beamerinnerthememetropolis.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{beamerinnerthememetropolis}[2016/02/21 Metropolis inner theme]
|
||||
\RequirePackage{etoolbox}
|
||||
\RequirePackage{keyval}
|
||||
\RequirePackage{calc}
|
||||
\RequirePackage{pgfopts}
|
||||
\RequirePackage{tikz}
|
||||
\pgfkeys{
|
||||
/metropolis/inner/sectionpage/.cd,
|
||||
.is choice,
|
||||
none/.code=\metropolis@disablesectionpage,
|
||||
simple/.code={\metropolis@enablesectionpage
|
||||
\setbeamertemplate{section page}[simple]},
|
||||
progressbar/.code={\metropolis@enablesectionpage
|
||||
\setbeamertemplate{section page}[progressbar]},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/inner/subsectionpage/.cd,
|
||||
.is choice,
|
||||
none/.code=\metropolis@disablesubsectionpage,
|
||||
simple/.code={\metropolis@enablesubsectionpage
|
||||
\setbeamertemplate{section page}[simple]},
|
||||
progressbar/.code={\metropolis@enablesubsectionpage
|
||||
\setbeamertemplate{section page}[progressbar]},
|
||||
}
|
||||
\newcommand{\metropolis@inner@setdefaults}{
|
||||
\pgfkeys{/metropolis/inner/.cd,
|
||||
sectionpage=progressbar,
|
||||
subsectionpage=none
|
||||
}
|
||||
}
|
||||
\setbeamertemplate{title page}{
|
||||
\begin{minipage}[b][\paperheight]{\textwidth}
|
||||
\ifx\inserttitlegraphic\@empty\else\usebeamertemplate*{title graphic}\fi
|
||||
\vfill%
|
||||
\ifx\inserttitle\@empty\else\usebeamertemplate*{title}\fi
|
||||
\ifx\insertsubtitle\@empty\else\usebeamertemplate*{subtitle}\fi
|
||||
\usebeamertemplate*{title separator}
|
||||
\ifx\beamer@shortauthor\@empty\else\usebeamertemplate*{author}\fi
|
||||
\ifx\insertdate\@empty\else\usebeamertemplate*{date}\fi
|
||||
\ifx\insertinstitute\@empty\else\usebeamertemplate*{institute}\fi
|
||||
\vfill
|
||||
\vspace*{1mm}
|
||||
\end{minipage}
|
||||
}
|
||||
\def\maketitle{%
|
||||
\ifbeamer@inframe
|
||||
\titlepage
|
||||
\else
|
||||
\frame[plain,noframenumbering]{\titlepage}
|
||||
\fi
|
||||
}
|
||||
\def\titlepage{%
|
||||
\usebeamertemplate{title page}
|
||||
}
|
||||
\setbeamertemplate{title graphic}{
|
||||
\vbox to 0pt {
|
||||
\vspace*{2em}
|
||||
\inserttitlegraphic%
|
||||
}%
|
||||
\nointerlineskip%
|
||||
}
|
||||
\setbeamertemplate{title}{
|
||||
\raggedright%
|
||||
\linespread{1.0}%
|
||||
\inserttitle%
|
||||
\par%
|
||||
\vspace*{0.5em}
|
||||
}
|
||||
\setbeamertemplate{subtitle}{
|
||||
\insertsubtitle%
|
||||
\par%
|
||||
\vspace*{0.5em}
|
||||
}
|
||||
\setbeamertemplate{title separator}{
|
||||
\begin{tikzpicture}
|
||||
\draw[fg, fill=fg] (0,0) rectangle (\textwidth, 0.4pt);
|
||||
\end{tikzpicture}%
|
||||
\par%
|
||||
}
|
||||
\setbeamertemplate{author}{
|
||||
\vspace*{2em}
|
||||
\insertauthor%
|
||||
\par%
|
||||
\vspace*{0.25em}
|
||||
}
|
||||
\setbeamertemplate{date}{
|
||||
\insertdate%
|
||||
\par%
|
||||
}
|
||||
\setbeamertemplate{institute}{
|
||||
\vspace*{3mm}
|
||||
\insertinstitute%
|
||||
\par%
|
||||
}
|
||||
\defbeamertemplate{section page}{simple}{
|
||||
\begin{center}
|
||||
\usebeamercolor[fg]{section title}
|
||||
\usebeamerfont{section title}
|
||||
\insertsectionhead\par
|
||||
\ifx\insertsubsection\@empty\else
|
||||
\usebeamercolor[fg]{subsection title}
|
||||
\usebeamerfont{subsection title}
|
||||
\insertsubsection
|
||||
\fi
|
||||
\end{center}
|
||||
}
|
||||
\defbeamertemplate{section page}{progressbar}{
|
||||
\centering
|
||||
\begin{minipage}{22em}
|
||||
\raggedright
|
||||
\usebeamercolor[fg]{section title}
|
||||
\usebeamerfont{section title}
|
||||
\insertsectionhead\\[-1ex]
|
||||
\usebeamertemplate*{progress bar in section page}
|
||||
\par
|
||||
\ifx\insertsubsection\@empty\else%
|
||||
\usebeamercolor[fg]{subsection title}%
|
||||
\usebeamerfont{subsection title}%
|
||||
\insertsubsection
|
||||
\fi
|
||||
\end{minipage}
|
||||
\par
|
||||
\vspace{\baselineskip}
|
||||
}
|
||||
\newcommand{\metropolis@disablesectionpage}{
|
||||
\AtBeginSection{
|
||||
% intentionally empty
|
||||
}
|
||||
}
|
||||
\newcommand{\metropolis@enablesectionpage}{
|
||||
\AtBeginSection{
|
||||
\ifbeamer@inframe
|
||||
\sectionpage
|
||||
\else
|
||||
\frame[plain,c,noframenumbering]{\sectionpage}
|
||||
\fi
|
||||
}
|
||||
}
|
||||
\setbeamertemplate{subsection page}{%
|
||||
\usebeamertemplate*{section page}
|
||||
}
|
||||
\newcommand{\metropolis@disablesubsectionpage}{
|
||||
\AtBeginSubsection{
|
||||
% intentionally empty
|
||||
}
|
||||
}
|
||||
\newcommand{\metropolis@enablesubsectionpage}{
|
||||
\AtBeginSubsection{
|
||||
\ifbeamer@inframe
|
||||
\subsectionpage
|
||||
\else
|
||||
\frame[plain,c,noframenumbering]{\subsectionpage}
|
||||
\fi
|
||||
}
|
||||
}
|
||||
\newlength{\metropolis@progressonsectionpage}
|
||||
\setbeamertemplate{progress bar in section page}{
|
||||
\setlength{\metropolis@progressonsectionpage}{%
|
||||
\textwidth * \ratio{\insertframenumber pt}{\inserttotalframenumber pt}%
|
||||
}%
|
||||
\begin{tikzpicture}
|
||||
\draw[bg, fill=bg] (0,0) rectangle (\textwidth, 0.4pt);
|
||||
\draw[fg, fill=fg] (0,0) rectangle (\metropolis@progressonsectionpage, 0.4pt);
|
||||
\end{tikzpicture}%
|
||||
}
|
||||
\def\inserttotalframenumber{100}
|
||||
\newlength{\metropolis@blocksep}
|
||||
\newlength{\metropolis@blockadjust}
|
||||
\setlength{\metropolis@blocksep}{0.75ex}
|
||||
\setlength{\metropolis@blockadjust}{0.25ex}
|
||||
\providecommand{\metropolis@strut}{%
|
||||
\vphantom{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz()}%
|
||||
}
|
||||
\newcommand{\metropolis@block}[1]{
|
||||
\par\vskip\medskipamount%
|
||||
\setlength{\parskip}{0pt}
|
||||
\ifbeamercolorempty[bg]{block title#1}{%
|
||||
\begin{beamercolorbox}[rightskip=0pt plus 4em]{block title#1}}{%
|
||||
\ifbeamercolorempty[bg]{block title}{%
|
||||
\begin{beamercolorbox}[rightskip=0pt plus 4em]{block title#1}%
|
||||
}%
|
||||
{%
|
||||
\begin{beamercolorbox}[
|
||||
sep=\dimexpr\metropolis@blocksep-\metropolis@blockadjust\relax,
|
||||
leftskip=\metropolis@blockadjust,
|
||||
rightskip=\dimexpr\metropolis@blockadjust plus 4em\relax
|
||||
]{block title#1}%
|
||||
}}%
|
||||
\usebeamerfont*{block title#1}%
|
||||
\metropolis@strut%
|
||||
\insertblocktitle%
|
||||
\metropolis@strut%
|
||||
\end{beamercolorbox}%
|
||||
\nointerlineskip%
|
||||
\ifbeamercolorempty[bg]{block body#1}{%
|
||||
\begin{beamercolorbox}[vmode]{block body#1}}{
|
||||
\ifbeamercolorempty[bg]{block body}{%
|
||||
\begin{beamercolorbox}[vmode]{block body#1}%
|
||||
}{%
|
||||
\begin{beamercolorbox}[sep=\metropolis@blocksep, vmode]{block body#1}%
|
||||
\vspace{-\metropolis@parskip}
|
||||
}}%
|
||||
\usebeamerfont{block body#1}%
|
||||
\setlength{\parskip}{\metropolis@parskip}%
|
||||
}
|
||||
\setbeamertemplate{block begin}{\metropolis@block{}}
|
||||
\setbeamertemplate{block alerted begin}{\metropolis@block{ alerted}}
|
||||
\setbeamertemplate{block example begin}{\metropolis@block{ example}}
|
||||
\setbeamertemplate{block end}{\end{beamercolorbox}\vspace*{0.2ex}}
|
||||
\setbeamertemplate{block alerted end}{\end{beamercolorbox}\vspace*{0.2ex}}
|
||||
\setbeamertemplate{block example end}{\end{beamercolorbox}\vspace*{0.2ex}}
|
||||
\setbeamertemplate{itemize items}{\textbullet}
|
||||
\setbeamertemplate{caption label separator}{: }
|
||||
\setbeamertemplate{caption}[numbered]
|
||||
\setbeamertemplate{footnote}{%
|
||||
\parindent 0em\noindent%
|
||||
\raggedright
|
||||
\usebeamercolor{footnote}\hbox to 0.8em{\hfil\insertfootnotemark}\insertfootnotetext\par%
|
||||
}
|
||||
\newlength{\metropolis@parskip}
|
||||
\setlength{\metropolis@parskip}{0.5em}
|
||||
\setlength{\parskip}{\metropolis@parskip}
|
||||
\linespread{1.15}
|
||||
\define@key{beamerframe}{c}[true]{% centered
|
||||
\beamer@frametopskip=0pt plus 1fill\relax%
|
||||
\beamer@framebottomskip=0pt plus 1fill\relax%
|
||||
\beamer@frametopskipautobreak=0pt plus .4\paperheight\relax%
|
||||
\beamer@framebottomskipautobreak=0pt plus .6\paperheight\relax%
|
||||
\def\beamer@initfirstlineunskip{}%
|
||||
}
|
||||
\providebool{metropolis@standout}
|
||||
\define@key{beamerframe}{standout}[true]{%
|
||||
\booltrue{metropolis@standout}
|
||||
\begingroup
|
||||
\setkeys{beamerframe}{c}
|
||||
\setkeys{beamerframe}{noframenumbering}
|
||||
\ifbeamercolorempty[bg]{palette primary}{
|
||||
\setbeamercolor{background canvas}{
|
||||
use=palette primary,
|
||||
bg=-palette primary.fg
|
||||
}
|
||||
}{
|
||||
\setbeamercolor{background canvas}{
|
||||
use=palette primary,
|
||||
bg=palette primary.bg
|
||||
}
|
||||
}
|
||||
\centering
|
||||
\usebeamercolor[fg]{palette primary}
|
||||
\usebeamerfont{standout}
|
||||
}
|
||||
\apptocmd{\beamer@reseteecodes}{%
|
||||
\ifbool{metropolis@standout}{
|
||||
\endgroup
|
||||
\boolfalse{metropolis@standout}
|
||||
}{}
|
||||
}{}{}
|
||||
\metropolis@inner@setdefaults
|
||||
\ProcessPgfPackageOptions{/metropolis/inner}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `beamerinnerthememetropolis.sty'.
|
@ -1,126 +0,0 @@
|
||||
%%
|
||||
%% This is file `beamerouterthememetropolis.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% beamerouterthememetropolis.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{beamerouterthememetropolis}[2016/02/21 Metropolis outer theme]
|
||||
\RequirePackage{etoolbox}
|
||||
\RequirePackage{calc}
|
||||
\RequirePackage{pgfopts}
|
||||
\pgfkeys{
|
||||
/metropolis/outer/numbering/.cd,
|
||||
.is choice,
|
||||
none/.code=\setbeamertemplate{frame numbering}[none],
|
||||
counter/.code=\setbeamertemplate{frame numbering}[counter],
|
||||
fraction/.code=\setbeamertemplate{frame numbering}[fraction],
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/outer/progressbar/.cd,
|
||||
.is choice,
|
||||
none/.code={%
|
||||
\setbeamertemplate{headline}[plain]
|
||||
\setbeamertemplate{frametitle}[plain]
|
||||
\setbeamertemplate{footline}[plain]
|
||||
},
|
||||
head/.code={\pgfkeys{/metropolis/outer/progressbar=none}
|
||||
\addtobeamertemplate{headline}{}{%
|
||||
\usebeamertemplate*{progress bar in head/foot}
|
||||
}
|
||||
},
|
||||
frametitle/.code={\pgfkeys{/metropolis/outer/progressbar=none}
|
||||
\addtobeamertemplate{frametitle}{}{%
|
||||
\usebeamertemplate*{progress bar in head/foot}
|
||||
}
|
||||
},
|
||||
foot/.code={\pgfkeys{/metropolis/outer/progressbar=none}
|
||||
\addtobeamertemplate{footline}{}{%
|
||||
\usebeamertemplate*{progress bar in head/foot}%
|
||||
}
|
||||
},
|
||||
}
|
||||
\newcommand{\metropolis@outer@setdefaults}{
|
||||
\pgfkeys{/metropolis/outer/.cd,
|
||||
numbering=counter,
|
||||
progressbar=none,
|
||||
}
|
||||
}
|
||||
\setbeamertemplate{navigation symbols}{}
|
||||
\defbeamertemplate{frame footer}{none}{}
|
||||
\defbeamertemplate{frame footer}{custom}[1]{ #1 }
|
||||
\defbeamertemplate{frame numbering}{none}{}
|
||||
\defbeamertemplate{frame numbering}{counter}{\insertframenumber}
|
||||
\defbeamertemplate{frame numbering}{fraction}{
|
||||
\insertframenumber/\inserttotalframenumber
|
||||
}
|
||||
\defbeamertemplate{headline}{plain}{}
|
||||
\defbeamertemplate{footline}{plain}{%
|
||||
\begin{beamercolorbox}[wd=\textwidth, sep=3ex]{footline}%
|
||||
\usebeamerfont{page number in head/foot}%
|
||||
\usebeamertemplate*{frame footer}
|
||||
\hfill%
|
||||
\usebeamertemplate*{frame numbering}
|
||||
\end{beamercolorbox}%
|
||||
}
|
||||
\newlength{\metropolis@frametitle@padding}
|
||||
\setlength{\metropolis@frametitle@padding}{2.2ex}
|
||||
\newcommand{\metropolis@frametitlestrut@start}{
|
||||
\rule{0pt}{\metropolis@frametitle@padding +%
|
||||
\totalheightof{%
|
||||
\ifcsdef{metropolis@frametitleformat}{\metropolis@frametitleformat X}{X}%
|
||||
}%
|
||||
}%
|
||||
}
|
||||
\newcommand{\metropolis@frametitlestrut@end}{
|
||||
\rule[-\metropolis@frametitle@padding]{0pt}{\metropolis@frametitle@padding}
|
||||
}
|
||||
\defbeamertemplate{frametitle}{plain}{%
|
||||
\nointerlineskip%
|
||||
\begin{beamercolorbox}[%
|
||||
wd=\paperwidth,%
|
||||
sep=0pt,%
|
||||
leftskip=\metropolis@frametitle@padding,%
|
||||
rightskip=\metropolis@frametitle@padding,%
|
||||
]{frametitle}%
|
||||
\metropolis@frametitlestrut@start\insertframetitle\metropolis@frametitlestrut@end%
|
||||
\end{beamercolorbox}%
|
||||
}
|
||||
\newlength{\metropolis@progressinheadfoot}
|
||||
\setbeamertemplate{progress bar in head/foot}{
|
||||
\nointerlineskip
|
||||
\setlength{\metropolis@progressinheadfoot}{%
|
||||
\paperwidth * \ratio{\insertframenumber pt}{\inserttotalframenumber pt}%
|
||||
}%
|
||||
\begin{beamercolorbox}[wd=\paperwidth]{progress bar in head/foot}
|
||||
\begin{tikzpicture}
|
||||
\draw[bg, fill=bg] (0,0) rectangle (\paperwidth, 0.4pt);
|
||||
\draw[fg, fill=fg] (0,0) rectangle (\metropolis@progressinheadfoot, 0.4pt);
|
||||
\end{tikzpicture}%
|
||||
\end{beamercolorbox}
|
||||
}
|
||||
\AtBeginDocument{%
|
||||
\apptocmd{\appendix}{%
|
||||
\pgfkeys{%
|
||||
/metropolis/outer/.cd,
|
||||
numbering=none,
|
||||
progressbar=none}
|
||||
}{}{}
|
||||
}
|
||||
\metropolis@outer@setdefaults
|
||||
\ProcessPgfPackageOptions{/metropolis/outer}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `beamerouterthememetropolis.sty'.
|
@ -1,105 +0,0 @@
|
||||
%%
|
||||
%% This is file `beamerthememetropolis.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% beamerthememetropolis.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{beamerthememetropolis}
|
||||
[2016/02/21 v1.1 Metropolis Beamer theme]
|
||||
\RequirePackage{etoolbox}
|
||||
\RequirePackage{pgfopts}
|
||||
\pgfkeys{/metropolis/.cd,
|
||||
.search also={
|
||||
/metropolis/inner,
|
||||
/metropolis/outer,
|
||||
/metropolis/color,
|
||||
/metropolis/font,
|
||||
}
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/titleformat plain/.cd,
|
||||
.is choice,
|
||||
regular/.code={%
|
||||
\let\metropolis@plaintitleformat\@empty%
|
||||
\setbeamerfont{standout}{shape=\normalfont}%
|
||||
},
|
||||
smallcaps/.code={%
|
||||
\let\metropolis@plaintitleformat\@empty%
|
||||
\setbeamerfont{standout}{shape=\scshape}%
|
||||
},
|
||||
allsmallcaps/.code={%
|
||||
\let\metropolis@plaintitleformat\MakeLowercase%
|
||||
\setbeamerfont{standout}{shape=\scshape}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat plain=allsmallcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
allcaps/.code={%
|
||||
\let\metropolis@plaintitleformat\MakeUppercase%
|
||||
\setbeamerfont{standout}{shape=\normalfont}%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
Be aware that titleformat plain=allcaps can lead to problems%
|
||||
}
|
||||
},
|
||||
}
|
||||
\pgfkeys{
|
||||
/metropolis/titleformat/.code=\pgfkeysalso{
|
||||
font/titleformat title=#1,
|
||||
font/titleformat subtitle=#1,
|
||||
font/titleformat section=#1,
|
||||
font/titleformat frame=#1,
|
||||
titleformat plain=#1,
|
||||
}
|
||||
}
|
||||
\pgfkeys{/metropolis/.cd,
|
||||
usetitleprogressbar/.code=\pgfkeysalso{outer/progressbar=frametitle},
|
||||
noslidenumbers/.code=\pgfkeysalso{outer/numbering=none},
|
||||
usetotalslideindicator/.code=\pgfkeysalso{outer/numbering=fraction},
|
||||
nosectionslide/.code=\pgfkeysalso{inner/sectionpage=none},
|
||||
darkcolors/.code=\pgfkeysalso{color/background=dark},
|
||||
blockbg/.code=\pgfkeysalso{color/block=fill, inner/block=fill},
|
||||
}
|
||||
\newcommand{\metropolis@setdefaults}{
|
||||
\pgfkeys{/metropolis/.cd,
|
||||
titleformat plain=regular,
|
||||
}
|
||||
}
|
||||
\useinnertheme{metropolis}
|
||||
\useoutertheme{metropolis}
|
||||
\usecolortheme{metropolis}
|
||||
\usefonttheme{metropolis}
|
||||
\AtEndPreamble{%
|
||||
\@ifpackageloaded{pgfplots}{%
|
||||
\RequirePackage{pgfplotsthemetol}
|
||||
}{}
|
||||
}
|
||||
\newcommand{\metroset}[1]{\pgfkeys{/metropolis/.cd,#1}}
|
||||
\def\metropolis@plaintitleformat#1{#1}
|
||||
\newcommand{\plain}[2][]{%
|
||||
\PackageWarning{beamerthememetropolis}{%
|
||||
The syntax `\plain' may be deprecated in a future version of Metropolis.
|
||||
Please use a frame with [standout] instead.
|
||||
}
|
||||
\begin{frame}[standout]{#1}
|
||||
\metropolis@plaintitleformat{#2}
|
||||
\end{frame}
|
||||
}
|
||||
\newcommand{\mreducelistspacing}{\vspace{-\topsep}}
|
||||
\metropolis@setdefaults
|
||||
\ProcessPgfOptions{/metropolis}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `beamerthememetropolis.sty'.
|
@ -1,123 +0,0 @@
|
||||
%%
|
||||
%% This is file `pgfplotsthemetol.sty',
|
||||
%% generated with the docstrip utility.
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% pgfplotsthemetol.dtx (with options: `package')
|
||||
%% ---------------------------------------------------------------------------
|
||||
%% Copyright 2015 Matthias Vogelgesang and the LaTeX community. A full list of
|
||||
%% contributors can be found at
|
||||
%%
|
||||
%% https://github.com/matze/mtheme/graphs/contributors
|
||||
%%
|
||||
%% and the original template was based on the HSRM theme by Benjamin Weiss.
|
||||
%%
|
||||
%% This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
|
||||
%% International License (https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
%% ---------------------------------------------------------------------------
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{pgfplotsthemetol}
|
||||
[2015/06/16 PGFplots colors based on Paul Tol's SRON technical note]
|
||||
\definecolor{TolDarkPurple}{HTML}{332288}
|
||||
\definecolor{TolDarkBlue}{HTML}{6699CC}
|
||||
\definecolor{TolLightBlue}{HTML}{88CCEE}
|
||||
\definecolor{TolLightGreen}{HTML}{44AA99}
|
||||
\definecolor{TolDarkGreen}{HTML}{117733}
|
||||
\definecolor{TolDarkBrown}{HTML}{999933}
|
||||
\definecolor{TolLightBrown}{HTML}{DDCC77}
|
||||
\definecolor{TolDarkRed}{HTML}{661100}
|
||||
\definecolor{TolLightRed}{HTML}{CC6677}
|
||||
\definecolor{TolLightPink}{HTML}{AA4466}
|
||||
\definecolor{TolDarkPink}{HTML}{882255}
|
||||
\definecolor{TolLightPurple}{HTML}{AA4499}
|
||||
\pgfplotscreateplotcyclelist{mbarplot cycle}{%
|
||||
{draw=TolDarkBlue, fill=TolDarkBlue!70},
|
||||
{draw=TolLightBrown, fill=TolLightBrown!70},
|
||||
{draw=TolLightGreen, fill=TolLightGreen!70},
|
||||
{draw=TolDarkPink, fill=TolDarkPink!70},
|
||||
{draw=TolDarkPurple, fill=TolDarkPurple!70},
|
||||
{draw=TolDarkRed, fill=TolDarkRed!70},
|
||||
{draw=TolDarkBrown, fill=TolDarkBrown!70},
|
||||
{draw=TolLightRed, fill=TolLightRed!70},
|
||||
{draw=TolLightPink, fill=TolLightPink!70},
|
||||
{draw=TolLightPurple, fill=TolLightPurple!70},
|
||||
{draw=TolLightBlue, fill=TolLightBlue!70},
|
||||
{draw=TolDarkGreen, fill=TolDarkGreen!70},
|
||||
}
|
||||
\pgfplotscreateplotcyclelist{mlineplot cycle}{%
|
||||
{TolDarkBlue, mark=*, mark size=1.5pt},
|
||||
{TolLightBrown, mark=square*, mark size=1.3pt},
|
||||
{TolLightGreen, mark=triangle*, mark size=1.5pt},
|
||||
{TolDarkBrown, mark=diamond*, mark size=1.5pt},
|
||||
}
|
||||
\pgfplotsset{
|
||||
compat=1.9,
|
||||
mlineplot/.style={
|
||||
mbaseplot,
|
||||
xmajorgrids=true,
|
||||
ymajorgrids=true,
|
||||
major grid style={dotted},
|
||||
axis x line=bottom,
|
||||
axis y line=left,
|
||||
legend style={
|
||||
cells={anchor=west},
|
||||
draw=none
|
||||
},
|
||||
cycle list name=mlineplot cycle,
|
||||
},
|
||||
mbarplot base/.style={
|
||||
mbaseplot,
|
||||
bar width=6pt,
|
||||
axis y line*=none,
|
||||
},
|
||||
mbarplot/.style={
|
||||
mbarplot base,
|
||||
ybar,
|
||||
xmajorgrids=false,
|
||||
ymajorgrids=true,
|
||||
area legend,
|
||||
legend image code/.code={%
|
||||
\draw[#1] (0cm,-0.1cm) rectangle (0.15cm,0.1cm);
|
||||
},
|
||||
cycle list name=mbarplot cycle,
|
||||
},
|
||||
horizontal mbarplot/.style={
|
||||
mbarplot base,
|
||||
xmajorgrids=true,
|
||||
ymajorgrids=false,
|
||||
xbar stacked,
|
||||
area legend,
|
||||
legend image code/.code={%
|
||||
\draw[#1] (0cm,-0.1cm) rectangle (0.15cm,0.1cm);
|
||||
},
|
||||
cycle list name=mbarplot cycle,
|
||||
},
|
||||
mbaseplot/.style={
|
||||
legend style={
|
||||
draw=none,
|
||||
fill=none,
|
||||
cells={anchor=west},
|
||||
},
|
||||
x tick label style={
|
||||
font=\footnotesize
|
||||
},
|
||||
y tick label style={
|
||||
font=\footnotesize
|
||||
},
|
||||
legend style={
|
||||
font=\footnotesize
|
||||
},
|
||||
major grid style={
|
||||
dotted,
|
||||
},
|
||||
axis x line*=bottom,
|
||||
},
|
||||
disable thousands separator/.style={
|
||||
/pgf/number format/.cd,
|
||||
1000 sep={}
|
||||
},
|
||||
}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `pgfplotsthemetol.sty'.
|
Binary file not shown.
@ -1,158 +0,0 @@
|
||||
\documentclass[10pt]{beamer}
|
||||
\beamertemplatenavigationsymbolsempty
|
||||
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{default}
|
||||
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{pictures/}}
|
||||
|
||||
\usepackage[french]{babel}
|
||||
\usepackage[T1]{fontenc}
|
||||
|
||||
\usetheme{metropolis}
|
||||
%\usecolortheme{dove}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Université de Technologie de Belfort-Montbéliard\\
|
||||
Département informatique}
|
||||
\vskip 4em
|
||||
\begin{center}
|
||||
{\LARGE Développement de nouveaux modules sur le projet Sith}\\
|
||||
\end{center}
|
||||
\vskip 4em
|
||||
Florent \textsc{Jacquet}\\
|
||||
Guillaume \textsc{Renaud}\\
|
||||
{\scriptsize TO52 - A16}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Sommaire}
|
||||
\tableofcontents
|
||||
\end{frame}
|
||||
|
||||
\section{Les nouvelles applications}
|
||||
\subsection{Eboutic}
|
||||
\begin{frame}[fragile]\frametitle{Eboutic}
|
||||
\begin{itemize}
|
||||
\item Fournir une boutique
|
||||
\item Paiement en ligne en lien avec l'API du Credit Agricole
|
||||
\item Gestion des cotisations et rechargements
|
||||
\item Attention aux accès concurrentiels: pas visibles pendant le développement, car mono-thread, mais problèmes
|
||||
à la mise en production
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Le SAS}
|
||||
\begin{frame}[fragile]\frametitle{Le SAS - Stock à Souvenirs}
|
||||
\begin{itemize}
|
||||
\item Galerie de photos
|
||||
\item Upload simple pour tout le monde, même pour plusieurs dizaines de photos
|
||||
\item Modération et gestion des droits basée sur la gestion des fichiers, ce qui a permis d'améliorer ces
|
||||
derniers
|
||||
\item Problèmes d'optimisation de certaines pages qui mettaient plus de 9 secondes à générer (plus que 2s
|
||||
maintenant)
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Les élections}
|
||||
\begin{frame}[fragile]\frametitle{Les élections}
|
||||
\begin{itemize}
|
||||
\item Grosse partie "gestion": c'est Sli qui a principalement développé l'application
|
||||
\item Revue des \textsc{merges request} et choix de design
|
||||
\item Problèmatique de législation vite ignorées puisque validation officielle en AG
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{La laverie}
|
||||
\begin{frame}[fragile]\frametitle{La laverie}
|
||||
\begin{itemize}
|
||||
\item Gestion d'un planning de reservation en prenant bien en compte les différents états (hors-service, ...) de
|
||||
chaque machine
|
||||
\item Génération de formulaires dynamiques en fonction des réservations (factory design pattern)
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{La communication}
|
||||
\begin{frame}[fragile]\frametitle{La communication}
|
||||
\begin{itemize}
|
||||
\item Dynamise le site avec tous les textes paramètrables
|
||||
\item Fourni un système de news
|
||||
\item Fourni une newsletter
|
||||
\end{itemize}
|
||||
\begin{itemize}
|
||||
\item Envoie de mails en masse
|
||||
\item Beaucoup de templates
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\section{La gestion des stocks}
|
||||
|
||||
\subsection{Fonctionnement}
|
||||
\begin{frame}[fragile]{Fonctionnement}
|
||||
\begin{itemize}
|
||||
\item Création automatique des listes de courses
|
||||
\item Approvisionnement des stocks
|
||||
\item Prise d'éléments dans le stock
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Améliorations et difficultés}
|
||||
\begin{frame}[fragile]\frametitle{Améliorations et difficultés}
|
||||
\begin{itemize}
|
||||
\item Mise à jour quantité liste de courses
|
||||
\item Mise à jour automatique du stock selon les ventes
|
||||
\item Ajout au système de notifications
|
||||
\end{itemize}
|
||||
\textbf{Difficultés}
|
||||
\begin{itemize}
|
||||
\item Découverte du design pattern "factory" pour les formulaires dynamiques
|
||||
\item Apprentissage de Python, en plus du framework
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\section{Le rôle de mainteneur}
|
||||
|
||||
\subsection{Réviser les merge requests}
|
||||
\begin{frame}[fragile]\frametitle{Réviser les merge requests}
|
||||
\begin{itemize}
|
||||
\item Long et fastidieux
|
||||
\item Nécessaire pour maintenir une base de code cohérente
|
||||
\item Permet de retrouver les bugs des nouveaux contributeurs
|
||||
\item Oriente les contributeurs sur la bonne voie et la marche à suivre avec Django/Jinja2/etc...
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Gestion des bugs, des tickets, de la mise en production...}
|
||||
\begin{frame}[fragile]\frametitle{Gestion des bugs, des tickets, de la mise en production...}
|
||||
\begin{itemize}
|
||||
\item Ouverture/fermeture des tickets
|
||||
\item Mailing list/IRC
|
||||
\item Mise en production, gestion des migrations
|
||||
\item Restauration de la base de tests régulièrement
|
||||
\end{itemize}
|
||||
\par Organisation de la passation
|
||||
\end{frame}
|
||||
|
||||
\section{Conclusion}
|
||||
\begin{frame}[fragile]\frametitle{Conclusion}
|
||||
\begin{itemize}
|
||||
\item Apprentissage Django/Git
|
||||
\item Nouvelle mise en pratique des concepts de base de données relationnelles
|
||||
\item Utilisation poussée de Gitlab
|
||||
\item Formation de nouveaux contributeurs
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
|
||||
\begin{frame}[fragile]
|
||||
\begin{center}
|
||||
\textbf{Merci de votre attention}\\
|
||||
Questions?\\
|
||||
Remarques?\\
|
||||
\end{center}
|
||||
\end{frame}
|
||||
|
||||
\end{document}
|
1
docs/archives/TW_Skia/.gitignore
vendored
1
docs/archives/TW_Skia/.gitignore
vendored
@ -1 +0,0 @@
|
||||
_minted-Rapport
|
@ -1,13 +0,0 @@
|
||||
CC=pdflatex
|
||||
|
||||
all: rapport clean
|
||||
|
||||
rapport: Rapport.tex
|
||||
@echo "Compiling "$<
|
||||
$(CC) -shell-escape $<
|
||||
$(CC) -shell-escape $<
|
||||
|
||||
clean:
|
||||
@echo "Cleaning folder"
|
||||
rm *.aux; rm *.log; rm *.out; rm *.toc; rm *.snm; rm *.nav; rm *.lof
|
||||
|
Binary file not shown.
@ -1,683 +0,0 @@
|
||||
%%
|
||||
%
|
||||
% Skia
|
||||
% skia@libskia.so
|
||||
%
|
||||
%%
|
||||
|
||||
\documentclass[a4paper]{report}
|
||||
|
||||
%packages
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[francais]{babel}
|
||||
\usepackage{graphicx}\graphicspath{{pix/}}
|
||||
\usepackage{float}
|
||||
\usepackage{scrextend}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{color}
|
||||
\usepackage{fancyhdr}
|
||||
%Options: Sonny, Lenny, Glenn, Conny, Rejne, Bjarne, Bjornstrup
|
||||
\usepackage[Bjornstrup]{fncychap}
|
||||
\usepackage{minted}
|
||||
\usepackage[colorlinks=true,linkcolor=black]{hyperref}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage{titlesec, blindtext, color}
|
||||
|
||||
%pdf metadata
|
||||
\hypersetup{
|
||||
unicode=true,
|
||||
colorlinks=true,
|
||||
citecolor=black,
|
||||
filecolor=black,
|
||||
linkcolor=black,
|
||||
urlcolor=black,
|
||||
pdfauthor={Skia <skia@libskia.so>},
|
||||
pdftitle={},
|
||||
pdfcreator={pdftex},
|
||||
pdfsubject={},
|
||||
pdfkeywords={},
|
||||
}
|
||||
|
||||
|
||||
\definecolor{keywords}{RGB}{200,0,90}
|
||||
\definecolor{comments}{RGB}{50,50,253}
|
||||
\definecolor{red}{RGB}{160,0,0}
|
||||
\definecolor{brown}{RGB}{160,100,100}
|
||||
\definecolor{green}{RGB}{0,200,0}
|
||||
\definecolor{darkgreen}{RGB}{0,130,0}
|
||||
\definecolor{gray}{RGB}{100,100,100}
|
||||
|
||||
|
||||
%inner meta
|
||||
\title{Architecture de Sith: le nouveau site AE}
|
||||
\author{Skia (Florent JACQUET)}
|
||||
\date{Dernière version: \today}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\chapter{Introduction}
|
||||
\par Il y a longtemps, au début des années 2000, l'Association des Étudiants a mis en place un site internet qui n'a eu de
|
||||
cesse d'évoluer au fil des ans. Grâce aux différents contributeurs qui s'y sont plongés, et qui ont pu y ajouter leurs
|
||||
bouts de code plus ou moins utiles, le site possède désormais un ensemble de fonctionnalités impressionnant.
|
||||
\par De la comptabilité à la gestion de la laverie, en passant par le forum ou le Matmatronch', le site de l'AE prend
|
||||
actuellement en charge la quasi totalité de la gestion de l'argent, et c'est là un de ses rôles les plus importants.
|
||||
\par Mais les vieilles technologies qu'il emploie, et l'entretien plus ou moins aléatoire qu'il a subit, en font un
|
||||
outil très difficile à maintenir à l'heure actuelle, et le besoin d'une refonte s'imposait de plus en plus.
|
||||
\par Le choix de technologies récentes, maintenues, et éprouvées a donc été fait, et le développement a pu commencer dès
|
||||
Novembre 2015, avec l'objectif d'une mise en production dans l'été 2016, au moins dans une version incluant
|
||||
l'intégralité des fonctions liées à l'argent, qui sont les plus critiques.
|
||||
\par Soutenant les projets libres, j'ai décidé de placer le projet sous licence MIT, assurant ainsi une pérénité aux
|
||||
source. Si quelqu'un dans le futur souhaite le relicencier sous GPL (ou autre licence plus restrictive que la MIT, voire
|
||||
contagieuse), cela reste possible, mais je n'impose au départ que très peu de restrictions \footnote{La seule condition
|
||||
en réalité, est de toujours garder à sa place une copie de la licence originale, à savoir le fichier LICENSE à la racine
|
||||
du site.} .
|
||||
|
||||
\chapter{Les technologies}
|
||||
\label{cha:les_technologies}
|
||||
\par C'est là un des choix les plus important lors d'un tel projet, puisqu'il se fait au début, et qu'il n'est ensuite plus
|
||||
possible de revenir en arrière. Le PHP vieillissant, et
|
||||
piègeux\footnote{\url{https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/}} a donc été mis de côté au profit
|
||||
d'un language plus stable, le \emph{Python} dans sa version 3.
|
||||
|
||||
\section{Python3}
|
||||
\label{sec:python3}
|
||||
\par Le site étant développé en \emph{Python}, il est impératif d'avoir un environnement de développement approprié à ce
|
||||
language. L'outil \verb#virtualenv# permet d'installer un environnement \emph{Python} de manière locale, sans avoir besoin des
|
||||
droits root pour installer des packages. De plus cela permet d'avoir sur sa machine plusieurs environnements différents,
|
||||
adaptés à chaque projet, avec chacun des versions différentes des même paquets.
|
||||
\par La procédure pour installer son \verb#virtualenv# est décrite dans le fichier \verb#README# situé à la racine du
|
||||
projet.
|
||||
|
||||
\section{Django}
|
||||
\label{sec:django}
|
||||
\par \emph{Django} est un framework web pour \emph{Python}, apparu en 2005, et fournissant un grand nombre de
|
||||
fonctionnalités pour développer un site rapidement et simplement. Cela inclut entre autre un serveur Web, pour les
|
||||
échanges HTTP, un parseur d'URL, pour le routage des différentes URI du site, un ORM\footnote{Object-Relational Mapper}
|
||||
pour la gestion de la base de donnée, ou encore un moteur de templates, pour les rendus HTML.
|
||||
\par La version 1.8 de \emph{Django} a été choisie pour le développement de ce projet, car c'est une version LTS (Long Term
|
||||
Support), c'est à dire qu'elle restera stable et maintenue plus longtemps que les autres (au moins jusqu'en Avril 2018).
|
||||
\par La documentation est disponible à cette addresse: \url{https://docs.djangoproject.com/en/1.8/}. Bien que ce rapport
|
||||
présente dans les grandes lignes le fonctionnement de \emph{Django}, il n'est pas et ne se veut pas exhaustif, et la
|
||||
documentation restera donc toujours la référence à ce sujet.
|
||||
|
||||
\subsection{Le fichier de management et l'organisation d'un projet}
|
||||
\label{sub:Le fichier de management et l'organisation d'un projet}
|
||||
|
||||
\par Lors de la création d'un projet \emph{Django}, plusieurs fichiers sont créés. Ces fichiers sont essentiels pour le projet,
|
||||
mais ne contiennent en général pas de code à proprement parler. Ce n'est pas là qu'on y développe quoi que ce soit.
|
||||
|
||||
\subsubsection{manage.py}
|
||||
\label{ssub:manage.py}
|
||||
|
||||
\par Le fichier \verb-manage.py-, situé à la racine, permet de lancer toutes les tâches d'administration du site. Parmis
|
||||
elles:
|
||||
\begin{itemize}
|
||||
\item \textbf{startapp} \\
|
||||
Créer une application.
|
||||
\item \textbf{makemigrations} \\
|
||||
Parser les modèles pour créer les fichiers de migration de la base de donnée.
|
||||
\item \textbf{migrate} \\
|
||||
Appliquer les migrations sur la base de données.
|
||||
\item \textbf{runserver} \\
|
||||
Pour lancer le serveur Web, et donc le site en lui même, dans une version de développement.
|
||||
\item \textbf{makemessages} \\
|
||||
Pour générer les fichiers de traduction, dans le dossier \verb#locale#.
|
||||
\item \textbf{compilemessages} \\
|
||||
Pour compiler les fichiers de traduction, dans le dossier \verb#locale#, et passer de \verb#django.po# à
|
||||
\verb#django.mo#, sa version binaire, optimisée pour l'utilisation.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Un premier dossier}
|
||||
\label{ssub:Un premier dossier}
|
||||
\par Un premier dossier est toujours créé, du nom du projet, et contenant plusieurs fichiers: \verb#settings.py#,
|
||||
\verb#urls.py#, et \verb#wsgi.py#.
|
||||
|
||||
\par \verb#settings.py# est un fichier \emph{Python} servant à définir un grand nombre de constantes paramètrant le
|
||||
fonctionnement du site. L'avantage par rapport à un fichier de configuration classique est que ce dernier est
|
||||
executable, et on peut donc y mettre de la logique, afin d'avoir des paramètres dynamiques.
|
||||
|
||||
\par \verb#urls.py# est le fichier principale contenant les routes du site, c'est à dire les URLs existantes. Il se
|
||||
charge en général d'inclure les fichiers \verb#urls.py# de chaque application afin de garder une architecture modulaire
|
||||
et simple.
|
||||
|
||||
\par \verb#wsgi.py# contient quant à lui les paramètres pour la mise en production du site en tant qu'application WSGI
|
||||
(Web Server Gateway Interface) pour tourner derrière un serveur Web.
|
||||
|
||||
\subsection{Organisation d'une application}
|
||||
\label{sub:organisation_d_une_application}
|
||||
\par Lorsque l'on créer une application avec \verb#./manage.py startapp#, on obtient une fois de plus un dossier type.
|
||||
On trouve dans celui-ci un certain nombre de fichiers:
|
||||
\begin{itemize}
|
||||
\item \textbf{\_\_init\_\_.py} \\
|
||||
Permet de définir le dossier comme un package \emph{Python}. Ce fichier est généralement vide.
|
||||
\item \textbf{models.py} \\
|
||||
C'est là que l'on définit tous les modèles, c'est à dire toutes les classes qui définissent des tables dans la base
|
||||
de donnée.
|
||||
\item \textbf{views.py} \\
|
||||
Les vues y sont définies.
|
||||
\item \textbf{admin.py} \\
|
||||
C'est là que l'on déclare quels modèles doivent apparaîtrent dans l'interface fournie par le module
|
||||
d'administration.
|
||||
\item \textbf{tests.py} \\
|
||||
Ce dernier fichier sert à écrire les tests fonctionnels, unitaires, ou d'intégation à l'aide de la librairie de
|
||||
test de \emph{Django}.
|
||||
\item \textbf{migrations} \\
|
||||
Ce dossier sert à stocker les fichiers de migration de la base de donnée générés par \verb#./manage.py makemigrations#.
|
||||
\end{itemize}
|
||||
\vskip 1em
|
||||
\par On rajoute par la suite généralement plusieurs fichiers:
|
||||
\begin{itemize}
|
||||
\item \textbf{urls.py} \\
|
||||
Pour y définir toutes les URLs de l'application, et ensuite inclure ce fichier dans le fichier \verb#urls.py#
|
||||
global au projet.
|
||||
\item \textbf{templates} \\
|
||||
Celui-ci est un dossier, et on y remet en général un sous dossier du nom de l'application afin de s'en servir de
|
||||
namespace pour les templates.
|
||||
\end{itemize}
|
||||
\vskip 1em
|
||||
\par Dans le cas où un fichier \emph{Python} deviendrait trop gros ou trop complexe, il est toujours possible de le diviser en
|
||||
plusieurs fichiers que l'on met dans un dossier du même nom que ce fichier de départ, et contenant en plus un fichier
|
||||
\verb#__init__.py#. De plus, pour faciliter les imports depuis ce dossier, on peut mettre dans \verb#__init__.py# la
|
||||
ligne\footnote{Un exemple est disponible dans l'application core}:
|
||||
\mint{python}|from .[nom_de_fichier_sans_le_.py] import *|
|
||||
|
||||
\subsection{Les modèles avec l'ORM}
|
||||
\label{sub:les_modèles_avec_l_orm}
|
||||
|
||||
\subsubsection{Le modèle en lui même}
|
||||
\label{ssub:Le modèle en lui même}
|
||||
\par Rien ne vaudra un bon exemple pour comprendre comment sont construits les modèles avec \emph{Django}:
|
||||
\begin{addmargin}[-7em]{0em}
|
||||
\begin{minted}{python}
|
||||
class Club(models.Model): # (1)
|
||||
"""
|
||||
The Club class, made as a tree to allow nice tidy organization
|
||||
""" # (2)
|
||||
name = models.CharField(_('name'), max_length=30) # (3)
|
||||
parent = models.ForeignKey('Club', related_name='children', null=True, blank=True) # (4)
|
||||
unix_name = models.CharField(_('unix name'), max_length=30, unique=True,
|
||||
validators=[ # (5)
|
||||
validators.RegexValidator(
|
||||
r'^[a-z0-9][a-z0-9._-]*[a-z0-9]$',
|
||||
_('Enter a valid unix name. This value may contain only '
|
||||
'letters, numbers ./-/_ characters.')
|
||||
),
|
||||
],
|
||||
error_messages={ # (6)
|
||||
'unique': _("A club with that unix name already exists."),
|
||||
},
|
||||
)
|
||||
address = models.CharField(_('address'), max_length=254)
|
||||
email = models.EmailField(_('email address'), unique=True)
|
||||
owner_group = models.ForeignKey(Group, related_name="owned_club",
|
||||
default=settings.SITH_GROUP_ROOT_ID) # (7)
|
||||
edit_groups = models.ManyToManyField(Group, related_name="editable_club", blank=True) # (8)
|
||||
view_groups = models.ManyToManyField(Group, related_name="viewable_club", blank=True)
|
||||
home = models.OneToOneField(SithFile, related_name='home_of_club', verbose_name=_("home"), null=True, blank=True,
|
||||
on_delete=models.SET_NULL) # (9)
|
||||
\end{minted}
|
||||
\end{addmargin}
|
||||
\par Explications:
|
||||
\begin{description}
|
||||
\item[(1)] Un modèle hérite toujours de \verb#models.Model#. Il peut y avoir des intermédiaires, mais \verb#Model#
|
||||
sera toujours en haut.
|
||||
\item[(2)] Toujours penser à commenter le modèle.
|
||||
\item[(3)] Un premier attribut: \verb#name#, de type \verb#CharField#. Il constitue une colonne dans la base de
|
||||
donnée une fois que \verb#./manage.py migrate# a été appliqué.
|
||||
\item[(4)] Une \verb#ForeignKey#, l'une des relations les plus utilisées. \verb#related_name# précise le nom qui sert
|
||||
de retour vers cette classe depuis la classe pointée. Ici, elle est même récursive, puisque l'on pointe vers la
|
||||
classe que l'on est en train de définir, ce qui donne au final une structure d'arbre.
|
||||
\item[(5)] On peut toujours préciser des \verb#validators#, afin que le modèle soit contraint, et que \emph{Django}
|
||||
maintienne toujours des informations cohérentes dans la base.
|
||||
\item[(6)] Un message d'erreur peut être précisé pour expliciter à l'utilisateur les problèmes rencontrés.
|
||||
\item[(7)] On utilise ici le champ \verb#default# pour préciser une valeur par défaut au modèle, et celui-ci est
|
||||
affecté à une valeur contenue dans les \verb#settings# de \emph{Django}.
|
||||
\item[(8)] Les \verb#ManyToManyField# permettent de générer automatiquement une table intermédiaire de manière
|
||||
transparente afin d'avoir des relations doubles dans les deux classes mises en jeu.
|
||||
\item[(9)] Le \verb#OneToOneField# est très utilisé pour étendre une table avec des informations supplémentaires
|
||||
sans toucher à la table originale.
|
||||
\item[PRIMARY KEY] Les plus observateurs d'entre vous auront remarqué qu'il n'y a pas ici de \verb#PRIMARY KEY# de précisé. En
|
||||
effet, \emph{Django} s'en occupe automatiquement en rajoutant un champ \verb#id# jouant ce rôle. On peut alors y
|
||||
accèder en l'appelant par son nom, \verb#id# la plupart du temps, sauf s'il a été personnalisé, ou bien par
|
||||
l'attribut générique \verb#pk#, toujours présent pour désigner la \verb#PRIMARY KEY# d'un modèle, quelle qu'elle
|
||||
soit.
|
||||
\end{description}
|
||||
|
||||
\subsubsection{Les migrations}
|
||||
\label{ssub:Les migrations}
|
||||
\par Les migrations sont à lancer à chaque fois que l'on modifie un modèle. Elles permettent de conserver la base de
|
||||
donnée tout en la faisant évoluer dans sa structure, pour ajouter ou supprimer une colonne dans une table par exemple.
|
||||
\par Lancer la commande \verb#./manage.py makemigrations [nom de l'appli]# va permettre de générer un fichier \emph{Python}
|
||||
automatiquement, qui sera mis à la suite des précédents, et qui sera appliqué sur la base au moment du lancement de
|
||||
\verb#./manage.py migrate#.
|
||||
|
||||
\subsection{Les vues}
|
||||
\label{sub:les_vues}
|
||||
\par Les vues sont les parties de code s'occupant de l'interface avec l'utilisateur. Elles sont appelées par les URLs,
|
||||
et renvoient des réponses HTTP en fonction du traitement effectué.
|
||||
|
||||
\subsubsection{Les URL}
|
||||
\label{ssub:Les URL}
|
||||
\par Les URLs sont définies par application, et centralisées dans le dossier du projet. Il s'agit à chaque fois d'une
|
||||
liste d'appel à la fonction \verb#url()#, qui comprends toujours une expression rationnelle décrivant l'URL, une
|
||||
fonction passée en tant que callback qui sera appelé au moment où l'URL est résolue, et enfin un nom, permettant de s'y
|
||||
référer dans les fonctions de résolution inverse, comme dans les templates par exemple. Nous détaillerons cette
|
||||
utilisation plus tard.
|
||||
|
||||
\par Pour garder une organisation claire, les URLs sont classées par espaces de noms (namespace) afin d'avoir à éviter
|
||||
de préfixer tous les noms pour s'y retrouver. Le namespace d'une URL est généralement le même nom que celui de
|
||||
l'application dans laquelle elle se trouve.
|
||||
|
||||
\subsubsection{Les fonctions de vue}
|
||||
\label{ssub:Les fonctions de vue}
|
||||
\par Une fonction de vue prend toujours en paramètre une variable \verb#request# et renvoie toujours un objet
|
||||
\verb#HTTPResponse#, contenant un code de retour HTTP, ainsi qu'une chaîne de caractères contenant la réponse en elle
|
||||
même.
|
||||
\par Entre temps, le traitement des informations permet de mettre à jour, de créer, ou de supprimer les objets définis
|
||||
dans les modèles, par le biais des paramètres passé dans la requête. Ainsi, on peut accèder aux informations des
|
||||
variables \verb#GET# et \verb#POST# très facilement en appelant respectivement \verb#request.GET['ma_clef']# et
|
||||
\verb#request.POST['ma_clef']#, ces deux variables fonctionnant comme des dictionnaires.
|
||||
|
||||
\subsubsection{Des vues basées sur des classes}
|
||||
\label{ssub:Des vues basées sur des classes}
|
||||
\par Les vues avec \emph{Django} peuvent aussi être définies comme des classes. Elles héritent alors à ce moment là
|
||||
toutes de la classe \verb#View#, mais ont toutefois souvent beaucoup d'intermédiaires et n'héritent donc pas directement
|
||||
de cette dernière.
|
||||
\par L'avantage de ces vues sous forme de classe est de pouvoir séparer toute la chaîne de traitement entre les
|
||||
différentes méthodes, et ainsi permettre, en jouant avec l'héritage, de fournir alors très peu d'informations à la
|
||||
classe, tout en lui permettant d'effectuer un travail correct.
|
||||
\par Ainsi, on retrouve de base, dans les filles de \verb#View#, un grand nombre de classes prédéfinies pour la plupart
|
||||
des comportement. \verb#DetailView#, \verb#CreateView#, \verb#ListView#, sont quelques exemples de classes renvoyant
|
||||
respectivement un objet en détails, un formulaire pour créer un nouvel objet, et enfin une liste d'objets. Il existe
|
||||
cependant un bon nombre de ces vues fournissant d'autres fonctionnalités, et si malgré tout, aucune ne peut convenir, il
|
||||
reste possible de se baser sur l'une d'elle et surcharger l'une de ses fonctions pour l'adapter à ses besoins.
|
||||
\par L'écosystème des \verb#class-based views# étant toutefois assez complexe et riche, un site web a été créé afin
|
||||
d'offrir un bon résumé de la situation: \emph{Classy class-based views}, accessible à l'adresse
|
||||
\url{http://ccbv.co.uk/}.
|
||||
|
||||
\section{Jinja2}
|
||||
\label{sec:jinja2}
|
||||
\par \emph{Jinja2} est un moteur de template écrit en \emph{Python} qui s'inspire fortement de la syntaxe des templates de
|
||||
\emph{Django}, mais qui apporte toutefois son lot d'améliorations non négligeables. En effet, l'ajout des macros, par
|
||||
exemple, permet de factoriser une grande partie du code.
|
||||
\par Un moteur de template permet de générer du contenu textuel de manière procédural en fonction des données à
|
||||
afficher. Cela permet en pratique de pouvoir inclure du code proche de \emph{Python} dans la syntaxe au milieu d'un
|
||||
document contenant principalement du HTML. Ainsi, si on a une liste d'objets, on peut facilement executer une boucle
|
||||
\verb#for# afin de faire afficher simplement tous les objets selon le même format.
|
||||
\noindent De même, il est facile d'inclure un \verb#if# pour décider à l'execution d'afficher ou non un lien en fonction
|
||||
des droits que l'utilisateur possède sur le site, par exemple.
|
||||
\par En plus des structures conditionnelles classiques, un moteur de templates permet de formater des données plus
|
||||
simplement, comme par exemple des dates, en fonction de la langue actuellement utilisée par l'utilisateur.
|
||||
\par Enfin, bien utilisés, les templates permettent d'utiliser des fonctions d'inclusion, ce qui permet de hiérarchiser
|
||||
les fichiers, et de s'assurer de l'unité de certaines parties du site. Ainsi, les \emph{headers}, les \emph{footers}, et
|
||||
autres menus que l'on retrouve sur toutes les pages du site sont définis chacun dans un seul fichier et inclus dans
|
||||
tous les autres.
|
||||
|
||||
\subsection{Exemple de template Jinja2}
|
||||
\label{sub:exemple_de_template_jinja2}
|
||||
|
||||
\begin{addmargin}[-4em]{0em}
|
||||
\begin{minted}{jinja}
|
||||
{% extends "core/base.jinja" %} {# (1) #}
|
||||
|
||||
{% block title %} {# (2) #}
|
||||
{% trans user_name=user.get_display_name() %}{{ user_name }}'s tools{% endtrans %} {# (3) #}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}User Tools{% endtrans %}</h3> {# (4) #}
|
||||
<p><a href="{{ url('core:user_profile', user_id=request.user.id) }}{# (5) #}">
|
||||
{% trans %}Back to profile{% endtrans %}</a>
|
||||
</p>
|
||||
|
||||
<h4>{% trans %}Sith management{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_root %} {# (6) #}
|
||||
<li><a href="{{ url('core:group_list') }}">{% trans %}Groups{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<li><a href="{{ url('accounting:bank_list') }}">Accounting</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_board_member or user.is_root %}
|
||||
<li><a href="{{ url('subscription:subscription') }}">Subscriptions</a></li>
|
||||
<li><a href="{{ url('counter:admin_list') }}">Counters management</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<h4>{% trans %}Club tools{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% for m in user.memberships.filter(end_date=None).all() %} {# (7) #}
|
||||
<li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
\end{minted}
|
||||
\end{addmargin}
|
||||
|
||||
\begin{description}
|
||||
\item[(1)] Nous faisons ici une extension d'un template existant afin de bénéficier des blocs déjà défini, et afin
|
||||
d'intégrer le contenu de ce template dans celui déjà défini.
|
||||
\item[(2)] \verb#title# est un bloc défini dans le template \verb#base.jinja#. Le redéfinir joue alors le même rôle
|
||||
qu'une surcharge de méthode dans de l'héritage, et permet de remplacer le contenu du bloc, tout en conservant sa
|
||||
place dans le template parent.
|
||||
\item[(3)] La variable \verb#user# faisant ici partie du contexte, nous pouvons donc appeler une de ses méthodes
|
||||
pour obtenir un contenu dynamiquement.
|
||||
\item[(4)] Les blocs \verb#{% trans %}# et \verb#{% endtrans %}# permettent de définir les chaînes qui vont ensuite
|
||||
être traduites.
|
||||
\item[(5)] L'appel à la fonction \verb#url()# permet de résoudre la route afin d'obtenir l'adresse appropriée en
|
||||
fonction des arguments passé. Cette fonction fait généralement partie du contexte global, et est donc accessible
|
||||
dans tous les templates.
|
||||
\item[(6)] Les structures conditionnelles permettent d'afficher ou pas un élément en fonction de la valeur d'une
|
||||
variable ou du retour d'une fonction.
|
||||
\item[(7)] Le \verb#for# permet, comme en Python, d'itérer sur les éléments d'une liste. Ici, on fait même une
|
||||
requête via l'ORM de \emph{Django} en utilisant un filtre pour obtenir directement des valeurs depuis la base de
|
||||
donnée de manière transparente.
|
||||
\end{description}
|
||||
|
||||
\subsection{Le contexte}
|
||||
\label{sub:le_contexte}
|
||||
\par Le contexte dans lequel le template s'execute influe beaucoup sur la capacité de \emph{Jinja} à s'adapter
|
||||
dynamiquement au contenu. Plus on a de variables disponibles, plus on va pouvoir générer un contenu s'y adaptant.
|
||||
\par Il est possible de définir le contexte global, et donc ce qui est accessible dans tous les templates, comme il est
|
||||
possible d'ajouter manuellement et spécifiquement des variables au contexte pour un template particulier, dans une vue
|
||||
particulière.
|
||||
|
||||
\chapter{Organisation du projet}
|
||||
\label{cha:organisation_du_projet}
|
||||
|
||||
\par Après cette présentations des différentes technologies employées dans le projet, passons maintenant à une partie plus
|
||||
spécifique à Sith en lui même.
|
||||
|
||||
\section{Les options spécifiques}
|
||||
\label{sec:les_options_sp_cifiques}
|
||||
|
||||
\subsection{Django-jinja}
|
||||
\label{sub:django_jinja}
|
||||
\par \emph{Jinja} n'étant pas inclus de base dans \emph{Django}, le paquet \emph{Django-jinja} a été mis en place afin
|
||||
de bénéficier au mieux des performances de chacun, comme les filtres personnalisés de \emph{Django} dans la puissance des
|
||||
macros de \emph{Jinja}. Tout cela se trouve dans la variable \verb#TEMPLATES#.
|
||||
\par \emph{Jinja} a été ajouté afin de s'occuper uniquement des fichiers ayant l'extension \verb#.jinja# dans les
|
||||
dossiers \verb#templates# de chaque application.
|
||||
\par Un certain nombre de variables et fonctions ont été ajoutés au contexte global. Parmis elles, l'ensemble des
|
||||
filtres que \emph{Django} fournit, mais aussi un filtre pour passer de \emph{Markdown} à \emph{HTML}, l'ensemble du
|
||||
contenu de \verb#settings#, et enfin des fonction utiles dont voici la liste:
|
||||
\begin{itemize}
|
||||
\item \textbf{can\_edit\_prop} permet, en fonction d'une variable \verb#user# et d'un objet, de savoir si
|
||||
l'utilisateur donnée peut modifier les propriétés de cet objet.
|
||||
\item \textbf{can\_edit} permet, en fonction d'une variable \verb#user# et d'un objet, de savoir si
|
||||
l'utilisateur donnée peut éditer l'objet.
|
||||
\item \textbf{can\_view} permet, en fonction d'une variable \verb#user# et d'un objet, de savoir si
|
||||
l'utilisateur donnée peut voir l'objet.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Le fichier \textbf{settings\_custom.py}}
|
||||
\label{sub:le_fichier_settings_custom.py}
|
||||
\par Afin de faciliter la configuration des différentes instances du projet, un fichier \verb#settings_custom.py# a été
|
||||
créé à côté de \verb#settings.py#. Celui-ci est automatiquement inclu à la fin de \verb#settings.py#, pour que tout ce
|
||||
qui est défini dans le \verb#_custom# vienne remplacer les valeurs par défaut. Seul \verb#settings.py# est versionné
|
||||
dans \emph{Git}, et est exhaustif concernant la configuration et les variables requises. \verb#settings_custom.py# quant
|
||||
à lui n'est même pas obligatoire, et s'il existe, ne peut contenir que quelques variables qui diffèrent de la
|
||||
configuration par défaut\footnote{Typiquement, ajouter \textbf{DEBUG=True} }.
|
||||
|
||||
|
||||
\section{Les commandes ajoutées}
|
||||
\label{sec:les_commandes_ajoutees}
|
||||
\par Si cela ne suffit pas, il est possible d'enrichir de nouvelles commandes le script \verb#manage.py#. Cela a été fait
|
||||
pour \emph{Sith}, afin de pouvoir très rapidement déployer un environnement en ayant déjà les quelques données
|
||||
nécéssaires au fonctionnement du projet, comme le groupe \verb#root# par exemple.
|
||||
|
||||
\subsection{setup}
|
||||
\label{sub:setup}
|
||||
\par La fonction \verb#setup# s'occupe simplement de supprimer le fichier \verb#db.sqlite3#, qui est le fichier de base
|
||||
de donnée utilisé pour le développement, et relance une procédure de migration pour reconstruire une base de donnée
|
||||
propre avant de la peupler.
|
||||
\par Cette commande permet donc de s'assurer que la base de donnée utilisée est neuve et non corrompue.
|
||||
|
||||
\subsection{populate}
|
||||
\label{sub:populate}
|
||||
\par \verb#populate# permet de remplir la base de donnée avec dans un premier temps les données \textbf{nécessaires} au
|
||||
bon fonctionnement du site. Cela comprend notamment un superutilisateur, les groupes définis dans
|
||||
\verb#settings.SITH_GROUP_*_ID#, dont le groupe \verb#root# fait partie, une première page de Wiki, ainsi qu'un club
|
||||
racine, l'AE dans notre cas.
|
||||
\par Cette fonction prend un éventuel argument, \verb#--prod#, qui lui permet de mettre en place le strict minimum
|
||||
énoncé précédemment. Sinon, elle continue en ajoutant un certain nombre de données pratiques pour le développement,
|
||||
comme un certain nombre d'utilisateurs avec différents droits, de nouvelles pages dans le Wiki, de nouveaux clubs, des
|
||||
comptoirs et des produits, ou encore des données de comptabilité.
|
||||
\par L'argument \verb#--prod# peut, en outre, être passé directement depuis la fonction \verb#setup#.
|
||||
|
||||
\chapter{Les applications}
|
||||
\label{cha:les_applications}
|
||||
\par Chaque application va être détaillée ici. Cela permet de mettre en valeur le rôle de chacune, et de signaler les
|
||||
éventuelles particularités qui peuvent s'y trouver.
|
||||
|
||||
\section{Core}
|
||||
\label{sec:core}
|
||||
\subsection{Résumé}
|
||||
\label{sub:resume}
|
||||
\par L'application \emph{Core} est de loin la plus importante de toutes. C'est elle qui gère les utilisateurs ainsi que
|
||||
leurs droits. Le CMS y est aussi définit pour tout ce qui est pages de Wiki, pages statiques, ou l'ajout du filtre
|
||||
\verb#markdown# pour les templates.
|
||||
|
||||
\subsection{Liste des modèles}
|
||||
\label{sub:liste_des_modeles}
|
||||
\begin{itemize}
|
||||
\item \textbf{Group} \\
|
||||
Ce modèle se subdivise en deux: RealGroup et MetaGroup, décrivants respectivement un vrai groupe géré à la main
|
||||
dans la liste des groupes, et un meta-groupe, géré automatiquement, en général par les clubs, ou bien par les
|
||||
cotisations.
|
||||
\item \textbf{User} \\
|
||||
Le modèle des utilisateurs, qui est ensuite décliné ou référencé dans beaucoup d'applications pour les
|
||||
utilisations spécifiques. C'est toutefois ici que sont déclarés les fonctions de gestion des droits des
|
||||
utilisateurs, afin de pouvoir les utiliser partout ailleurs.
|
||||
\item \textbf{AnonymousUser} \\
|
||||
Cette classe n'est pas un modèle stocké en base, puisqu'elle sert à instancier la variable \verb#user#
|
||||
lorsqu'aucun utilisateur n'est connecté au site.
|
||||
\item \textbf{Page} \\
|
||||
Décrit une entité page, servant dans le Wiki ou pour les pages statiques du site. Cette classe s'occupe des
|
||||
méta-données de la page, comme ses droits, mais son contenu est en réalité stocké dans un objet \verb#PageRev#.
|
||||
\item \textbf{PageRev} \\
|
||||
Décrit une révision de page. Utiliser une autre classe avec une \verb#ForeignKey# permet de gérer facilement un
|
||||
historique des révisions.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{La gestion des droits}
|
||||
\label{sub:la_gestion_des_droits}
|
||||
\par La gestion des droits est implémentée de manière globale dans l'application Core.
|
||||
\par On trouve en effet dans \verb#views/__init__.py# un certain nombre de mixins \footnote{Un mixin est, dans
|
||||
\emph{Django}, un terme désignant une classe abstraite qui ne peut pas servir de parente seule. Elle permet de
|
||||
surcharger certaines méthodes d'une autre classe abstraite afin de l'adapter à un comportement plus spécifique, mais
|
||||
reste totalement inutile quand elle est seule. La gestion des droits est un bon exemple puisqu'elle ne s'occupe pas
|
||||
vraiment de traitement des données comme les autres vues le feraient, elle permet simplement d'ajouter une condition à une
|
||||
autre classe où cette dernière renverrait un \emph{403 Forbidden} } s'occupant de cela, en se basant sur
|
||||
un modèle général permettant de rendre compatible rapidement n'importe quel modèle que l'on voudrait protéger. Il suffit
|
||||
alors de déclarer dans la classe une certain nombre de méthodes et/ou d'attributs, le reste étant simplement déjà pris
|
||||
en charge par les mixins suivants:
|
||||
\begin{itemize}
|
||||
\item \textbf{CanCreateMixin} \\
|
||||
Cette classe est à mettre en parente d'une classe héritant de \verb#CreateView#, afin d'empêcher quelqu'un
|
||||
n'ayant pas les droits de créer un objet.\\
|
||||
Méthode correspondante à créer dans les modèles: \\
|
||||
\verb#def can_be_created_by(user):# \\
|
||||
(Attention, ce n'est pas une méthode prenant \verb#self# en premier paramètre!)
|
||||
\item \textbf{CanEditPropMixin} \\
|
||||
Cette classe protège l'objet pour l'édition avancée. Par exemple: éditer les droits sur une page, ou éditer les
|
||||
droits accordé à un utilisateur. \\
|
||||
Attribut correspondant à créer dans les modèles: \\
|
||||
\verb#owner_group = models.ForeignKey(Group, # \\
|
||||
\verb# related_name="owned_user", default=settings.SITH_GROUP_ROOT_ID)# \\
|
||||
Méthode correspondante à créer dans les modèles: \\
|
||||
\verb#def is_owned_by(self, user):# \\
|
||||
\item \textbf{CanEditMixin} \\
|
||||
Cette classe protège l'objet pour l'édition non avancée. Par exemple: éditer une page, ou éditer le profil d'un
|
||||
utilisateur. \\
|
||||
Attribut correspondant à créer dans les modèles: \\
|
||||
\verb#edit_groups = models.ManyToManyField(Group, # \\
|
||||
\verb# related_name="editable_user", blank=True)# \\
|
||||
Méthode correspondante à créer dans les modèles: \\
|
||||
\verb#def can_be_edited_by(self, user):# \\
|
||||
\item \textbf{CanViewMixin} \\
|
||||
Cette classe protège l'objet pour la vue. Par exemple: consulter une page, ou voir le profil d'un utilisateur. \\
|
||||
Attribut correspondant à créer dans les modèles: \\
|
||||
\verb#view_groups = models.ManyToManyField(Group, # \\
|
||||
\verb# related_name="viewable_user", blank=True)# \\
|
||||
Méthode correspondante à créer dans les modèles: \\
|
||||
\verb#def can_be_viewed_by(self, user):# \\
|
||||
\end{itemize}
|
||||
\par Pour savoir si l'on doit implémenter les méthodes, les attributs, ou les deux, il faut simplement se poser la
|
||||
question de savoir si l'objet en question requiert une gestion des droits à l'échelle de la classe ou à l'échelle de
|
||||
l'objet, et si cette gestion peut être calculé par de la logique.
|
||||
\par Si on a besoin d'une gestion pour la classe, ou si du code peut être implémenter pour déterminer qui peut avoir tel
|
||||
droit, alors la méthode suffira. Mais si on a besoin d'une gestion au niveau de l'objet, alors il faudra certainement
|
||||
recourir aux attributs.
|
||||
\par Exemples:
|
||||
\begin{itemize}
|
||||
\item Les comptes en banque sont gérés uniquement par les personnes faisant partie du groupe \verb#admin-compta#.
|
||||
Ils ont donc tous les mêmes droits, c'est une gestion au niveau de la classe, donc les méthodes suffisent.
|
||||
\item Les classeurs de comptabilité sont gérés par les trésoriers des clubs, ils n'ont pas tous les mêmes droits,
|
||||
mais cela peut tout de même se calculer en fonction des postes dans les clubs correspondants. On a donc besoin
|
||||
des méthodes uniquement.
|
||||
\item Les pages n'appartiennent pas forcément à un club, ni à une quelconque entité, mais ont tout de même besoin de
|
||||
gestion des droits au niveau de l'objet. L'ajout des attributs est donc nécessaire pour pouvoir gérer cela au
|
||||
cas par cas.
|
||||
\end{itemize}
|
||||
|
||||
\section{Subscription}
|
||||
\label{sec:subscription}
|
||||
\subsection{Résumé}
|
||||
\label{sub:resume}
|
||||
\par Cette application ajoute le support des cotisations. Elle fournit également les interfaces de cotisation.
|
||||
|
||||
\subsection{Liste des modèles}
|
||||
\label{sub:liste_des_modeles}
|
||||
\begin{itemize}
|
||||
\item \textbf{Subscription} \\
|
||||
Un modèle cotisation, pour stocker ces dernières. Cette classe fait automatiquement les calculs de début et de
|
||||
fin de cotisation en fonction de la date du jour, du type de cotisation, et de la durée en semestre de
|
||||
cotisation.
|
||||
\end{itemize}
|
||||
|
||||
\section{Accounting}
|
||||
\label{sec:accounting}
|
||||
\subsection{Résumé}
|
||||
\label{sub:resume}
|
||||
\par Cette application sert à gérer la comptabilité. Elle est architecturée de façon hiérarchique, avec en haut, les
|
||||
comptes bancaires réels, qui contiennent eux des comptes de clubs, permettant de les diviser en plusieurs petits comptes
|
||||
en interne, et enfin les classeurs de trésorerie, propres à chaque compte club, permettant de faire les comptes en
|
||||
triant par semestre.
|
||||
\par De plus, cette application définit un nouveau type de champ dans la base de donnée: le champ \verb#CurrencyField#,
|
||||
permettant de stocker de valeurs monétaires.
|
||||
|
||||
\subsection{Liste des modèles}
|
||||
\label{sub:liste_des_modeles}
|
||||
\begin{itemize}
|
||||
\item \textbf{BankAccount} \\
|
||||
Le modèle des comptes bancaires.
|
||||
\item \textbf{ClubAccount} \\
|
||||
Le modèle des comptes clubs.
|
||||
\item \textbf{GeneralJournal} \\
|
||||
Le modèle des classeurs de comptabilité, généralement semestriels, mais ils peuvent toutefois fonctionner en
|
||||
année pour les activités plus longues comme le Gala.
|
||||
\item \textbf{AccountingType} \\
|
||||
Le modèle pour stocker les types comptables, servant à remplir les opérations.
|
||||
\item \textbf{SimpleAccountingType} \\
|
||||
Le modèle pour stocker les types comptables simplifiés, servant à remplir les opérations.
|
||||
\item \textbf{Label} \\
|
||||
Le modèle pour stocker les étiquettes, servant à classifer les opérations.
|
||||
\item \textbf{Operation} \\
|
||||
Le modèle des opérations, servant à remplir les classeurs comptables. Une opération peut être un débit ou un
|
||||
crédit, et permet ensuite d'éditer des factures, par exemple.
|
||||
\end{itemize}
|
||||
|
||||
\section{Counter}
|
||||
\label{sec:counter}
|
||||
\subsection{Résumé}
|
||||
\label{sub:resume}
|
||||
\par Cette application s'occupe de la gestion des comptoirs. Elle définit ainsi des produits, et ajoute également le
|
||||
support du compte AE pour les utilisateurs.
|
||||
|
||||
\subsection{Liste des modèles}
|
||||
\label{sub:liste_des_modeles}
|
||||
\begin{itemize}
|
||||
\item \textbf{Customer} \\
|
||||
Ce modèle étend l'utilisateur pour lui rajouter un compte AE. Il est lié à la classe \verb#User# par un
|
||||
\verb#OneToOneField#.
|
||||
\item \textbf{ProductType} \\
|
||||
Ce modèle ajoute des types de produits afin de catégoriser ces derniers.
|
||||
\item \textbf{Product} \\
|
||||
Ce modèle décrit les produits pouvant être vendus dans les différents comptoirs.
|
||||
\item \textbf{Counter} \\
|
||||
Ce modèle décrit les comptoirs, qui permettent de générer des recharges de compte et des ventes de produits.
|
||||
\item \textbf{Refilling} \\
|
||||
Ce modèle permet de stocker les rechargements de compte.
|
||||
\item \textbf{Selling} \\
|
||||
Ce modèle permet d'enregistrer toutes les ventes de produits.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\section{Club}
|
||||
\label{sec:club}
|
||||
\subsection{Résumé}
|
||||
\label{sub:resume}
|
||||
\par Cette application permet de générer les clubs et les adhésions des utilisateurs à ceux-ci.
|
||||
|
||||
\subsection{Liste des modèles}
|
||||
\label{sub:liste_des_modeles}
|
||||
\begin{itemize}
|
||||
\item \textbf{Club} \\
|
||||
Le modèle des clubs.
|
||||
\item \textbf{Membership} \\
|
||||
Le modèle des adhésions. Stocker cela dans un modèle à part permet de conserver un historique des personnes
|
||||
ayant eu un rôle quelconque dans un club quelconque.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
||||
\chapter{Conclusion}
|
||||
\par Encore une fois, ce rapport ne se veut absolument pas exhaustif sur quoi que ce soit.
|
||||
\par Concernant \emph{Python}, \emph{Django}, ou \emph{Jinja}, les documentations respectives sont toujours très bien
|
||||
faites, et permettront de répondre à toutes les questions techniques concernant les technologies.
|
||||
\par Concernant le projet \emph{Sith} en lui-même, ce rapport n'est pas non plus exhaustif. Pour cela, lire le code des
|
||||
différentes sections sera le meilleur moyen de comprendre le fonctionnement des différentes applications. Pour obtenir plus
|
||||
rapidement un résumé à jour des sources, le fichier \verb#Doxyfile# présent à la racine du site permet de regénérer de
|
||||
la documentation exhaustive rapidement à l'aide de \emph{Doxygen} (voir la section correspondante dans le README).
|
||||
\par J'espère toutefois que même s'il n'est pas complet, ce rapport permettra à tout futur contributeur de rentrer plus
|
||||
rapidement dans le projet.
|
||||
\par L'idéal serait également de maintenir à jour ce rapport du mieux possible en même temps que le développement
|
||||
avance, même si je ne me fais guère d'illusions en pratique.
|
||||
|
||||
\section{Pour le futur...}
|
||||
\label{sec:pour_le_futur}
|
||||
\par En l'état actuel des choses, un grand nombre d'éléments sont encore manquants au site:
|
||||
\begin{itemize}
|
||||
\item Une API REST pour pouvoir facilement intégrer d'autres outils autour du site.
|
||||
\item Du CSS, pour qu'il soit un peu plus joli à regarder.
|
||||
\item Du Javascript, et particulièrement de l'AJAX pour améliorer l'ergonomie de certaines pages.
|
||||
\item Un grand nombre de vues pour aider à gérer les données plus efficacement, ou à les gérer tout court dans
|
||||
certains cas.
|
||||
\item Quelques applications utiles à qui existent sur le site actuel, mais que je n'ai pas encore eu le temps de
|
||||
développer: un forum, une galerie de photos, une gestion basique des fichiers pour uploader des documents dans
|
||||
les pages ou le forum, un système de news, une newsletter (Weekmail), une gestion des sondages et des élections,
|
||||
etc...
|
||||
\end{itemize}
|
||||
|
||||
\section{Apports personnels}
|
||||
\label{sec:apports_personnels}
|
||||
\par Même s'il est vrai que j'ai beaucoup appris en développant ce site, cela reste avant tout un travail de quantité
|
||||
plus que de qualité: on définit des modèles, puis les vues correspondantes en terminant par les templates, et on répète
|
||||
l'opération pour l'application suivante.
|
||||
\par Mais j'ai tout de même pu mettre en place de l'intégration continue pour ce projet, ce qui a été certes, très
|
||||
rapide, mais toutefois très enrichissant, étant donnée que ces méthodes sont très en vogue ces derniers temps.
|
||||
\par J'ai également pu me familiariser d'avantage avec le fonctionnement d'un ORM, et la magie noire que cela permet de
|
||||
faire \footnote{Je trouve toujours magique de pouvoir faire une requête SQL au milieu d'un template sans que cela
|
||||
paraisse affreux :)}.
|
||||
\par Enfin, j'espère que ce projet va, en plus d'être correctement mené au bout, pouvoir être repris par la suite par
|
||||
les futurs membres de l'équipe info de l'AE, et pourquoi pas par d'autres contributeurs...
|
||||
\vskip 3em
|
||||
\emph{Skia <skia@libskia.so> - 2016}
|
||||
|
||||
\end{document}
|
||||
|
8
docs/explanation/archives.md
Normal file
8
docs/explanation/archives.md
Normal file
@ -0,0 +1,8 @@
|
||||
!!!note "Page générée"
|
||||
Cette page est générée à partir du wiki GitHub du projet puisqu'elle
|
||||
héberge du contenu binaire lourd qui encombrerait le repo git.
|
||||
La [page originale ici](https://github.com/ae-utbm/sith3/wiki/Archives) peut être plus à jour puisque le contenu
|
||||
de cette page date de la dernière génération de la documentation.
|
||||
|
||||
{! include-markdown 'https://raw.githubusercontent.com/wiki/ae-utbm/sith3/Archives.md', '') !}
|
||||
|
@ -48,6 +48,9 @@ plugins:
|
||||
show_inherited_members: true
|
||||
merge_init_into_class: true
|
||||
show_root_toc_entry: false
|
||||
- include-markdown:
|
||||
opening_tag: "{!"
|
||||
closing_tag: "!}"
|
||||
- search
|
||||
nav:
|
||||
- Accueil: index.md
|
||||
@ -55,6 +58,7 @@ nav:
|
||||
- Accueil: explanation/index.md
|
||||
- Technologies utilisées: explanation/technos.md
|
||||
- Conventions: explanation/conventions.md
|
||||
- Archives: explanation/archives.md
|
||||
- Tutoriels:
|
||||
- Installer le projet: tutorial/install.md
|
||||
- Configurer son éditeur: tutorial/devtools.md
|
||||
|
225
poetry.lock
generated
225
poetry.lock
generated
@ -60,6 +60,28 @@ files = [
|
||||
[package.extras]
|
||||
dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "backports-strenum"
|
||||
version = "1.3.1"
|
||||
description = "Base class for creating enumerated constants that are also subclasses of str"
|
||||
optional = false
|
||||
python-versions = ">=3.8.6,<3.11"
|
||||
files = [
|
||||
{file = "backports_strenum-1.3.1-py3-none-any.whl", hash = "sha256:cdcfe36dc897e2615dc793b7d3097f54d359918fc448754a517e6f23044ccf83"},
|
||||
{file = "backports_strenum-1.3.1.tar.gz", hash = "sha256:77c52407342898497714f0596e86188bb7084f89063226f4ba66863482f42414"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bracex"
|
||||
version = "2.4"
|
||||
description = "Bash style brace expander."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "bracex-2.4-py3-none-any.whl", hash = "sha256:efdc71eff95eaff5e0f8cfebe7d01adf2c8637c8c92edaf63ef348c241a82418"},
|
||||
{file = "bracex-2.4.tar.gz", hash = "sha256:a27eaf1df42cf561fed58b7a8f3fdf129d1ea16a81e1fadd1d17989bc6384beb"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.7.4"
|
||||
@ -283,63 +305,63 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.5.4"
|
||||
version = "7.6.0"
|
||||
description = "Code coverage measurement for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"},
|
||||
{file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"},
|
||||
{file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"},
|
||||
{file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"},
|
||||
{file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"},
|
||||
{file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"},
|
||||
{file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"},
|
||||
{file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"},
|
||||
{file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"},
|
||||
{file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"},
|
||||
{file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"},
|
||||
{file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"},
|
||||
{file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"},
|
||||
{file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"},
|
||||
{file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -639,13 +661,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
|
||||
{file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
|
||||
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
|
||||
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -714,16 +736,17 @@ dev = ["flake8", "markdown", "twine", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "griffe"
|
||||
version = "0.47.0"
|
||||
version = "0.48.0"
|
||||
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "griffe-0.47.0-py3-none-any.whl", hash = "sha256:07a2fd6a8c3d21d0bbb0decf701d62042ccc8a576645c7f8799fe1f10de2b2de"},
|
||||
{file = "griffe-0.47.0.tar.gz", hash = "sha256:95119a440a3c932b13293538bdbc405bee4c36428547553dc6b327e7e7d35e5a"},
|
||||
{file = "griffe-0.48.0-py3-none-any.whl", hash = "sha256:f944c6ff7bd31cf76f264adcd6ab8f3d00a2f972ae5cc8db2d7b6dcffeff65a2"},
|
||||
{file = "griffe-0.48.0.tar.gz", hash = "sha256:f099461c02f016b6be4af386d5aa92b01fb4efe6c1c2c360dda9a5d0a863bb7f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
backports-strenum = {version = ">=1.3", markers = "python_version < \"3.11\""}
|
||||
colorama = ">=0.4"
|
||||
|
||||
[[package]]
|
||||
@ -1043,15 +1066,33 @@ mergedeep = ">=1.3.4"
|
||||
platformdirs = ">=2.2.0"
|
||||
pyyaml = ">=5.1"
|
||||
|
||||
[[package]]
|
||||
name = "mkdocs-include-markdown-plugin"
|
||||
version = "6.2.1"
|
||||
description = "Mkdocs Markdown includer plugin."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "mkdocs_include_markdown_plugin-6.2.1-py3-none-any.whl", hash = "sha256:8dfc3aee9435679b094cbdff023239e91d86cf357c40b0e99c28036449661830"},
|
||||
{file = "mkdocs_include_markdown_plugin-6.2.1.tar.gz", hash = "sha256:46fc372886d48eec541d36138d1fe1db42afd08b976ef7c8d8d4ea6ee4d5d1e8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mkdocs = ">=1.4"
|
||||
wcmatch = ">=8,<9"
|
||||
|
||||
[package.extras]
|
||||
cache = ["platformdirs"]
|
||||
|
||||
[[package]]
|
||||
name = "mkdocs-material"
|
||||
version = "9.5.28"
|
||||
version = "9.5.29"
|
||||
description = "Documentation that simply works"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "mkdocs_material-9.5.28-py3-none-any.whl", hash = "sha256:ff48b11b2a9f705dd210409ec3b418ab443dd36d96915bcba45a41f10ea27bfd"},
|
||||
{file = "mkdocs_material-9.5.28.tar.gz", hash = "sha256:9cba305283ad1600e3d0a67abe72d7a058b54793b47be39930911a588fe0336b"},
|
||||
{file = "mkdocs_material-9.5.29-py3-none-any.whl", hash = "sha256:afc1f508e2662ded95f0a35a329e8a5acd73ee88ca07ba73836eb6fcdae5d8b4"},
|
||||
{file = "mkdocs_material-9.5.29.tar.gz", hash = "sha256:3e977598ec15a4ddad5c4dfc9e08edab6023edb51e88f0729bd27be77e3d322a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1802,29 +1843,29 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.5.1-py3-none-linux_armv6l.whl", hash = "sha256:6ecf968fcf94d942d42b700af18ede94b07521bd188aaf2cd7bc898dd8cb63b6"},
|
||||
{file = "ruff-0.5.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:204fb0a472f00f2e6280a7c8c7c066e11e20e23a37557d63045bf27a616ba61c"},
|
||||
{file = "ruff-0.5.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d235968460e8758d1e1297e1de59a38d94102f60cafb4d5382033c324404ee9d"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38beace10b8d5f9b6bdc91619310af6d63dd2019f3fb2d17a2da26360d7962fa"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e478d2f09cf06add143cf8c4540ef77b6599191e0c50ed976582f06e588c994"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0368d765eec8247b8550251c49ebb20554cc4e812f383ff9f5bf0d5d94190b0"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3a9a9a1b582e37669b0138b7c1d9d60b9edac880b80eb2baba6d0e566bdeca4d"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd9f723e16003623423affabcc0a807a66552ee6a29f90eddad87a40c750b78"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9fd62c1e99539da05fcdc1e90d20f74aec1b7a1613463ed77870057cd6bd96"},
|
||||
{file = "ruff-0.5.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e216fc75a80ea1fbd96af94a6233d90190d5b65cc3d5dfacf2bd48c3e067d3e1"},
|
||||
{file = "ruff-0.5.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c4c2112e9883a40967827d5c24803525145e7dab315497fae149764979ac7929"},
|
||||
{file = "ruff-0.5.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dfaf11c8a116394da3b65cd4b36de30d8552fa45b8119b9ef5ca6638ab964fa3"},
|
||||
{file = "ruff-0.5.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d7ceb9b2fe700ee09a0c6b192c5ef03c56eb82a0514218d8ff700f6ade004108"},
|
||||
{file = "ruff-0.5.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bac6288e82f6296f82ed5285f597713acb2a6ae26618ffc6b429c597b392535c"},
|
||||
{file = "ruff-0.5.1-py3-none-win32.whl", hash = "sha256:5c441d9c24ec09e1cb190a04535c5379b36b73c4bc20aa180c54812c27d1cca4"},
|
||||
{file = "ruff-0.5.1-py3-none-win_amd64.whl", hash = "sha256:b1789bf2cd3d1b5a7d38397cac1398ddf3ad7f73f4de01b1e913e2abc7dfc51d"},
|
||||
{file = "ruff-0.5.1-py3-none-win_arm64.whl", hash = "sha256:2875b7596a740cbbd492f32d24be73e545a4ce0a3daf51e4f4e609962bfd3cd2"},
|
||||
{file = "ruff-0.5.1.tar.gz", hash = "sha256:3164488aebd89b1745b47fd00604fb4358d774465f20d1fcd907f9c0fc1b0655"},
|
||||
{file = "ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be"},
|
||||
{file = "ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1"},
|
||||
{file = "ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132"},
|
||||
{file = "ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649"},
|
||||
{file = "ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60"},
|
||||
{file = "ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846"},
|
||||
{file = "ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060"},
|
||||
{file = "ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335"},
|
||||
{file = "ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718"},
|
||||
{file = "ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084"},
|
||||
{file = "ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583"},
|
||||
{file = "ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2026,13 +2067,13 @@ test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "sqlparse"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
description = "A non-validating SQL parser."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"},
|
||||
{file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"},
|
||||
{file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"},
|
||||
{file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -2187,6 +2228,20 @@ files = [
|
||||
[package.extras]
|
||||
watchmedo = ["PyYAML (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcmatch"
|
||||
version = "8.5.2"
|
||||
description = "Wildcard/glob file name matcher."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "wcmatch-8.5.2-py3-none-any.whl", hash = "sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478"},
|
||||
{file = "wcmatch-8.5.2.tar.gz", hash = "sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
bracex = ">=2.1.1"
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.13"
|
||||
@ -2216,4 +2271,4 @@ filelock = ">=3.4"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "d6d524c293fe2560487d9b9e6287f0d4a369294ba30be0de4a3ff092844b9a4e"
|
||||
content-hash = "9038b84fac4dc7ce5aea0520d29e4d5705e2e55f3e165d2455ebc61eafe6cfe0"
|
||||
|
@ -73,6 +73,7 @@ mkdocs = "^1.6.0"
|
||||
mkdocs-material = "^9.5.28"
|
||||
mkdocstrings = "^0.25.1"
|
||||
mkdocstrings-python = "^1.10.5"
|
||||
mkdocs-include-markdown-plugin = "^6.2.1"
|
||||
|
||||
[tool.poetry.group.docs]
|
||||
optional = true
|
||||
|
Loading…
Reference in New Issue
Block a user