Rapport.tex 40.7 KB
Newer Older
Skia's avatar
Skia committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
%%
%
% Skia
% skia@libskia.so
%
%%

\documentclass[a4paper]{report}

%packages
\usepackage[utf8]{inputenc}
\usepackage[francais]{babel}
\usepackage{graphicx}\graphicspath{{pix/}}
\usepackage{float}
Skia's avatar
Skia committed
15
\usepackage{scrextend}
Skia's avatar
Skia committed
16
17
18
19
20
\usepackage[T1]{fontenc}
\usepackage{color}
\usepackage{fancyhdr}
%Options: Sonny, Lenny, Glenn, Conny, Rejne, Bjarne, Bjornstrup
\usepackage[Bjornstrup]{fncychap}
Skia's avatar
Skia committed
21
\usepackage{minted}
Skia's avatar
Skia committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
\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}
Skia's avatar
Skia committed
43
\definecolor{comments}{RGB}{50,50,253}
Skia's avatar
Skia committed
44
\definecolor{red}{RGB}{160,0,0}
Skia's avatar
Skia committed
45
46
47
48
\definecolor{brown}{RGB}{160,100,100}
\definecolor{green}{RGB}{0,200,0}
\definecolor{darkgreen}{RGB}{0,130,0}
\definecolor{gray}{RGB}{100,100,100}
Skia's avatar
Skia committed
49
50
51
52
53


%inner meta
\title{Architecture de Sith: le nouveau site AE}
\author{Skia (Florent JACQUET)}
Skia's avatar
Skia committed
54
\date{Dernière version: \today}
Skia's avatar
Skia committed
55
56
57

\begin{document}

Skia's avatar
Skia committed
58
59
\maketitle

Skia's avatar
Skia committed
60
61
\tableofcontents

Skia's avatar
Skia committed
62
\chapter{Introduction}
Skia's avatar
Skia committed
63
\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
Skia's avatar
Skia committed
64
65
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
fonctionnalités plus ou moins utiles, le site possède désormais un ensemble de fonctionnalité impressionnant.
Skia's avatar
Skia committed
66
\par De la comptabilité à la gestion de la laverie, en passant par le forum ou le Matmatronch', le site de l'AE prend
Skia's avatar
Skia committed
67
actuellement en charge la quasi totalité de la gestion de l'argent, et c'est là un de ces rôles les plus importants.
Skia's avatar
Skia committed
68
\par Mais les vieilles technologies qu'il emploie, et le maintient plus ou moins aléatoire, en font un outil très difficile à
Skia's avatar
Skia committed
69
maintenir à l'heure actuelle, et le besoin d'une refonte s'imposait de plus en plus.
Skia's avatar
Skia committed
70
\par Le choix de technologies récentes, maintenues, et éprouvée a donc été fait, et le développement a pu commencer dès
Skia's avatar
Skia committed
71
72
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.
Skia's avatar
Skia committed
73
74
75
76
\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, 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.} .
Skia's avatar
Skia committed
77
78
79

\chapter{Les technologies}
\label{cha:les_technologies}
Skia's avatar
Skia committed
80
\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
Skia's avatar
Skia committed
81
82
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
Skia's avatar
Skia committed
83
d'un language plus stable, le \emph{Python} dans sa version 3.
Skia's avatar
Skia committed
84

Skia's avatar
Skia committed
85
86
\section{Python3}
\label{sec:python3}
Skia's avatar
Skia committed
87
88
\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
Skia's avatar
Skia committed
89
90
91
92
93
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.

Skia's avatar
Skia committed
94
95
\section{Django}
\label{sec:django}
Skia's avatar
Skia committed
96
\par \emph{Django}  est un framework web pour \emph{Python}, apparu en 2005, et fournissant un grand nombre de fonctionnalités pour
Skia's avatar
Skia committed
97
développer un site rapidement et simplement. Cela inclut entre autre un serveur Web, pour les échanges HTTP, un parseur
Skia's avatar
Skia committed
98
d'URL, pour le routage des différentes URI du site, un ORM\footnote{Object-Relational Mapper} pour la gestion de la base
Skia's avatar
Skia committed
99
de donnée, ou encore un moteur de template, pour les rendus HTML.
Skia's avatar
Skia committed
100
\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
Skia's avatar
Skia committed
101
102
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
Skia's avatar
Skia committed
103
présente dans les grandes lignes le fonctionnement de \emph{Django}, il n'est pas et ne se veut pas exhaustif, et la
Skia's avatar
Skia committed
104
105
106
107
108
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}

Skia's avatar
Skia committed
109
\par Lors de la création d'un projet \emph{Django}, plusieurs fichiers sont créés. Ces fichiers sont essentiels pour le projet,
Skia's avatar
Skia committed
110
111
112
113
114
115
116
117
118
119
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
Skia's avatar
Skia committed
120
    \item \textbf{makemigrations} \\
Skia's avatar
Skia committed
121
122
123
124
125
126
127
128
129
130
131
132
        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
\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#.

Skia's avatar
Skia committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
\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à qu'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 ou unitaires à 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 *|
Skia's avatar
Skia committed
180
181
182
183
184
185

\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}
Skia's avatar
Skia committed
186
\par Rien ne vaudra un bon exemple pour comprendre comment sont construits les modèles avec \emph{Django}:
Skia's avatar
Skia committed
187
\begin{addmargin}[-7em]{0em}
Skia's avatar
Skia committed
188
    \begin{minted}{python}
Skia's avatar
Skia committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
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_GROUPS['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)
Skia's avatar
Skia committed
213
\end{minted}
Skia's avatar
Skia committed
214
215
216
217
218
219
220
221
222
223
\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ée. \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
Skia's avatar
Skia committed
224
225
        classe que l'on est en train de définir, ce qui donne au final une structure d'arbre.)r
    \item[(5)] On peut toujours préciser des \verb#validators#, afin que le modèle soit contraint, et que \emph{Django}
Skia's avatar
Skia committed
226
227
228
        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
Skia's avatar
Skia committed
229
        affecté à une valeur contenue dans les \verb#settings# de \emph{Django}.
Skia's avatar
Skia committed
230
231
232
233
234
    \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[OneToOneField] Il n'est pas présent dans ce modèle, mais 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
Skia's avatar
Skia committed
235
        effet, \emph{Django} s'en occupe automatiquement en rajoutant un champ \verb#id# jouant ce rôle. On peut alors y
Skia's avatar
Skia committed
236
237
238
239
        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}
Skia's avatar
Skia committed
240
241
242

\subsubsection{Les migrations}
\label{ssub:Les migrations}
Skia's avatar
Skia committed
243
244
\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.
Skia's avatar
Skia committed
245
\par Lancer la commande \verb#./manage.py makemigrations [nom de l'appli]# va permettre de générer un fichier \emph{Python}
Skia's avatar
Skia committed
246
247
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#.
Skia's avatar
Skia committed
248
249
250

\subsection{Les vues}
\label{sub:les_vues}
Skia's avatar
Skia committed
251
252
\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é.
Skia's avatar
Skia committed
253
254
255

\subsubsection{Les URL}
\label{ssub:Les URL}
Skia's avatar
Skia committed
256
257
258
259
260
261
262
263
264
\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 fonctiones 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.
Skia's avatar
Skia committed
265
266
267

\subsubsection{Les fonctions de vue}
\label{ssub:Les fonctions de vue}
Skia's avatar
Skia committed
268
269
270
271
272
273
274
\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.
Skia's avatar
Skia committed
275
276
277

\subsubsection{Des vues basées sur des classes}
\label{ssub:Des vues basées sur des classes}
Skia's avatar
Skia committed
278
279
280
281
282
283
284
285
286
287
288
289
290
291
\par Les vues en \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édiaire 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 affichant
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/}.
Skia's avatar
Skia committed
292
293
294

\section{Jinja2}
\label{sec:jinja2}
Skia's avatar
Skia committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
\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 sont lot d'améliorations non négligeable. 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'objet, 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 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}

Skia's avatar
Skia committed
314
\begin{addmargin}[-4em]{0em}
Skia's avatar
Skia committed
315
    \begin{minted}{jinja}
Skia's avatar
Skia committed
316
{% extends "core/base.jinja" %} {# (1) #}
Skia's avatar
Skia committed
317

Skia's avatar
Skia committed
318
319
{% block title %} {# (2) #}
    {{ user.get_display_name() }}'s tools {# (3) #}
Skia's avatar
Skia committed
320
321
322
323
{% endblock %}

{% block content %}
<h3>User Tools</h3>
Skia's avatar
Skia committed
324
325
326
<p><a href="{{ url('core:user_profile', user_id=request.user.id) }}{# (4) #}">
    Back to profile</a>
</p>
Skia's avatar
Skia committed
327
328
329

<h4>Sith management</h4>
<ul>
Skia's avatar
Skia committed
330
{% if user.is_in_group(settings.SITH_GROUPS['root']['name']) %} {# (5) #}
Skia's avatar
Skia committed
331
332
333
334
335
    <li><a href="{{ url('core:group_list') }}">Groups</a></li>
{% endif %}
{% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) %}
    <li><a href="{{ url('accounting:bank_list') }}">Accounting</a></li>
{% endif %}
Skia's avatar
Skia committed
336
337
{% if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or
    user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
Skia's avatar
Skia committed
338
339
340
341
342
343
    <li><a href="{{ url('subscription:subscription') }}">Subscriptions</a></li>
    <li><a href="{{ url('counter:admin_list') }}">Counters management</a></li>
{% endif %}
</ul>
<h4>Clubs</h4>
<ul>
Skia's avatar
Skia committed
344
    {% for m in user.membership.filter(end_date=None).all() %} {# (6) #}
Skia's avatar
Skia committed
345
346
347
348
349
350
351
    <li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
    {% endfor %}
</ul>
{% endblock %}
    \end{minted}
\end{addmargin}

Skia's avatar
Skia committed
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
\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)] 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[(5)] 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[(6)] 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}
Skia's avatar
Skia committed
369

Skia's avatar
Skia committed
370
371
372
373
374
375
376
\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.
Skia's avatar
Skia committed
377
378
379
380

\chapter{Organisation du projet}
\label{cha:organisation_du_projet}

Skia's avatar
Skia committed
381
382
383
384
385
386
387
388
389
390
391
392
393
\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.
Skia's avatar
Skia committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
\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.
    \item \textbf{get\_subscriber} permet à partir d'un utilisateur d'obtenir son équivalent en objet \verb#subscriber#,
        afin de vérifier l'état de sa cotisation.
\end{itemize}

\subsection{Liste des variables définies dans \textbf{settings.py}}
\label{sub:liste_des_variables_d_finies_dans_settings.py}
\begin{itemize}
    \item \textbf{SITH\_MAIN\_CLUB} \\
        Définit le club principal, en général propriétaire du site. Les membres du bureau de ce club auront accès à la
        plupart des outils d'administration, droits que les autres clubs ne confèrent pas. Dans notre cas, c'est bien
        évidemment l'AE elle même qui est définit ici.
    \item \textbf{SITH\_START\_DATE} \\
        Définit la date de début du semestre. Plusieurs fonctions se basent dessus, notamment pour remettre à jour
        certains compteurs semestriel, ou pour les dates de début de certains types de cotisation comme la cotisation au
        cursus.
    \item \textbf{SITH\_GROUPS} \\
        Définit les groupes nécessaires au fonctionnement du site, comme le groupe \verb#root#, les groupes
        administrateurs de certains outils spécifiques comme la comptabilité, ou le groupe \verb#public#.
    \item \textbf{SITH\_BOARD\_SUFFIX} \\
        Définit le suffixe appliqué à chaque nom de club pour constituer le groupe des membres du bureau de ce club.
    \item \textbf{SITH\_MEMBER\_SUFFIX} \\
        Définit le suffixe appliqué à chaque nom de club pour constituer le groupe des membres de ce club.
    \item \textbf{SITH\_MAIN\_BOARD\_GROUP} \\
        Définit le nom du groupe constituant le bureau de l'association principale, pour éviter de le recalculer à
        chaque fois. Il est définit en fonction des précédentes variable et ne devrait jamais être affecté à la main.
    \item \textbf{SITH\_MAIN\_MEMBERS\_GROUP} \\
        Définit le nom du groupe constituant les membres de l'association principale, pour éviter de le recalculer à
        chaque fois. Il est définit en fonction des précédentes variable et ne devrait jamais être affecté à la main.
    \item \textbf{SITH\_ACCOUNTING\_PAYMENT\_METHOD} \\
        Définit les méthodes de paiement pour la comptabilité.
    \item \textbf{SITH\_SUBSCRIPTION\_PAYMENT\_METHOD} \\
        Définit les méthodes de paiement pour les cotisations.
    \item \textbf{SITH\_COUNTER\_PAYMENT\_METHOD} \\
        Définit les méthodes de paiement pour les comptoirs.
    \item \textbf{SITH\_SUBSCRIPTIONS} \\
        Définit les différentes cotisations possibles.
    \item \textbf{SITH\_CLUB\_ROLES} \\
        Définit les différentes postes possibles dans les clubs, ainsi que leur hiérarchie.
    \item \textbf{SITH\_MAXIMUM\_FREE\_ROLE} \\
        Définit jusqu'à quel rôle un utilisateur lambda peut s'ajouter seul dans un club sans requérir de droits
        particuliers. Cela permet par exemple de s'ajouter à des mailings lists.
    \item \textbf{SITH\_BARMAN\_TIMEOUT} \\
        Définit au bout de combien de minutes d'inactivité les barmans sont déconnectés d'un comptoir.
\end{itemize}

Skia's avatar
Skia committed
449
450
451

\section{Les commandes ajoutées}
\label{sec:les_commandes_ajout_es}
Skia's avatar
Skia committed
452
453
454
\par Si cela ne suffit, 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.
Skia's avatar
Skia committed
455
456
457

\subsection{setup}
\label{sub:setup}
Skia's avatar
Skia committed
458
459
460
461
\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.
Skia's avatar
Skia committed
462

Skia's avatar
Skia committed
463
464
\subsection{populate}
\label{sub:populate}
Skia's avatar
Skia committed
465
466
467
468
469
470
471
472
\par \verb#populate# permet de remplir la base de donnée avec dans un premier temps les données \textbf{nécéssaires} au
bon fonctionnement du site. Cela comprend un superutilisateur, les groupes définis dans \verb#settings.SITH_GROUPS#,
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, ainsi que des données de comptabilité.
\par L'argument \verb#--prod# peut, en outre, être passé directement depuis la fonction \verb#setup#.
Skia's avatar
Skia committed
473
474
475

\chapter{Les applications}
\label{cha:les_applications}
Skia's avatar
Skia committed
476
477
\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.
Skia's avatar
Skia committed
478
479
480

\section{Core}
\label{sec:core}
Skia's avatar
Skia committed
481
482
483
484
485
\subsection{Résumé}
\label{sub:r_sum_}
\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.
Skia's avatar
Skia committed
486

Skia's avatar
Skia committed
487
488
\subsection{Liste des modèles}
\label{sub:liste_des_mod_les}
Skia's avatar
Skia committed
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
\begin{itemize}
    \item \textbf{Group} \\
        Ce modèle se subdivise en deux: RealGroup et MetaGroup, décrivant 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, en
\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 ferait, 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_GROUPS['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{CanEditPropMixin} \\
        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 banques sont gérés uniquement par les personnes faisant partie du groupe \verb#admin-compta#.
        Ils ont donc tous les même 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ême 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}
Skia's avatar
Skia committed
569
570
571

\section{Subscription}
\label{sec:subscription}
Skia's avatar
Skia committed
572
573
\subsection{Résumé}
\label{sub:r_sum_}
Skia's avatar
Skia committed
574
575
\par Cette application étend le modèle \verb#User# pour y ajouter le support des cotisations. Elle fournit également les
interfaces de cotisation.
Skia's avatar
Skia committed
576
577
578

\subsection{Liste des modèles}
\label{sub:liste_des_mod_les}
Skia's avatar
Skia committed
579
580
581
582
583
584
585
586
587
\begin{itemize}
    \item \textbf{Subscriber} \\
        Un modèle proxy de \verb#User# fournissant les méthodes pour rapidement savoir si l'utilisateur est cotisant ou
        non.
    \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}
Skia's avatar
Skia committed
588
589
590

\section{Accounting}
\label{sec:accounting}
Skia's avatar
Skia committed
591
592
\subsection{Résumé}
\label{sub:r_sum_}
Skia's avatar
Skia committed
593
594
595
596
597
598
\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.
Skia's avatar
Skia committed
599
600
601

\subsection{Liste des modèles}
\label{sub:liste_des_mod_les}
Skia's avatar
Skia committed
602
603
604
605
606
607
608
609
610
611
612
613
614
615
\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{Operation} \\
        Le modèle des opérations, servant à remplir les classeurs comptables. Un opération peut être un débit ou un
        crédit, et permet ensuite d'éditer des factures, par exemple.
\end{itemize}
Skia's avatar
Skia committed
616
617
618

\section{Counter}
\label{sec:counter}
Skia's avatar
Skia committed
619
620
\subsection{Résumé}
\label{sub:r_sum_}
Skia's avatar
Skia committed
621
622
\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.
Skia's avatar
Skia committed
623
624
625

\subsection{Liste des modèles}
\label{sub:liste_des_mod_les}
Skia's avatar
Skia committed
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
\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}
Skia's avatar
Skia committed
641

Skia's avatar
Skia committed
642
643
644

\section{Club}
\label{sec:club}
Skia's avatar
Skia committed
645
646
\subsection{Résumé}
\label{sub:r_sum_}
Skia's avatar
Skia committed
647
\par Cette application permet de générer les clubs et les adhésions des utilisateur à ceux-ci.
Skia's avatar
Skia committed
648
649
650

\subsection{Liste des modèles}
\label{sub:liste_des_mod_les}
Skia's avatar
Skia committed
651
652
653
654
655
656
657
658
659
\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}


Skia's avatar
Skia committed
660

Skia's avatar
Skia committed
661
662
663
664
665
666
667
668
669
670
671
672
\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 fonctions. 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.
Skia's avatar
Skia committed
673

Skia's avatar
Skia committed
674
675
676
677
678
679
680
681
682
683
684
685
686
687
\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}
Skia's avatar
Skia committed
688

Skia's avatar
Skia committed
689
690
691
692
693
694
695
696
697
698
699
700
701
702
\section{Apports personnels}
\label{sec:apports_personnels}
\par Même s'il est vrai que j'ai beaucoup appris en développement 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'autre contributeurs...
\vskip 3em
\emph{Skia <skia@libskia.so> - 2016}
Skia's avatar
Skia committed
703
704
705

\end{document}