mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-26 11:04:20 +00:00
Merge branch 'documentation' into 'master'
write a new shiny and comprehensive documentation See merge request ae/Sith!224
This commit is contained in:
commit
7be9077fce
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ sith/settings_custom.py
|
|||||||
sith/search_indexes/
|
sith/search_indexes/
|
||||||
.coverage
|
.coverage
|
||||||
coverage_report/
|
coverage_report/
|
||||||
|
doc/_build
|
||||||
|
@ -15,6 +15,8 @@ test:
|
|||||||
- coverage run ./manage.py test
|
- coverage run ./manage.py test
|
||||||
- coverage html
|
- coverage html
|
||||||
- coverage report
|
- coverage report
|
||||||
|
- cd doc
|
||||||
|
- make html # Make documentation
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- coverage_report/
|
- coverage_report/
|
||||||
|
18
.readthedocs.yml
Normal file
18
.readthedocs.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Build documentation in the doc/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: doc/conf.py
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF and ePub
|
||||||
|
formats: all
|
||||||
|
|
||||||
|
# Optionally set the version of Python and requirements required to build your docs
|
||||||
|
python:
|
||||||
|
version: 3.6
|
||||||
|
install:
|
||||||
|
- requirements: requirements.txt
|
106
CONTRIBUTING.md
106
CONTRIBUTING.md
@ -1,106 +0,0 @@
|
|||||||
*Contribuer c'est la vie*
|
|
||||||
=========================
|
|
||||||
|
|
||||||
Hey ! Tu veux devenir un mec bien et en plus devenir bon en python si tu l'es pas déjà ?
|
|
||||||
Il se trouve que le sith AE prévu pour l'été 2016 a besoin de toi !
|
|
||||||
|
|
||||||
Pour faire le sith, on utilise le framework Web [Django](https://docs.djangoproject.com/fr/1.11/intro/)
|
|
||||||
N'hésite pas à lire les tutos et à nous demander (ae.info@utbm.fr).
|
|
||||||
|
|
||||||
Bon, passons aux choses sérieuses, pour bidouiller le sith sans le casser :
|
|
||||||
Ben en fait, tu peux pas le casser, tu vas juste t'amuser comme un petit fou sur un clone du sith.
|
|
||||||
|
|
||||||
C'est pas compliqué, il suffit d'avoir [Git](http://www.git-scm.com/book/fr/v2), python et pip (pour faciliter la gestion des paquets python).
|
|
||||||
|
|
||||||
Tout d'abord, tu vas avoir besoin d'un compte Gitlab pour pouvoir te connecter.
|
|
||||||
Ensuite, tu fais :
|
|
||||||
`git clone https://ae-dev.utbm.fr/ae/Sith.git`
|
|
||||||
Avec cette commande, tu clones le sith AE dans le dossier courant.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd Sith
|
|
||||||
virtualenv --system-site-packages --python=python3 env
|
|
||||||
source env/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
./manage runserver
|
|
||||||
```
|
|
||||||
|
|
||||||
Attention aux dépendances système, à voir dans le README.md
|
|
||||||
|
|
||||||
Maintenant, faut passer le sith en mode debug dans le fichier de settings personnalisé.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
echo "DEBUG=True" > sith/settings_custom.py
|
|
||||||
echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Enfin, il s'agit de créer la base de donnée de test lors de la première utilisation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./manage.py setup
|
|
||||||
```
|
|
||||||
|
|
||||||
Et pour lancer le sith, tu fais `python3 manage.py runserver`
|
|
||||||
|
|
||||||
Voilà, c'est le sith AE. Il y a des issues dans le gitlab qui sont à régler. Si tu as un domaine qui t'intéresse, une appli que tu voudrais développer, n'hésites pas et contacte-nous.
|
|
||||||
Va, et que l'AE soit avec toi.
|
|
||||||
|
|
||||||
# Black
|
|
||||||
|
|
||||||
Pour uniformiser le formattage du code nous utilisons [Black](https://github.com/ambv/black). Cela permet d'avoir le même codestyle et donc le codereview prend moins de temps. Tout étant dans le même format, il est plus facile pour chacun de comprendre le code de chacun ! Cela permet aussi d'éviter des erreurs (y parait 🤷♀️).
|
|
||||||
|
|
||||||
Installation de black:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install black
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sous VsCode:
|
|
||||||
Attention, pour VsCode, Black doit être installé dans votre virtualenv !
|
|
||||||
Ajouter ces deux lignes dans les settings de VsCode
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"python.formatting.provider": "black",
|
|
||||||
"editor.formatOnSave": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sous Sublime Text
|
|
||||||
Il faut installer le plugin [sublack](https://packagecontrol.io/packages/sublack) depuis Package Control.
|
|
||||||
|
|
||||||
Il suffit ensuite d'ajouter dans les settings du projet (ou en global)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"sublack.black_on_save": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Si vous utilisez le plugin [anaconda](http://damnwidget.github.io/anaconda/), pensez à modifier les paramètres du linter pep8 pour éviter de recevoir des warnings dans le formatage de black
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"pep8_ignore": [
|
|
||||||
"E203",
|
|
||||||
"E266",
|
|
||||||
"E501",
|
|
||||||
"W503"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Sites et doc cools
|
|
||||||
------------------
|
|
||||||
|
|
||||||
[Classy Class-Based Views](http://ccbv.co.uk/projects/Django/1.11/)
|
|
||||||
|
|
||||||
Helpers:
|
|
||||||
|
|
||||||
`./manage.py makemessages --ignore "env/*" -e py,jinja`
|
|
||||||
|
|
||||||
`for f in $(find . -name "*.py" ! -path "*migration*" ! -path "./env/*" ! -path "./doc/*"); do cat ./doc/header "$f" > /tmp/temp && mv /tmp/temp "$f"; done`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
CONTRIBUTING.rst
Normal file
3
CONTRIBUTING.rst
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Pour contribuer au projet, vous pouvez vous référer à la documentation disponible à https://sith-ae.readthedocs.io/.
|
||||||
|
|
||||||
|
Et n'oubliez pas, contribuer c'est la vie !
|
104
README.md
104
README.md
@ -1,104 +0,0 @@
|
|||||||
[![pipeline status](https://ae-dev.utbm.fr/ae/Sith/badges/master/pipeline.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
|
||||||
[![coverage report](https://ae-dev.utbm.fr/ae/Sith/badges/master/coverage.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
|
||||||
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
|
|
||||||
[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://ae-dev.zulipchat.com)
|
|
||||||
|
|
||||||
## Sith AE
|
|
||||||
|
|
||||||
### Dependencies:
|
|
||||||
See requirements.txt
|
|
||||||
|
|
||||||
You may need to install some dev libraries like `libmysqlclient-dev`, `libssl-dev`, `libjpeg-dev`, `python3-xapian`, or `zlib1g-dev` to install all the
|
|
||||||
requiered dependancies with pip. You may also need `mysql-client`. Don't also forget `python3-dev` if you don't have it
|
|
||||||
already.
|
|
||||||
|
|
||||||
You can check all of them with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt install libmysqlclient-dev libssl-dev libjpeg-dev zlib1g-dev python3-dev libffi-dev python3-dev libgraphviz-dev pkg-config python3-xapian gettext
|
|
||||||
```
|
|
||||||
|
|
||||||
On macos, you will need homebrew
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install xapian
|
|
||||||
```
|
|
||||||
|
|
||||||
If it doesn't work it's because it need [this pull request](https://github.com/Homebrew/homebrew-core/pull/34835) to be validated.
|
|
||||||
|
|
||||||
The development is done with sqlite, but it is advised to set a more robust DBMS for production (Postgresql for example)
|
|
||||||
|
|
||||||
### Get started
|
|
||||||
|
|
||||||
To start working on the project, just run the following commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://ae-dev.utbm.fr/ae/Sith.git
|
|
||||||
cd Sith
|
|
||||||
virtualenv --system-site-packages --python=python3 env
|
|
||||||
source env/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
./manage.py setup
|
|
||||||
```
|
|
||||||
|
|
||||||
To start the simple development server, just run `python3 manage.py runserver`
|
|
||||||
|
|
||||||
For more informations, check out the CONTRIBUTING.md file.
|
|
||||||
|
|
||||||
### Logging errors with sentry
|
|
||||||
|
|
||||||
To connect the app to sentry.io, you must set the variable SENTRY_DSN in your settings custom. It's composed of the full link given on your sentry project
|
|
||||||
|
|
||||||
### Generating documentation
|
|
||||||
|
|
||||||
There is a Doxyfile at the root of the project, meaning that if you have Doxygen, you can run `doxygen Doxyfile` to
|
|
||||||
generate a complete HTML documentation that will be available in the *./doc/html/* folder.
|
|
||||||
|
|
||||||
### Collecting statics for production:
|
|
||||||
|
|
||||||
We use scss in the project. In development environment (DEBUG=True), scss is compiled every time the file is needed. For production, it assumes you have already compiled every files and to do so, you need to use the following commands :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./manage.py collectstatic # To collect statics
|
|
||||||
./manage.py compilestatic # To compile scss in those statics
|
|
||||||
```
|
|
||||||
|
|
||||||
### Misc about development
|
|
||||||
|
|
||||||
#### Controlling the rights
|
|
||||||
|
|
||||||
When you need to protect an object, there are three levels:
|
|
||||||
* Editing the object properties
|
|
||||||
* Editing the object various values
|
|
||||||
* Viewing the object
|
|
||||||
|
|
||||||
Now you have many solutions in your model:
|
|
||||||
* You can define a `is_owned_by(self, user)`, a `can_be_edited_by(self, user)`, and/or a `can_be_viewed_by(self, user)`
|
|
||||||
method, each returning True is the user passed can edit/view the object, False otherwise.
|
|
||||||
This allows you to make complex request when the group solution is not powerful enough.
|
|
||||||
It's useful too when you want to define class-wide permissions, e.g. the club members, that are viewable only for
|
|
||||||
Subscribers.
|
|
||||||
* You can add an `owner_group` field, as a ForeignKey to Group. Second is an `edit_groups` field, as a ManyToMany to
|
|
||||||
Group, and third is a `view_groups`, same as for edit.
|
|
||||||
|
|
||||||
Finally, when building a class based view, which is highly advised, you just have to inherit it from CanEditPropMixin,
|
|
||||||
CanEditMixin, or CanViewMixin, which are located in core.views. Your view will then be protected using either the
|
|
||||||
appropriate group fields, or the right method to check user permissions.
|
|
||||||
|
|
||||||
#### Counting the number of line of code
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt install cloc
|
|
||||||
cloc --exclude-dir=doc,env .
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Updating doc/SYNTAX.md
|
|
||||||
|
|
||||||
If you make an update in the Markdown syntax parser, it's good to document
|
|
||||||
update the syntax reference page in `doc/SYNTAX.md`. But updating this file will
|
|
||||||
break the tests if you don't update the corresponding `doc/SYNTAX.html` file at
|
|
||||||
the same time.
|
|
||||||
To do that, simply run `./manage.py markdown > doc/SYNTAX.html`,
|
|
||||||
and the tests should pass again.
|
|
||||||
|
|
||||||
|
|
37
README.rst
Normal file
37
README.rst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
.. image:: https://ae-dev.utbm.fr/ae/Sith/badges/master/pipeline.svg
|
||||||
|
:target: https://ae-dev.utbm.fr/ae/Sith/commits/master
|
||||||
|
:alt: pipeline status
|
||||||
|
|
||||||
|
.. image:: https://readthedocs.org/projects/sith-ae/badge/?version=latest
|
||||||
|
:target: https://sith-ae.readthedocs.io/?badge=latest
|
||||||
|
:alt: documentation Status
|
||||||
|
|
||||||
|
.. image:: https://ae-dev.utbm.fr/ae/Sith/badges/master/coverage.svg
|
||||||
|
:target: https://ae-dev.utbm.fr/ae/Sith/commits/master
|
||||||
|
:alt: coverage report
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||||
|
:target: https://github.com/ambv/black
|
||||||
|
:alt: code style: black
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/zulip-join_chat-brightgreen.svg
|
||||||
|
:target: https://ae-dev.zulipchat.com
|
||||||
|
:alt: project chat
|
||||||
|
|
||||||
|
This is the source code of the UTBM's student association available at https://ae.utbm.fr/.
|
||||||
|
|
||||||
|
All documentation is in the ``docs`` directory and online at https://sith-ae.readthedocs.io/. This documentation is written in French because it targets a French audience and it's too much work to maintain two versions. The code and code comments are strictly written in English.
|
||||||
|
|
||||||
|
If you want to contribute, here's how we recommend to read the docs:
|
||||||
|
|
||||||
|
* First, it's advised to read the about part of the project to understand the goals and the mindset of the current and previous maintainers and know what to expect to learn.
|
||||||
|
* If in the first part you find you need more background about what we use, we provide some links to tutorials and documentation at the end of our documentation. Feel free to use it and complete it with what you found helpful.
|
||||||
|
* Keep in mind that this documentation is thought to be read in order.
|
||||||
|
|
||||||
|
To join our team :
|
||||||
|
|
||||||
|
* Send a mail at mailto:ae.utbm.fr
|
||||||
|
* Join our group chat at https://ae-dev.zulipchat.com
|
||||||
|
* See and join our Trello at https://trello.com/b/YQOaF33m/site-ae.
|
||||||
|
|
||||||
|
This project is licenced under GNU GPL, see the LICENSE file at the top of the repository for more details.
|
9
TODO.md
9
TODO.md
@ -1,9 +0,0 @@
|
|||||||
# TODO
|
|
||||||
|
|
||||||
## Easter eggs
|
|
||||||
|
|
||||||
* 'A' 'L' 'L' 'O': Entendre le Allooo de Madame Coucoune
|
|
||||||
* idem avec cacafe
|
|
||||||
* Un meat spin quelque part
|
|
||||||
* Konami code
|
|
||||||
|
|
@ -149,6 +149,13 @@ class NewsDate(models.Model):
|
|||||||
class Weekmail(models.Model):
|
class Weekmail(models.Model):
|
||||||
"""
|
"""
|
||||||
The weekmail class
|
The weekmail class
|
||||||
|
|
||||||
|
:ivar title: Title of the weekmail
|
||||||
|
:ivar intro: Introduction of the weekmail
|
||||||
|
:ivar joke: Joke of the week
|
||||||
|
:ivar protip: Tip of the week
|
||||||
|
:ivar conclusion: Conclusion of the weekmail
|
||||||
|
:ivar sent: Track if the weekmail has been sent
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = models.CharField(_("title"), max_length=64, blank=True)
|
title = models.CharField(_("title"), max_length=64, blank=True)
|
||||||
@ -162,6 +169,10 @@ class Weekmail(models.Model):
|
|||||||
ordering = ["-id"]
|
ordering = ["-id"]
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
|
"""
|
||||||
|
Send the weekmail to all users with the receive weekmail option opt-in.
|
||||||
|
Also send the weekmail to the mailing list in settings.SITH_COM_EMAIL.
|
||||||
|
"""
|
||||||
dest = [
|
dest = [
|
||||||
i[0]
|
i[0]
|
||||||
for i in Preferences.objects.filter(receive_weekmail=True).values_list(
|
for i in Preferences.objects.filter(receive_weekmail=True).values_list(
|
||||||
@ -183,19 +194,31 @@ class Weekmail(models.Model):
|
|||||||
Weekmail().save()
|
Weekmail().save()
|
||||||
|
|
||||||
def render_text(self):
|
def render_text(self):
|
||||||
|
"""
|
||||||
|
Renders a pure text version of the mail for readers without HTML support.
|
||||||
|
"""
|
||||||
return render(
|
return render(
|
||||||
None, "com/weekmail_renderer_text.jinja", context={"weekmail": self}
|
None, "com/weekmail_renderer_text.jinja", context={"weekmail": self}
|
||||||
).content.decode("utf-8")
|
).content.decode("utf-8")
|
||||||
|
|
||||||
def render_html(self):
|
def render_html(self):
|
||||||
|
"""
|
||||||
|
Renders an HTML version of the mail with images and fancy CSS.
|
||||||
|
"""
|
||||||
return render(
|
return render(
|
||||||
None, "com/weekmail_renderer_html.jinja", context={"weekmail": self}
|
None, "com/weekmail_renderer_html.jinja", context={"weekmail": self}
|
||||||
).content.decode("utf-8")
|
).content.decode("utf-8")
|
||||||
|
|
||||||
def get_banner(self):
|
def get_banner(self):
|
||||||
|
"""
|
||||||
|
Return an absolute link to the banner.
|
||||||
|
"""
|
||||||
return "http://" + settings.SITH_URL + static("com/img/weekmail_bannerA19.jpg")
|
return "http://" + settings.SITH_URL + static("com/img/weekmail_bannerA19.jpg")
|
||||||
|
|
||||||
def get_footer(self):
|
def get_footer(self):
|
||||||
|
"""
|
||||||
|
Return an absolute link to the footer.
|
||||||
|
"""
|
||||||
return "http://" + settings.SITH_URL + static("com/img/weekmail_footerA19.jpg")
|
return "http://" + settings.SITH_URL + static("com/img/weekmail_footerA19.jpg")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
44
core/management/commands/compilemessages.py
Normal file
44
core/management/commands/compilemessages.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*
|
||||||
|
#
|
||||||
|
# Copyright 2019
|
||||||
|
# - Sli <antoine@bartuccio.fr>
|
||||||
|
#
|
||||||
|
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
||||||
|
# http://ae.utbm.fr.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License a published by the Free Software
|
||||||
|
# Foundation; either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
||||||
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
from django.core.management.commands import compilemessages
|
||||||
|
|
||||||
|
|
||||||
|
class Command(compilemessages.Command):
|
||||||
|
"""
|
||||||
|
Wrap call to compilemessages to avoid building whole env
|
||||||
|
"""
|
||||||
|
|
||||||
|
help = """
|
||||||
|
The usage is the same as the real compilemessages
|
||||||
|
but it goes into the sith dir first
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
os.chdir("sith")
|
||||||
|
super(Command, self).handle(*args, **options)
|
71
core/management/commands/documentation.py
Normal file
71
core/management/commands/documentation.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*
|
||||||
|
#
|
||||||
|
# Copyright 2019
|
||||||
|
# - Sli <antoine@bartuccio.fr>
|
||||||
|
#
|
||||||
|
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
||||||
|
# http://ae.utbm.fr.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License a published by the Free Software
|
||||||
|
# Foundation; either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
||||||
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from http.server import test, CGIHTTPRequestHandler
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
# TODO Django 2.2 : implement autoreload following
|
||||||
|
# https://stackoverflow.com/questions/42907285/django-autoreload-add-watched-file
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Generate Sphinx documentation and launch basic server"
|
||||||
|
|
||||||
|
default_addr = "127.0.0.1"
|
||||||
|
default_port = "8080"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"addrport", nargs="?", help="Optional port number, or ipaddr:port"
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
os.chdir("doc")
|
||||||
|
err = os.system("make html")
|
||||||
|
|
||||||
|
if err != 0:
|
||||||
|
self.stdout.write("A build error occured, exiting")
|
||||||
|
sys.exit(err)
|
||||||
|
|
||||||
|
os.chdir("_build/html")
|
||||||
|
addr = self.default_addr
|
||||||
|
port = self.default_port
|
||||||
|
if kwargs["addrport"]:
|
||||||
|
addrport = kwargs["addrport"].split(":")
|
||||||
|
|
||||||
|
addr = addrport[0]
|
||||||
|
|
||||||
|
if len(addrport) > 1:
|
||||||
|
port = addrport[1]
|
||||||
|
|
||||||
|
if not port.isnumeric():
|
||||||
|
self.stdout.write("%s is not a valid port" % (port,))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
test(HandlerClass=CGIHTTPRequestHandler, port=int(port), bind=addr)
|
@ -377,13 +377,6 @@ Welcome to the wiki page!
|
|||||||
|
|
||||||
""",
|
""",
|
||||||
).save()
|
).save()
|
||||||
# Adding README
|
|
||||||
p = Page(name="README")
|
|
||||||
p.save(force_lock=True)
|
|
||||||
p.view_groups = [settings.SITH_GROUP_PUBLIC_ID]
|
|
||||||
p.save(force_lock=True)
|
|
||||||
with open(os.path.join(root_path) + "/README.md", "r") as rm:
|
|
||||||
PageRev(page=p, title="README", author=skia, content=rm.read()).save()
|
|
||||||
|
|
||||||
# Subscription
|
# Subscription
|
||||||
default_subscription = "un-semestre"
|
default_subscription = "un-semestre"
|
||||||
|
@ -81,18 +81,60 @@ def internal_servor_error(request):
|
|||||||
|
|
||||||
|
|
||||||
def can_edit_prop(obj, user):
|
def can_edit_prop(obj, user):
|
||||||
|
"""
|
||||||
|
:param obj: Object to test for permission
|
||||||
|
:param user: core.models.User to test permissions against
|
||||||
|
:return: if user is authorized to edit object properties
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
:Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if not can_edit_prop(self.object ,request.user):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
"""
|
||||||
if obj is None or user.is_owner(obj):
|
if obj is None or user.is_owner(obj):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def can_edit(obj, user):
|
def can_edit(obj, user):
|
||||||
|
"""
|
||||||
|
:param obj: Object to test for permission
|
||||||
|
:param user: core.models.User to test permissions against
|
||||||
|
:return: if user is authorized to edit object
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
:Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if not can_edit(self.object ,request.user):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
"""
|
||||||
if obj is None or user.can_edit(obj):
|
if obj is None or user.can_edit(obj):
|
||||||
return True
|
return True
|
||||||
return can_edit_prop(obj, user)
|
return can_edit_prop(obj, user)
|
||||||
|
|
||||||
|
|
||||||
def can_view(obj, user):
|
def can_view(obj, user):
|
||||||
|
"""
|
||||||
|
:param obj: Object to test for permission
|
||||||
|
:param user: core.models.User to test permissions against
|
||||||
|
:return: if user is authorized to see object
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
:Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
if not can_view(self.object ,request.user):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
"""
|
||||||
if obj is None or user.can_view(obj):
|
if obj is None or user.can_view(obj):
|
||||||
return True
|
return True
|
||||||
return can_edit(obj, user)
|
return can_edit(obj, user)
|
||||||
@ -102,6 +144,8 @@ class CanCreateMixin(View):
|
|||||||
"""
|
"""
|
||||||
This view is made to protect any child view that would create an object, and thus, that can not be protected by any
|
This view is made to protect any child view that would create an object, and thus, that can not be protected by any
|
||||||
of the following mixin
|
of the following mixin
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *arg, **kwargs):
|
def dispatch(self, request, *arg, **kwargs):
|
||||||
@ -123,6 +167,8 @@ class CanEditPropMixin(View):
|
|||||||
to only the owner group of the given object.
|
to only the owner group of the given object.
|
||||||
In other word, you can make a view with this view as parent, and it would be retricted to the users that are in the
|
In other word, you can make a view with this view as parent, and it would be retricted to the users that are in the
|
||||||
object's owner_group
|
object's owner_group
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *arg, **kwargs):
|
def dispatch(self, request, *arg, **kwargs):
|
||||||
@ -150,6 +196,8 @@ class CanEditMixin(View):
|
|||||||
"""
|
"""
|
||||||
This view makes exactly the same thing as its direct parent, but checks the group on the edit_groups field of the
|
This view makes exactly the same thing as its direct parent, but checks the group on the edit_groups field of the
|
||||||
object
|
object
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *arg, **kwargs):
|
def dispatch(self, request, *arg, **kwargs):
|
||||||
@ -177,6 +225,8 @@ class CanViewMixin(View):
|
|||||||
"""
|
"""
|
||||||
This view still makes exactly the same thing as its direct parent, but checks the group on the view_groups field of
|
This view still makes exactly the same thing as its direct parent, but checks the group on the view_groups field of
|
||||||
the object
|
the object
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *arg, **kwargs):
|
def dispatch(self, request, *arg, **kwargs):
|
||||||
@ -206,6 +256,8 @@ class CanViewMixin(View):
|
|||||||
class FormerSubscriberMixin(View):
|
class FormerSubscriberMixin(View):
|
||||||
"""
|
"""
|
||||||
This view check if the user was at least an old subscriber
|
This view check if the user was at least an old subscriber
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
@ -217,6 +269,8 @@ class FormerSubscriberMixin(View):
|
|||||||
class UserIsLoggedMixin(View):
|
class UserIsLoggedMixin(View):
|
||||||
"""
|
"""
|
||||||
This view check if the user is logged
|
This view check if the user is logged
|
||||||
|
|
||||||
|
:raises: PermissionDenied
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
20
doc/Makefile
Normal file
20
doc/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
1
doc/TO_Skia_LoJ/.gitignore
vendored
1
doc/TO_Skia_LoJ/.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
Rapport.pdf
|
|
||||||
_minted-Rapport/
|
_minted-Rapport/
|
||||||
|
2
doc/TW_Skia/.gitignore
vendored
2
doc/TW_Skia/.gitignore
vendored
@ -1 +1 @@
|
|||||||
Rapport.pdf
|
_minted-Rapport
|
BIN
doc/TW_Skia/Rapport.pdf
Normal file
BIN
doc/TW_Skia/Rapport.pdf
Normal file
Binary file not shown.
29
doc/about/introduction.rst
Normal file
29
doc/about/introduction.rst
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
Le but de ce projet est de fournir à l'Association des Étudiants de l'UTBM une plate-forme pratique et centralisée de ses services. Le Sith de l'AE tient à jour le registre des cotisations à l'association, prend en charge la trésorerie, les ventes de produits et services, la diffusion d’événements, la gestion de la laverie et bien plus encore. Il est conçu de manière suffisamment générique pour être facilement adaptable à une autre association.
|
||||||
|
|
||||||
|
C'est un projet bénévole qui tire ses origines des années 2000. Il s'agit de la troisième version du site de l'association initiée en 2015. C'est une réécriture complète en rupture totale des deux versions qui l'ont précédée.
|
||||||
|
|
||||||
|
Pourquoi réécrire le site
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
L'ancienne version du site, sobrement baptisée `ae2 <https://ae-dev.utbm.fr/ae/ae2>`_ présentait un nombre impressionnant de fonctionnalités. Il avait été écrit en PHP et se basait sur son propre framework maison.
|
||||||
|
|
||||||
|
Malheureusement, son entretiens était plus ou moins hasardeux et son framework reposait sur des principes assez différents de ce qui se fait aujourd'hui, rendant la maintenance difficile. De plus, la version de PHP qu'il utilisait était plus que déprécié et à l'heure de l'arrivée de PHP 7 et de sa non rétrocompatibilité il était vital de faire quelque chose. Il a donc été décidé de le réécrire.
|
||||||
|
|
||||||
|
La philosophie du projet
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Pour éviter les erreurs du passé, ce projet met l'accent sur la maintenabilité. Le choix des technologies ne s'est donc pas fait uniquement sur le fait qu'elle soit récentes, mais également sur leur robustesse, leur fiabilité et leur potentiel à être maintenu loin dans le futur.
|
||||||
|
|
||||||
|
La maintenabilité passe également par le choix minutieux des dépendances qui doivent eux aussi passer l'épreuve du temps pour éviter qu'elles ne mettent le projet en danger.
|
||||||
|
|
||||||
|
Cela passe également par la minimisation des frameworks employés de manière à réduire un maximum les connaissances nécessaires pour contribuer au projet et donc simplifier la prise en main. La simplicité est à privilégier si elle est possible.
|
||||||
|
|
||||||
|
Le projet doit être simple à installer et à déployer.
|
||||||
|
|
||||||
|
Le projet étant à destination d'étudiants, il est préférable de minimiser les ressources utilisées par l'utilisateur final. Il faut qu'il soit au maximum économe en bande passante et calcul côté client.
|
||||||
|
|
||||||
|
|
||||||
|
Le projet est un logiciel libre et est sous licence GPL. Aucune dépendance propriétaire ne sera acceptée.
|
177
doc/about/tech.rst
Normal file
177
doc/about/tech.rst
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
Technologies utilisées
|
||||||
|
======================
|
||||||
|
|
||||||
|
Bien choisir ses technologies est crucial puisqu'une fois que le projet est suffisamment avancé, il est très difficile voir impossible de revenir en arrière.
|
||||||
|
|
||||||
|
En novembre 2015, plusieurs choix s'offraient à nous :
|
||||||
|
|
||||||
|
* Continuer avec du PHP
|
||||||
|
* S'orienter vers un langage web plus moderne et à la mode comme le Python ou le Ruby
|
||||||
|
* Baser le site sur un framework Javascript
|
||||||
|
|
||||||
|
Le PHP 5, bientôt 7, de l'époque étant assez discutable comme `cet article <https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/>`__ et l'ancien site ayant laissé un goût amer à certains développeurs, celui-ci a été mis de côté.
|
||||||
|
|
||||||
|
L'écosystème Javascript étant à peine naissant et les frameworks allant et venant en seulement quelques mois, il était impossible de prédire avec certitude si ceux-ci passeraient l'épreuve du temps, il était inconcevable de tout parier là dessus.
|
||||||
|
|
||||||
|
Ne restait plus que le Python et le Ruby avec les frameworks Django et Ruby On Rails. Ruby ayant une réputation d'être très "cutting edge", c'est Python, un langage bien implanté et ayant fait ses preuves, qui a été retenu.
|
||||||
|
|
||||||
|
Backend
|
||||||
|
-------
|
||||||
|
|
||||||
|
Python 3
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://www.python.org/>`__
|
||||||
|
|
||||||
|
Le python est un langage de programmation interprété multi paradigme sorti en 1991. Il est très populaire pour sa simplicité d'utilisation, sa puissance, sa stabilité, sécurité ainsi que sa grande communauté de développeur. Sa version 3, non rétro compatible avec sa version 2, a été publiée en 2008.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Puisque toutes les dépendances du backend sont des packages Python, elles sont toutes ajoutées directement dans le fichier **requirements.txt** à la racine du projet.
|
||||||
|
|
||||||
|
Django
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
| `Site officiel <https://www.djangoproject.com/>`__
|
||||||
|
| `Documentation <https://docs.djangoproject.com/en/1.11/>`__
|
||||||
|
|
||||||
|
Django est un framework web pour Python apparu en 2005. Il fourni un grand nombre de fonctionnalités pour développer un site rapidement et simplement. Cela inclu entre autre un serveur Web de développement, un parseur d'URLs pour le routage des différentes URI du site, un ORM (Object-Relational Mapper) pour la gestion de la base de donnée ainsi qu'un moteur de templates pour le rendu HTML. Django propose une version LTS (Long Term Support) qui reste stable et est maintenu sur des cycles plus longs, ce sont ces versions qui sont utilisées.
|
||||||
|
|
||||||
|
PostgreSQL / SQLite
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
| `Site officiel PostgreSQL <https://www.postgresql.org/>`__
|
||||||
|
| `Site officiel SQLite <https://www.sqlite.org/index.html>`__
|
||||||
|
|
||||||
|
Comme la majorité des sites internet, le Sith de l'AE enregistre ses données dans une base de donnée. Nous utilisons une base de donnée relationnelle puisque c'est la manière typique d'utiliser Django et c'est ce qu'utilise son ORM. Dans la pratique il arrive rarement dans le projet de se soucier de ce qui fonctionne derrière puisque le framework abstrait les requêtes au travers de son ORM. Cependant, il arrive parfois que certaines requêtes, lorsqu'on cherche à les optimiser, ne fonctionnent que sur un seul backend.
|
||||||
|
|
||||||
|
Le principal à retenir ici est :
|
||||||
|
|
||||||
|
* Sur la version de production nous utilisons PostgreSQL, c'est cette version qui doit fonctionner en priorité
|
||||||
|
* Sur les versions de développement, pour faciliter l'installation du projet, nous utilisons la technologie SQLite qui ne requiert aucune installation spécifique. Certaines instructions ne sont pas supportées par cette technologie et il est parfois nécessaire d'installer PostgreSQL pour le développement de certaines parties du site.
|
||||||
|
|
||||||
|
Frontend
|
||||||
|
--------
|
||||||
|
|
||||||
|
Jinja2
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://jinja.palletsprojects.com/en/2.10.x/>`__
|
||||||
|
|
||||||
|
Jinja2 est un moteur de template écrit en Python qui s'inspire fortement de la syntaxe des templates de Django. Ce moteur apporte toutefois son lot d'améliorations non négligeables. Il permet par exemple l'ajout de macros, sortes de fonctions écrivant du HTML.
|
||||||
|
|
||||||
|
Un moteur de templates permet de générer du contenu textuel de manière procédural en fonction des données à afficher, cela permet de pouvoir inclure du code proche du Python dans la syntaxe au milieu d'un document contenant principalement du HTML. On peut facilement faire des boucles ou des conditions ainsi même que de l'héritage de templates.
|
||||||
|
|
||||||
|
Attention : le rendu est fait côté serveur, si on souhaite faire des modifications côté client, il faut utiliser du Javascript, rien ne change à ce niveau là.
|
||||||
|
|
||||||
|
Exemple d'utilisation d'un template Jinja2
|
||||||
|
|
||||||
|
.. sourcecode:: html+jinja
|
||||||
|
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
<ul>
|
||||||
|
{% for user in users %}
|
||||||
|
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
jQuery
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://jquery.com/>`__
|
||||||
|
|
||||||
|
jQuery est une bibliothèque JavaScript libre et multiplateforme créée pour faciliter l'écriture de scripts côté client dans le code HTML des pages web. La première version est lancée en janvier 2006 par John Resig.
|
||||||
|
|
||||||
|
C'est une vieille technologie et certains feront remarquer à juste titre que le Javascript moderne permet d'utiliser assez simplement la majorité de ce que fourni jQuery sans rien avoir à installer. Cependant, de nombreuses dépendances du projet utilisent encore jQuery qui est toujours très implanté aujourd'hui. Le sucre syntaxique qu'offre cette libraire reste très agréable à utiliser et économise parfois beaucoup de temps. Ça fonctionne et ça fonctionne très bien. C'est maintenu, léger et pratique, il n'y a pas de raison particulière de s'en séparer.
|
||||||
|
|
||||||
|
Sass
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://sass-lang.com/>`__
|
||||||
|
|
||||||
|
Sass (Syntactically Awesome Stylesheets) est un langage dynamique de génération de feuilles CSS apparu en 2006. C'est un langage de CSS "amélioré" qui permet l'ajout de variables (à une époque où le CSS ne les supportait pas), de fonctions, mixins ainsi qu'une syntaxe pour imbriquer plus facilement et proprement les règles sur certains éléments. Le Sass est traduit en CSS directement côté serveur et le client ne reçoit que du CSS.
|
||||||
|
|
||||||
|
C'est une technologie stable, mature et pratique qui ne nécessite pas énormément d'apprentissage.
|
||||||
|
|
||||||
|
Fontawesome
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://fontawesome.com>`__
|
||||||
|
|
||||||
|
Fontawesome regroupe tout un ensemble d'icônes libres de droits utilisables facilement sur n'importe quelle page web. Ils sont simple à modifier puisque modifiables via le CSS et présentent l'avantage de fonctionner sur tous les navigateurs contrairement à un simple icône unicode qui s'affiche lui différemment selon la plate-forme.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
C'est une dépendance capricieuse qu'il évolue très vite et qu'il faut très souvent mettre à jour.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Il a été décidé de **ne pas utiliser** de CDN puisque le site ralentissait régulièrement. Il est préférable de fournir cette dépendance avec le site.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Sphinx
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://www.sphinx-doc.org/en/master/>`__
|
||||||
|
|
||||||
|
Sphinx est un outil qui permet la création de documentations intelligentes et très jolies. C'est cet outil qui permet d'écrire le documentation que vous êtes en train de lire actuellement. Développé en 2008 pour la communauté Python, c'est l'outil le plus répandu. Il est utilisé pour la documentation officielle de Python, pour celle de Django, Jinja2 et bien d'autres.
|
||||||
|
|
||||||
|
ReadTheDocs
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://www.sphinx-doc.org/en/master/>`__
|
||||||
|
|
||||||
|
C'est un site d'hébergement de documentations utilisant Sphinx. Il propose la génération de documentation à partir de sources et leur hébergement gracieusement pour tout projet open source. C'est le site le plus utilisé et sur lequel sont hébergées bon nombre de documentations comme par exemple celle de Django. La documentation sur ce site est automatiquement générée à chaque nouvelle modification du projet.
|
||||||
|
|
||||||
|
reStructuredText
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
`Site officiel <http://docutils.sourceforge.net/rst.html>`__
|
||||||
|
|
||||||
|
C'est un langage de balisage léger utilisé notamment dans la documentation du langage Python. C'est le langage dans lequel est écrit l'entièreté de la documentation ci-présente pour que Sphinx puisse la lire et la mettre en forme.
|
||||||
|
|
||||||
|
Workflow
|
||||||
|
--------
|
||||||
|
|
||||||
|
Git
|
||||||
|
~~~
|
||||||
|
|
||||||
|
`Site officiel <https://git-scm.com/>`__
|
||||||
|
|
||||||
|
Git est un logiciel de gestion de versions écrit par Linus Torsvald pour les besoins du noyau linux en 2005. C'est ce logiciel qui remplace svn anciennement utilisé pour gérer les sources du projet (rappelez vous, l'ancien site date d'avant 2005). Git est plus complexe à utiliser mais est bien plus puissant, permet de gérer plusieurs version en parallèle et génère des codebases vraiment plus légères puisque seules les modifications sont enregistrées (contrairement à svn qui garde une copie de la codebase par version).
|
||||||
|
|
||||||
|
GitLab
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
| `Site officiel <https://about.gitlab.com/>`__
|
||||||
|
| `Instance de l'AE <https://ae-dev.utbm.fr/>`__
|
||||||
|
|
||||||
|
GitLab est une alternative libre à GitHub. C'est une plate-forme avec interface web permettant de déposer du code géré avec Git offrant également de l'intégration continue et du déploiement automatique.
|
||||||
|
|
||||||
|
C'est au travers de cette plate-forme que le Sith de l'AE est géré, sur une instance hébergée directement sur nos serveurs.
|
||||||
|
|
||||||
|
Sentry
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
| `Site officiel <https://sentry.io>`__
|
||||||
|
| `Instance de l'AE <https://ae2.utbm.fr>`__
|
||||||
|
|
||||||
|
Sentry est une plate-forme libre qui permet de se tenir informer des bugs qui ont lieu sur le site. À chaque crash du logiciel (erreur 500), une erreur est envoyée sur la plate-forme et est indiqué précisément à quelle ligne de code celle-ci a eu lieu, à quelle heure, combien de fois, avec quel navigateur la page a été visitée et même éventuellement un commentaire de l'utilisateur qui a rencontré le bug.
|
||||||
|
|
||||||
|
Virtualenv
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
`Utiliser virtualenv <https://python-guide-pt-br.readthedocs.io/fr/latest/dev/virtualenvs.html>`__
|
||||||
|
|
||||||
|
Virtualenv est un utilitaire permettant d'installer un environnement Python de manière locale sans avoir besoin des droits root pour y installer des dépendances. Il est très utilisé pour gérer plusieurs projets différents en parallèles puisqu'il permet d'avoir sur sa machine plusieurs environnements différents et donc plusieurs versions d'une même dépendance dans plusieurs projets différent sans impacter le système sur lequel le tout est installé.
|
||||||
|
|
||||||
|
Black
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
`Site officiel <https://black.readthedocs.io/en/stable/>`__
|
||||||
|
|
||||||
|
Pour faciliter la lecture du code, il est toujours appréciable d'avoir une norme d'écriture cohérente. C'est généralement à l'étape de relecture des modifications par les autres contributeurs que sont repérées ces fautes de normes qui se doivent d'être corrigées pour le bien commun.
|
||||||
|
|
||||||
|
Imposer une norme est très fastidieux, que ce soit pour ceux qui relisent ou pour ceux qui écrivent. C'est pour cela que nous utilisons black qui est un formateur automatique de code. Une fois l'outil lancé, il parcours la codebase pour y repérer les fautes de norme et les corrige automatiquement sans que l'utilisateur ai à s'en soucier. Bien installé, il peut effectuer ce travail à chaque sauvegarde d'un fichier dans son éditeur, ce qui est très agréable pour travailler.
|
36
doc/about/versioning.rst
Normal file
36
doc/about/versioning.rst
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
Le versioning
|
||||||
|
=============
|
||||||
|
|
||||||
|
Dans le monde du développement, nous faisons face à un problème relativement étrange pour un domaine aussi avancé : on est brouillon.
|
||||||
|
|
||||||
|
On teste, on envoie, ça marche pas, on reteste, c'est ok. Par contre, on a oublie plein d'exceptions. Et on refactor. Ça marche mieux mais c'est moins rapide, etc, etc.
|
||||||
|
|
||||||
|
Et derrière tout ça, on fait des trucs qui marchent puis on se retrouve dans la mouise parce qu'on a effacé un morceau de code qui nous aurait servi plus tard.
|
||||||
|
|
||||||
|
Pour palier à ce problème, le programmeur a créé un principe révolutionnaire (ouais... à mon avis, on s'est inspiré d'autres trucs, mais on va dire que c'est nous les créateurs) : le Versioning (*Apparition inexpliquée*).
|
||||||
|
|
||||||
|
D'après projet-isika (c'est pas wikipedia ouais, ils étaient pas clairs eux), le versioning (ou versionnage en français mais c'est quand même vachement dégueu comme mot) consiste à travailler directement sur le code source d'un projet, en gardant toutes les versions précédentes. Les outils du versioning aident les développeurs à travailler parallèlement sur différentes parties du projet et à revenir facilement aux étapes précédentes de leur travail en cas de besoin. L’utilisation d’un logiciel de versioning est devenue quasi-indispensable pour tout développeur, même s’il travaille seul.
|
||||||
|
|
||||||
|
Un versioning pour les gouverner tous
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
On va vite fait passer sur les différents logiciels de contrôle de version avant de revenir à l'essentiel, le vrai, le beau, l'unique et l'ultime : Git.
|
||||||
|
|
||||||
|
**Source Code Control System (SCCS)**) : Développé en 1972 dans les labos d'IBM, il a été porté sur Unix pour ensuite donner naissance à RCS.
|
||||||
|
**GNU RCS (Revision Control System)** : RCS est à l'origine un projet universitaire, initié au début des années 1980, et maintenu pendant plus d'une décennie par Walter F. Tichy au sein de l'université Purdue.
|
||||||
|
|
||||||
|
Ce logiciel représente à l'époque une alternative libre au système SCCS, et une évolution technique, notamment par son interface utilisateur, plus conviviale, et une récupération des données, plus rapide, par l'amélioration du stockage des différentes versions. Ce gain de performance provient d'un algorithme appelé en anglais « reverse differences » (ou plus simplement « deltas ») et consiste à stocker la copie complète des versions les plus récentes et conserver uniquement les changements réalisés.
|
||||||
|
|
||||||
|
**CVS (Concurrent Versions System)** : En gros, c'est la première fois qu'on essaie de fusionner des versions *concurrentes* (dis-donc, quel hasard que ce soit des concurrents vu le nom du système !) de fichiers sources. C'était pas forcément compliqué : en gros, il y avait un serveur qui prenait à chaque fois la dernière version de chaque fichier, les développeurs devaient toujours avoir la dernière version du fichier s'ils voulaient éditer celui-ci. Si c'était pas le cas, le serveur les envoyait paitre.
|
||||||
|
|
||||||
|
**SVN (Subversion)** : En gros, c'est comme CVS mais avec quelques améliorations du fait du refactoring complet fait par Apache. Subversion permet notamment le renommage et le déplacement de fichiers ou de répertoires sans en perdre l'historique. On a aussi un versioning sur les metadatas (genre les changements de permissions des fichiers.
|
||||||
|
|
||||||
|
**Git** : Enfin le voilà. Le versioning ultime. Créé par Linus Torvalds en 2005, il permet notamment au bordel qu'est Linux d'être maintenu par des développeurs du monde entier grâce à un système original de version : en gros, chaque ordinateur a une version du code source et il n'y a pas forcément un serveur central qui garde tout (et demande un compte à chaque fois. Bon, maintenant on est de retour au format minitel avec Github mais on va vous montrer comment s'en sortir). Il y a également un système de branche pour pouvoir gérer différentes versions du code en parallèle. Tout est fait sous forme de petits fichiers de versioning qui vont faire des copies des fichiers correspondant à la modification proposée. Bref, c'est trop bien et on a pas fait mieux.
|
||||||
|
|
||||||
|
C'est pas forcément utile de comprendre le fonctionnement interne de Git pour développer (la preuve, je n'ai pas franchement chercher au tréfond du bousin) mais c'est en revanche indispensable de comprendre comment l'utiliser avant de faire n'importe quoi. Du coup, on va voir ci-dessous comment utiliser Git et comment on l'utilise sur le site AE.
|
||||||
|
|
||||||
|
TLDR
|
||||||
|
----
|
||||||
|
|
||||||
|
Un système de versioning permet de faire de la merde dans votre code et de pouvoir revenir en arrière malgré tout. Ça permet aussi de coder à plusieurs.
|
||||||
|
Git est le meilleur système de gestion de version (ou système de versioning) que vous pourrez trouver à l'heure actuelle. Utilisez-le.
|
7
doc/apps/core.rst
Normal file
7
doc/apps/core.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Documentation de core
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
core/models.rst
|
4
doc/apps/core/models.rst
Normal file
4
doc/apps/core/models.rst
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Classes liées aux utilisateurs
|
||||||
|
==============================
|
||||||
|
|
||||||
|
.. autoclass:: core.models.User
|
64
doc/conf.py
Normal file
64
doc/conf.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# http://www.sphinx-doc.org/en/master/config
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(".."))
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sith.settings")
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = "Sith AE UTBM"
|
||||||
|
copyright = (
|
||||||
|
"2019, Bartuccio Antoine (Sli), Brunet Pierre (Krohpil), Jacquet Florent (Skia)"
|
||||||
|
)
|
||||||
|
author = "Bartuccio Antoine (Sli), Brunet Pierre (Krohpil), Jacquet Florent (Skia)"
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = ["sphinx.ext.autodoc", "sphinx_copybutton", "sphinx.ext.autosectionlabel"]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = "fr"
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ["_static"]
|
55
doc/frequent/subscriptions.rst
Normal file
55
doc/frequent/subscriptions.rst
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
.. _add_subscription:
|
||||||
|
|
||||||
|
Ajouter une nouvelle cotisation
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Il arrive régulièrement que le type de cotisation proposé varie en prix et en durée au cours des années. Le projet étant pensé pour être utilisé par d'autres associations dans la mesure du possible, ces cotisations sont configurables directement dans les paramètres du projet.
|
||||||
|
|
||||||
|
Comprendre la configuration
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Pour modifier les cotisations disponnibles, tout se gère dans la configuration avec la variable *SITH_SUBSCRIPTIONS*. Dans cet exemple, nous allons ajouter une nouvelle cotisation d'un mois.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
SITH_SUBSCRIPTIONS = {
|
||||||
|
# Voici un échantillon de la véritable configuration à l'heure de l'écriture.
|
||||||
|
# Celle-ci est donnée à titre d'exemple pour mieux comprendre comment cela fonctionne.
|
||||||
|
"un-semestre": {"name": _("One semester"), "price": 15, "duration": 1},
|
||||||
|
"deux-semestres": {"name": _("Two semesters"), "price": 28, "duration": 2},
|
||||||
|
"cursus-tronc-commun": {
|
||||||
|
"name": _("Common core cursus"),
|
||||||
|
"price": 45,
|
||||||
|
"duration": 4,
|
||||||
|
},
|
||||||
|
"cursus-branche": {"name": _("Branch cursus"), "price": 45, "duration": 6},
|
||||||
|
"cursus-alternant": {"name": _("Alternating cursus"), "price": 30, "duration": 6},
|
||||||
|
"membre-honoraire": {"name": _("Honorary member"), "price": 0, "duration": 666},
|
||||||
|
"un-jour": {"name": _("One day"), "price": 0, "duration": 0.00555333},
|
||||||
|
|
||||||
|
# On rajoute ici notre cotisation
|
||||||
|
# Elle se nomme "Un mois"
|
||||||
|
# Coûte 6€
|
||||||
|
# Dure 1 mois (on résonne en semestre, ici c'est 1/6 de semestre)
|
||||||
|
"un-mois": {"name": _("One month"), "price": 6, "duration": 0.166}
|
||||||
|
}
|
||||||
|
|
||||||
|
Créer une migration
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
La modification de ce paramètre est étroitement lié à la génération de la base de données. Cette variable est utilisé dans l'objet *Subscription* pour générer les *subscription_type*. Le modifier requiers de générer une migration de basse de données.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py makemigrations subscription
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
N'oubliez pas d'appliquer black sur le fichier de migration généré.
|
||||||
|
|
||||||
|
Rajouter la traduction pour la cotisation
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
Comme on peut l'observer, la cotisation a besoin d'un nom qui est internationalisé. Il est donc nécessaire de le traduire en français. Pour rajouter notre traduction de *"One month"* il faut se référer à cette partie de la documentation : :ref:`translations`.
|
53
doc/frequent/weekmail.rst
Normal file
53
doc/frequent/weekmail.rst
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
Modifier le weekmail
|
||||||
|
====================
|
||||||
|
|
||||||
|
Le site est capable de générer des mails automatiques composé de l’agrégation d'articles composé par les administrateurs de clubs. Le contenu est inséré dans un template standardisé et contrôlé directement dans le code. Il arrive régulièrement que l'équipe communication souhaite modifier ce template. Que ce soit les couleurs, l'agencement ou encore la bannière ou le footer, voici tout ce qu'il y a à savoir sur le fonctionnement du weekmail en commençant par la classe qui le contrôle.
|
||||||
|
|
||||||
|
.. autoclass:: com.models.Weekmail
|
||||||
|
:members:
|
||||||
|
|
||||||
|
Modifier la bannière et le footer
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Comme on peut l'observer plus haut, ces éléments sont contrôlés par les méthodes *get_banner* et *get_footer* de la classe *Weekmail*. Les modifier est donc très simple, il suffit de modifier le contenu de la fonction et de rajouter les nouvelles images dans les statics.
|
||||||
|
|
||||||
|
Les images sont à ajouter dans dans **core/static/com/img** et sont à nommer selon le type (banner ou footer), le semestre (Automne ou Printemps) et l'année.
|
||||||
|
|
||||||
|
Exemple : *weekmail_bannerA18.jpg* pour la bannière de l'automne 2018.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Sélectionner le fichier de bannière pour le weekmail de l'automne 2018
|
||||||
|
|
||||||
|
def get_banner(self):
|
||||||
|
return "http://" + settings.SITH_URL + static("com/img/weekmail_bannerA18.jpg")
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Penser à prendre les images au format **jpg** et que les images soient le plus léger possible, c'est bien mieux pour l'utilisateur final.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pensez à laisser les anciennes images dans le dossier pour que les anciens weekmails ne soient pas affectés par les changements.
|
||||||
|
|
||||||
|
Modifier le template
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Comme on peut le voir dans la documentation de la classe, il existe deux templates différents. Un des templates est en texte pur et sert pour le rendu dégradé des lecteurs de mails ne supportant pas le HTML et un autre fait un rendu en HTML.
|
||||||
|
|
||||||
|
Ces deux templates sont respectivement accessibles aux emplacements suivants :
|
||||||
|
|
||||||
|
* com/templates/com/weekmail_renderer_html.jinja
|
||||||
|
* com/templates/com/weekmail_renderer_text.jinja
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pour le rendu HTML, pensez à utiliser le CSS et le javascript le plus simple possible pour que le rendu se fasse correctement dans les clients mails qui sont souvent capricieux.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Le CSS est inclus statiquement pour que toute modification ultérieure de celui-ci n'affecte pas les versions précédemment envoyées.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Si vous souhaitez ajouter du contenu, n'oubliez pas de bien inclure ce contenu dans les deux templates.
|
93
doc/index.rst
Normal file
93
doc/index.rst
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
.. Sith AE UTBM documentation master file, created by
|
||||||
|
sphinx-quickstart on Thu Aug 8 19:24:14 2019.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
Bienvenue sur la documentation du Sith de l'AE
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: À propos du projet:
|
||||||
|
|
||||||
|
about/introduction
|
||||||
|
about/tech
|
||||||
|
about/versioning
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Bien démarrer
|
||||||
|
|
||||||
|
start/install
|
||||||
|
start/structure
|
||||||
|
start/hello_world
|
||||||
|
|
||||||
|
start/translations
|
||||||
|
|
||||||
|
start/devtools
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: La surcouche "Site AE"
|
||||||
|
|
||||||
|
overlay/rights
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Modifications fréquentes
|
||||||
|
|
||||||
|
frequent/subscriptions
|
||||||
|
frequent/weekmail
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
:caption: Documentation des apps
|
||||||
|
|
||||||
|
apps/core
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Divers
|
||||||
|
|
||||||
|
misc/md_syntax
|
||||||
|
misc/helpers
|
||||||
|
misc/direnv
|
||||||
|
misc/prod
|
||||||
|
|
||||||
|
Documentations complémentaires
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Python et Django
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* `Apprendre Python <https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python>`__
|
||||||
|
* `Documentation de Django <https://docs.djangoproject.com/fr/1.11/>`__
|
||||||
|
* `Classy Class-Based Views <http://ccbv.co.uk/projects/Django/1.11/>`__
|
||||||
|
|
||||||
|
HTML/Jinja/JS/(S)CSS
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* `Cours sur le javascript <https://openclassrooms.com/fr/courses/2984401-apprenez-a-coder-avec-javascript>`__
|
||||||
|
* `Cours sur jQuery <https://openclassrooms.com/fr/courses/1631636-simplifiez-vos-developpements-javascript-avec-jquery>`__
|
||||||
|
* `Cours sur le HTML et CSS <https://openclassrooms.com/fr/courses/1631636-simplifiez-vos-developpements-javascript-avec-jquery>`__
|
||||||
|
* `Documentation sur les grilles CSS <https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Grid_Layout>`__
|
||||||
|
* `Guide pour le SASS <https://sass-lang.com/guide>`__
|
||||||
|
* `Documentation de fontawesome <https://fontawesome.com/how-to-use/on-the-web/referencing-icons/basic-use>`__
|
||||||
|
* `Documentation pour Jinja2 <https://jinja.palletsprojects.com/en/2.10.x/>`__
|
||||||
|
|
||||||
|
Git
|
||||||
|
~~~
|
||||||
|
|
||||||
|
* `Cours sur Git <https://openclassrooms.com/fr/courses/2342361-gerez-votre-code-avec-git-et-github>`__
|
||||||
|
* `Livre sur Git <http://www.git-scm.com/book/fr/v2>`__
|
||||||
|
|
||||||
|
|
||||||
|
Documents téléchargeables
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
* :download:`Rapport de la TW de Skia sur la création du site <TW_Skia/Rapport.pdf>`
|
||||||
|
* :download:`Rapport sur la TO de Skia et LoJ <TO_Skia_LoJ/Rapport.pdf>`
|
||||||
|
* :download:`Manuel du service E-transactions <Etransaction/Manuel_Integration_E-transactions_Internet_V6.6_FR.pdf>`
|
||||||
|
* :download:`Guide de trésorerie <Guide de Tresorerie.pdf>`
|
35
doc/make.bat
Normal file
35
doc/make.bat
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
|
set BUILDDIR=_build
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.http://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
31
doc/misc/direnv.rst
Normal file
31
doc/misc/direnv.rst
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.. _direnv:
|
||||||
|
|
||||||
|
Utiliser direnv
|
||||||
|
===============
|
||||||
|
|
||||||
|
Pour éviter d'avoir à sourcer l'environnement à chaque fois qu'on rentre dans le projet, il est possible d'utiliser l'utilitaire `direnv <https://direnv.net/>`__.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
# Installation de l'utilitaire
|
||||||
|
|
||||||
|
# Debian et Ubuntu
|
||||||
|
sudo apt install direnv
|
||||||
|
# Mac
|
||||||
|
brew install direnv
|
||||||
|
|
||||||
|
|
||||||
|
# Installation dans la config
|
||||||
|
# Si sur bash
|
||||||
|
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
|
||||||
|
# Si sur ZSH
|
||||||
|
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
|
||||||
|
|
||||||
|
exit # On redémarre le terminal
|
||||||
|
|
||||||
|
# Une fois dans le dossier du projet site AE
|
||||||
|
direnv allow .
|
||||||
|
|
||||||
|
Une fois que cette configuration a été appliquée, aller dans le dossier du site applique automatiquement l'environnement virtuel, cela fait beaucoup moins de temps perdu pour tout le monde.
|
||||||
|
|
||||||
|
Direnv est un utilitaire très puissant et qui peut s'avérer pratique dans bien des situations, n'hésitez pas à aller vous renseigner plus en détail sur celui-ci.
|
17
doc/misc/helpers.rst
Normal file
17
doc/misc/helpers.rst
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Commandes utiles
|
||||||
|
================
|
||||||
|
|
||||||
|
Appliquer le header de licence sur tout le projet
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
for f in $(find . -name "*.py" ! -path "*migration*" ! -path "./env/*" ! -path "./doc/*"); do cat ./doc/header "$f" > /tmp/temp && mv /tmp/temp "$f"; done
|
||||||
|
|
||||||
|
Compter le nombre de lignes de code
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo apt install cloc
|
||||||
|
cloc --exclude-dir=doc,env .
|
20
doc/misc/md_syntax.rst
Normal file
20
doc/misc/md_syntax.rst
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Syntaxe markdown utilisée dans le site
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Si vous faites une mise à jour sur le parseur markdown, il est bon de documenter cette mise à jour dans la page de référence *doc/SYNTAX.md*. Mettre à jour ce fichier vas casser les tests si vous ne mettez pas à jour le fichier *doc/SYNTAX.html* qui lui correspond juste après. Pour mettre à jour ce fichier il suffit d'utiliser la commande
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./manage.py markdown > doc/SYNTAX.html
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Le rendu de cette aide est fait via Sphinx, il peut représenter quelques différences avec la réalité. Il est possible de télécharger juste en dessous les versions brutes.
|
||||||
|
|
||||||
|
* :download:`Fichier d'aide en markdown <../SYNTAX.md>`
|
||||||
|
* :download:`Fichier d'aide rendu en HTML <../SYNTAX.html>`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
:file: ../SYNTAX.html
|
21
doc/misc/prod.rst
Normal file
21
doc/misc/prod.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Configurer pour la production
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Configurer Sentry
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Pour connecter l'application à une instance de sentry (ex: https://sentry.io) il est nécessaire de configurer la variable **SENTRY_DSN** dans le fichier *settings_custom.py*. Cette variable est composée d'un lien complet vers votre projet sentry.
|
||||||
|
|
||||||
|
Récupérer les statiques
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Nous utilisons du SCSS dans le projet. En environnement de développement (DEBUG=True), le SCSS est compilé à chaque fois que le fichier est demandé. Pour la production, le projet considère que chacun des fichier est déjà compilé, et, pour ce faire, il est nécessaire d'utiliser les commandes suivantes dans l'ordre :
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py collectstatic # Pour récupérer tous les fichiers statiques
|
||||||
|
./manage.py compilestatic # Pour compiler les fichiers SCSS qu'ils contiennent
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Le dossier où seront enregistrés ces fichiers statiques peut être changé en modifiant la variable *STATIC_ROOT* dans les paramètres.
|
158
doc/overlay/rights.rst
Normal file
158
doc/overlay/rights.rst
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
La gestion des droits
|
||||||
|
=====================
|
||||||
|
|
||||||
|
La gestion des droits dans l'association étant très complexe, le système de permissions intégré dans Django ne suffisait pas, il a donc fallu créer et intégrer le notre.
|
||||||
|
|
||||||
|
La gestion des permissions se fait directement sur un modèle, il existe trois niveaux de permission :
|
||||||
|
|
||||||
|
* Édition des propriétés de l'objet
|
||||||
|
* Édition de certaines valeurs l'objet
|
||||||
|
* Voir l'objet
|
||||||
|
|
||||||
|
Protéger un modèle
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Lors de l'écriture d'un modèle, il est très simple de définir des permissions. Celle-ci peuvent être basées sur des groupes et/ou sur des fonctions personnalisées.
|
||||||
|
|
||||||
|
Nous allons présenter ici les deux techniques. Dans un premier temps nous allons protéger une classe Article par groupes.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from core.views import *
|
||||||
|
from core.models import User, Group
|
||||||
|
|
||||||
|
# Utilisation de la protection par groupe
|
||||||
|
class Article(models.Model):
|
||||||
|
|
||||||
|
title = models.CharField(_("title"), max_length=100)
|
||||||
|
content = models.TextField(_("content"))
|
||||||
|
|
||||||
|
# Ne peut pas être une liste
|
||||||
|
# Groupe possédant l'objet
|
||||||
|
# Donne les droits d'édition des propriétés de l'objet
|
||||||
|
owner_group = models.ForeignKey(
|
||||||
|
Group, related_name="owned_articles", default=settings.SITH_GROUP_ROOT_ID
|
||||||
|
)
|
||||||
|
|
||||||
|
# Doit être une liste
|
||||||
|
# Tous les groupes qui seront ajouté dans ce champ auront les droits d'édition de l'objet
|
||||||
|
edit_group = models.ManyToManyField(
|
||||||
|
edit_groups = models.ManyToManyField(
|
||||||
|
Group,
|
||||||
|
related_name="editable_articles",
|
||||||
|
verbose_name=_("edit groups"),
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Doit être une liste
|
||||||
|
# Tous les groupes qui seront ajouté dans ce champ auront les droits de vue de l'objet
|
||||||
|
view_groups = models.ManyToManyField(
|
||||||
|
Group,
|
||||||
|
related_name="viewable_articles",
|
||||||
|
verbose_name=_("view groups"),
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
Voici maintenant comment faire en définissant des fonctions personnalisées. Cette deuxième solution permet, dans le cas où la première n'est pas assez puissante, de créer des permissions complexes et fines. Attention à bien les rendre lisibles et de bien documenter.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from core.views import *
|
||||||
|
from core.models import User, Group
|
||||||
|
|
||||||
|
# Utilisation de la protection par fonctions
|
||||||
|
class Article(models.Model):
|
||||||
|
|
||||||
|
title = models.CharField(_("title"), max_length=100)
|
||||||
|
content = models.TextField(_("content"))
|
||||||
|
|
||||||
|
# Donne ou non les droits d'édition des propriétés de l'objet
|
||||||
|
# Un utilisateur dans le bureau AE aura tous les droits sur cet objet
|
||||||
|
def is_owned_by(self, user):
|
||||||
|
return user.is_board_member
|
||||||
|
|
||||||
|
# Donne ou non les droits d'édition de l'objet
|
||||||
|
# L'objet ne sera modifiable que par un utilisateur cotisant
|
||||||
|
def can_be_edited_by(self, user):
|
||||||
|
return user.is_subscribed
|
||||||
|
|
||||||
|
# Donne ou non les droits de vue de l'objet
|
||||||
|
# Ici, l'objet n'est visible que par un utilisateur connecté
|
||||||
|
def can_be_viewed_by(self, user):
|
||||||
|
return not user.user.is_anonymous
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Si un utilisateur est autorisé à un niveau plus élevé que celui auquel il est testé, le système le détectera automatiquement et les droits lui seront accordé. Par défaut, les seuls utilisateurs ayant des droits quelconques sont les *superuser* de Django et les membres du bureau AE qui sont définis comme *owner*.
|
||||||
|
|
||||||
|
Appliquer les permissions
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Dans un template
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Il existe trois fonctions de base sur lesquelles reposent les vérifications de permission. Elles sont disponibles dans le contexte par défaut du moteur de template et peuvent être utilisées à tout moment.
|
||||||
|
|
||||||
|
Tout d'abord, voici leur documentation et leur prototype.
|
||||||
|
|
||||||
|
.. autofunction:: core.views.can_edit_prop
|
||||||
|
.. autofunction:: core.views.can_edit
|
||||||
|
.. autofunction:: core.views.can_view
|
||||||
|
|
||||||
|
Voici un exemple d'utilisation dans un template :
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{# ... #}
|
||||||
|
{% if can_edit(club, user) %}
|
||||||
|
<a href="{{ url('club:tools', club_id=club.id) }}">{{ club }}</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
Dans une vue
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Généralement, les vérifications de droits dans les templates se limitent au liens à afficher puisqu'il ne faut pas mettre de logique autre que d'affichage à l'intérieur. C'est donc généralement au niveau des vues que cela a lieu.
|
||||||
|
|
||||||
|
Notre système s'appuie sur un système de mixin à hériter lors de la création d'une vue basée sur une classe. Ces mixins ne sont compatibles qu'avec les classes récupérant un objet ou une liste d'objet. Dans le cas d'un seul objet, une permission refusée est levée lorsque l'utilisateur n'as pas le droit de visionner la page. Dans le d'une liste d'objet, le mixin filtre les objets non autorisés et si aucun ne l'est l'utilisateur recevra une liste vide d'objet.
|
||||||
|
|
||||||
|
Voici un exemple d'utilisation en reprenant l'objet Article crée précédemment :
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.views.generic import CreateView, ListView
|
||||||
|
|
||||||
|
from core.views import CanViewMixin, CanCreateMixin
|
||||||
|
|
||||||
|
from .models import Article
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
# Il est important de mettre le mixin avant la classe héritée de Django
|
||||||
|
# L'héritage multiple se fait de droite à gauche et les mixins ont besoin
|
||||||
|
# d'une classe de base pour fonctionner correctement.
|
||||||
|
class ArticlesListView(CanViewMixin, ListView):
|
||||||
|
|
||||||
|
model = Article # On base la vue sur le modèle Article
|
||||||
|
...
|
||||||
|
|
||||||
|
# Même chose pour une vue de création de l'objet Article
|
||||||
|
class ArticlesCreateView(CanCreateMixin, CreateView):
|
||||||
|
|
||||||
|
model = Article
|
||||||
|
|
||||||
|
Le système de permissions de propose plusieurs mixins différents, les voici dans leur intégralité.
|
||||||
|
|
||||||
|
.. autoclass:: core.views.CanCreateMixin
|
||||||
|
.. autoclass:: core.views.CanEditPropMixin
|
||||||
|
.. autoclass:: core.views.CanEditMixin
|
||||||
|
.. autoclass:: core.views.CanViewMixin
|
||||||
|
.. autoclass:: core.views.FormerSubscriberMixin
|
||||||
|
.. autoclass:: core.views.UserIsLoggedMixin
|
60
doc/start/devtools.rst
Normal file
60
doc/start/devtools.rst
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
Configurer son environnement de développement
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
Le projet n'est en aucun cas lié à un quelconque environnement de développement. Il est possible pour chacun de travailler avec les outils dont il a envie et d'utiliser l'éditeur de code avec lequel il est le plus à l'aise.
|
||||||
|
|
||||||
|
Pour donner une idée, Skia a écrit une énorme partie de projet avec l'éditeur *vim* sur du GNU/Linux alors que Sli a utilisé *Sublime Text* sur MacOS.
|
||||||
|
|
||||||
|
Configurer Black pour son éditeur
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Tous les détails concernant l'installation de black sont ici : https://black.readthedocs.io/en/stable/editor_integration.html
|
||||||
|
|
||||||
|
Néanmoins, nous tenterons de vous faire ici un résumé pour deux éditeurs de textes populaires que sont VsCode et Sublime Text.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
# Installation de black
|
||||||
|
pip install black
|
||||||
|
|
||||||
|
VsCode
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Il faut installer black dans son virtualenv pour cet éditeur
|
||||||
|
|
||||||
|
Black est directement pris en charge par l'extension pour le Python de VsCode, il suffit de rentrer la configuration suivante :
|
||||||
|
|
||||||
|
.. sourcecode:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"python.formatting.provider": "black",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Sublime Text
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Il est tout d'abord nécessaire d'installer ce plugin : https://packagecontrol.io/packages/sublack.
|
||||||
|
|
||||||
|
Il suffit ensuite d'ajouter dans les settings du projet (ou directement dans les settings globales) :
|
||||||
|
|
||||||
|
.. sourcecode:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"sublack.black_on_save": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Si vous utilisez le plugin `anaconda <http://damnwidget.github.io/anaconda/>`__, pensez à modifier les paramètres du linter pep8 pour éviter de recevoir des warnings dans le formatage de black comme ceci :
|
||||||
|
|
||||||
|
.. sourcecode:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"pep8_ignore": [
|
||||||
|
"E203",
|
||||||
|
"E266",
|
||||||
|
"E501",
|
||||||
|
"W503"
|
||||||
|
]
|
||||||
|
}
|
275
doc/start/hello_world.rst
Normal file
275
doc/start/hello_world.rst
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
Créer une nouvelle application Hello World
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
L'objectif de ce petit tutoriel est de prendre rapidement en main les vues, les urls et les modèles de Django. On créera une application nommée *hello* qui fournira une page affichant "Hello World", une autre page qui affichera en plus un numéro qui sera récupéré depuis l'URL ainsi qu'une page affichant un élément récupéré de la base de données, le tout au milieu d'une page typique du Sith AE.
|
||||||
|
|
||||||
|
Créer l'application
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
La première étape est de crée l'application. Cela se fait très simplement avec les outils fournis par le framework.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py startapp hello
|
||||||
|
|
||||||
|
Il faut ensuite activer l'application dans les paramètres du projet en l'ajoutant dans la liste des applications installées.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# sith/settings.py
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
...
|
||||||
|
"hello",
|
||||||
|
)
|
||||||
|
|
||||||
|
Enfin, on vas inclure les URLs de cette application dans le projet sous le préfixe */hello/*.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# sith/urls.py
|
||||||
|
urlpatterns = [
|
||||||
|
...
|
||||||
|
url(r"^hello/", include("hello.urls", namespace="hello", app_name="hello")),
|
||||||
|
]
|
||||||
|
|
||||||
|
Un Hello World simple
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Dans un premier temps, nous allons créer une vue qui vas charger un template en utilisant le système de vues basées sur les classes de Django.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/views.py
|
||||||
|
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
# Toute la logique pour servir la vue et parser le template
|
||||||
|
# est directement héritée de TemplateView
|
||||||
|
class HelloView(TemplateView):
|
||||||
|
template_name = "hello/hello.jinja" # On indique quel template utiliser
|
||||||
|
|
||||||
|
On vas ensuite créer le template.
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{# hello/templates/hello/hello.jinja #}
|
||||||
|
|
||||||
|
{# On étend le template de base du Sith #}
|
||||||
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
|
{# On remplis la partie titre du template étendu #}
|
||||||
|
{# Il s'agit du titre qui sera affiché dans l'onglet du navigateur #}
|
||||||
|
{% block title %}
|
||||||
|
Hello World
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{# On remplis le contenu de la page #}
|
||||||
|
{% block content %}
|
||||||
|
<p>Hello World !</p>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
Enfin, on crée l'URL. On veut pouvoir appeler la page depuis https://localhost:8000/hello, le préfixe indiqué précédemment suffit donc.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/urls.py
|
||||||
|
from django.conf.urls import url
|
||||||
|
from hello.views import HelloView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
# Le préfixe étant retiré lors du passage du routeur d'URL
|
||||||
|
# dans le fichier d'URL racine du projet, l'URL à matcher ici est donc vide
|
||||||
|
url(r"^$", HelloView.as_view(), name="hello"),
|
||||||
|
]
|
||||||
|
|
||||||
|
Et voilà, c'est fini, il ne reste plus qu'à lancer le serveur et à se rendre sur la page.
|
||||||
|
|
||||||
|
Manipuler les arguments d'URL
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Dans cette partie, on cherche à détecter les numéros passés dans l'URL pour les passer dans le template. On commence par ajouter cet URL modifiée.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/urls.py
|
||||||
|
from django.conf.urls import url
|
||||||
|
from hello.views import HelloView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r"^$", HelloView.as_view(), name="hello"),
|
||||||
|
# On utilise un regex pour matcher un numéro
|
||||||
|
url(r"^(?P<hello_id>[0-9]+)$", HelloView.as_view(), name="hello"),
|
||||||
|
]
|
||||||
|
|
||||||
|
Cette deuxième URL vas donc appeler la classe crée tout à l'heure en lui passant une variable *hello_id* dans ses *kwargs*, nous allons la récupérer et la passer dans le contexte du template en allant modifier la vue.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/views.py
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
class HelloView(TemplateView):
|
||||||
|
template_name = "hello/hello.jinja"
|
||||||
|
|
||||||
|
# C'est la méthode appelée juste avant de définir le type de requête effectué
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
# On récupère l'ID et on le met en attribut
|
||||||
|
self.hello_id = kwargs.pop("hello_id", None)
|
||||||
|
|
||||||
|
# On reprend le déroulement normal en appelant la méthode héritée
|
||||||
|
return super(HelloView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
# Cette méthode renvoie les variables qui seront dans le contexte du template
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
|
||||||
|
# On récupère ce qui était sensé être par défaut dans le contexte
|
||||||
|
kwargs = super(HelloView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
# On ajoute notre ID
|
||||||
|
kwargs["hello_id"] = self.hello_id
|
||||||
|
|
||||||
|
# On renvoie le contexte
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
Enfin, on modifie le template en rajoutant une petite condition sur la présence ou non de cet ID pour qu'il s'affiche.
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{# hello/templates/hello/hello.jinja #}
|
||||||
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Hello World
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<p>
|
||||||
|
Hello World !
|
||||||
|
{% if hello_id -%}
|
||||||
|
{{ hello_id }}
|
||||||
|
{%- endif -%}
|
||||||
|
</p>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Il est tout à fait possible d'utiliser les arguments GET passés dans l'URL. Dans ce cas, il n'est pas obligatoire de modifier l'URL et il est possible de récupérer l'argument dans le dictionnaire `request.GET`.
|
||||||
|
|
||||||
|
À l'assaut des modèles
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Pour cette dernière partie, nous allons ajouter une entrée dans la base de donnée et l'afficher dans un template. Nous allons ainsi créer un modèle nommé *Article* qui contiendra une entrée de texte pour le titre et une autre pour le contenu.
|
||||||
|
|
||||||
|
Commençons par le modèle en lui même.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/models.py
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Article(models.Model):
|
||||||
|
|
||||||
|
title = models.CharField("titre", max_length=100)
|
||||||
|
content = models.TextField("contenu")
|
||||||
|
|
||||||
|
Continuons avec une vue qui sera en charge d'afficher l'ensemble des articles présent dans la base.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# hello/views.py
|
||||||
|
|
||||||
|
from django.views.generic import ListView
|
||||||
|
|
||||||
|
from hello.models import Article
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
# On hérite de ListView pour avoir plusieurs objets
|
||||||
|
class ArticlesListView(ListView):
|
||||||
|
|
||||||
|
model = Article # On base la vue sur le modèle Article
|
||||||
|
template_name = "hello/articles.jinja"
|
||||||
|
|
||||||
|
On n'oublie pas l'URL.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from hello.views import HelloView, ArticlesListView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
...
|
||||||
|
url(r"^articles$", ArticlesListView.as_view(), name="articles_list")
|
||||||
|
]
|
||||||
|
|
||||||
|
Et enfin le template.
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{# hello/templates/hello/articles.jinja #}
|
||||||
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Hello World Articles
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{# Par défaut une liste d'objets venant de ListView s'appelle object_list #}
|
||||||
|
{% for article in object_list %}
|
||||||
|
<h2>{{ article.title }}</h2>
|
||||||
|
<p>{{ article.content }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
Maintenant que toute la logique de récupération et d'affichage est terminée, la page est accessible à l'adresse https://localhost:8000/hello/articles.
|
||||||
|
|
||||||
|
Mais, j'ai une erreur ! Il se passe quoi ?! Et bien c'est simple, nous avons crée le modèle mais il n'existe pas dans la base de données. Il est dans un premier temps important de créer un fichier de migrations qui contiens des instructions pour la génération de celle-ci. Ce sont les fichiers qui sont enregistrés dans le dossier migration. Pour les générer à partir des classes de modèles qu'on viens de manipuler il suffit d'une seule commande.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py makemigrations
|
||||||
|
|
||||||
|
Un fichier *hello/migrations/0001_initial.py* se crée automatiquement, vous pouvez même aller le voir.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Il est tout à fait possible de modifier à la main les fichiers de migrations. C'est très intéressant si par exemple il faut appliquer des modifications sur les données d'un modèle existant après cette migration mais c'est bien au delà du sujet de ce tutoriel. Référez vous à la documentation pour ce genre de choses.
|
||||||
|
|
||||||
|
J'ai toujours une erreur ! Mais oui, c'est pas fini, faut pas aller trop vite. Maintenant il faut appliquer les modifications à la base de données.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py migrate
|
||||||
|
|
||||||
|
Et voilà, là il n'y a plus d'erreur. Tout fonctionne et on a une superbe page vide puisque aucun contenu pour cette table n'est dans la base. Nous allons en rajouter. Pour cela nous allons utiliser le fichier *core/management/commands/populate.py* qui contiens la commande qui initialise les données de la base de données de test. C'est un fichier très important qu'on viendra à modifier assez souvent. Nous allons y ajouter quelques articles.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# core/management/commands/populate.py
|
||||||
|
from hello.models import Article
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
Article(title="First hello", content="Bonjour tout le monde").save()
|
||||||
|
Article(title="Tutorial", content="C'était un super tutoriel").save()
|
||||||
|
|
||||||
|
|
||||||
|
On regénère enfin les données de test en lançant la commande que l'on viens de modifier.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
./manage.py setup
|
||||||
|
|
||||||
|
On reviens sur https://localhost:8000/hello/articles et cette fois-ci nos deux articles apparaissent correctement.
|
109
doc/start/install.rst
Normal file
109
doc/start/install.rst
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
Installer le projet
|
||||||
|
===================
|
||||||
|
|
||||||
|
Dépendances du système
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Certaines dépendances sont nécessaires niveau système :
|
||||||
|
|
||||||
|
* virtualenv
|
||||||
|
* limysqlclient
|
||||||
|
* libssl
|
||||||
|
* libjpeg
|
||||||
|
* python3-xapian
|
||||||
|
* zlib1g-dev
|
||||||
|
* python3
|
||||||
|
* mysql-client (pour migrer de l'ancien site)
|
||||||
|
|
||||||
|
Sur Ubuntu
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
sudo apt install libmysqlclient-dev libssl-dev libjpeg-dev zlib1g-dev python3-dev libffi-dev python3-dev libgraphviz-dev pkg-config python3-xapian gettext git
|
||||||
|
sudo pip3 install virtualenv
|
||||||
|
|
||||||
|
Sur MacOS
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
Pour installer les dépendances, il est fortement recommandé d'installer le gestionnaire de paquets `homebrew <https://brew.sh/index_fr>`_.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
brew install git python xapian
|
||||||
|
pip install virtualenv
|
||||||
|
|
||||||
|
Installer le projet
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
git clone https://ae-dev.utbm.fr/ae/Sith.git
|
||||||
|
cd Sith
|
||||||
|
|
||||||
|
# Prépare et active l'environnement du projet
|
||||||
|
virtualenv --system-site-packages --python=python3 env
|
||||||
|
source env/bin/activate
|
||||||
|
|
||||||
|
# Installe les dépendances du projet
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Prépare la base de donnée
|
||||||
|
./manage.py setup
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pour éviter d'avoir à utiliser la commande source sur le virtualenv systématiquement, il est possible de consulter :ref:`direnv`.
|
||||||
|
|
||||||
|
Configuration pour le développement
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Lorsqu'on souhaite développer pour le site, il est nécessaire de passer le logiciel en mode debug dans les settings_custom. Il est aussi conseillé de définir l'URL du site sur localhost. Voici un script rapide pour le faire.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
echo "DEBUG=True" > sith/settings_custom.py
|
||||||
|
echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py
|
||||||
|
|
||||||
|
Démarrer le serveur de développement
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Il faut toujours avoir préalablement activé l'environnement virtuel comme fait plus haut et se placer à la racine du projet. Il suffit ensuite d'utiliser cette commande :
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
./manage.py runserver
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Le serveur est alors accessible à l'adresse http://localhost:8000.
|
||||||
|
|
||||||
|
Générer la documentation
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
La documentation est automatiquement mise en ligne sur readthedocs à chaque envoi de code sur GitLab.
|
||||||
|
|
||||||
|
Pour l'utiliser en local ou globalement pour la modifier, il existe une commande du site qui génère la documentation et lance un serveur la rendant accessible à l'adresse http://localhost:8080.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
./manage.py documentation
|
||||||
|
|
||||||
|
Lancer les tests
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Pour lancer les tests il suffit d'utiliser la commande intégrée à django.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Lancer tous les tests
|
||||||
|
./manage.py test
|
||||||
|
|
||||||
|
# Lancer les tests de l'application core
|
||||||
|
./manage.py test core
|
||||||
|
|
||||||
|
# Lancer les tests de la classe UserRegistrationTest de core
|
||||||
|
./manage.py test core.tests.UserRegistrationTest
|
||||||
|
|
||||||
|
# Lancer une méthode en particulier de cette même classe
|
||||||
|
./manage.py test core.tests.UserRegistrationTest.test_register_user_form_ok
|
2
doc/start/mvt_circle.svg
Normal file
2
doc/start/mvt_circle.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.9 KiB |
2
doc/start/mvt_flat.svg
Normal file
2
doc/start/mvt_flat.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.8 KiB |
153
doc/start/structure.rst
Normal file
153
doc/start/structure.rst
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
La structure du projet
|
||||||
|
======================
|
||||||
|
|
||||||
|
Le principe MVT
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Django est un framework suivant le modèle MVT (Model-View-Template) aussi appelé MTV (Model-Template-View).
|
||||||
|
|
||||||
|
.. figure:: mvt_circle.svg
|
||||||
|
:alt: Diagramme MVT
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Diagramme MVT
|
||||||
|
|
||||||
|
On peut ainsi voir que la Vue gère la logique d'application, le modèle gère la structure de la base de données et communique avec elle et la vue effectue la logique de l'application. Décris comme ça, cela fait penser au modèle MVC (Model-View-Controller) mais évitons de nous complexifier les choses. Disons que c'est assez proche mais qu'il y a quelques différences (déjà au niveau du nommage).
|
||||||
|
|
||||||
|
On peut également représenter le tout sous une autre forme, plus simple à comprendre et visualiser en aplatissant le diagramme. Cela représente mieux ce qui se passe.
|
||||||
|
|
||||||
|
.. figure:: mvt_flat.svg
|
||||||
|
:alt: Diagramme MVT aplati
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Diagramme MVT aplati
|
||||||
|
|
||||||
|
Cette représentation permet de se représenter les interactions sous formes de couches. Avec ça en tête, ce sera plus simple d’appréhender la manière dont est découpé le projet.
|
||||||
|
|
||||||
|
Le découpage en applications
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
| /projet
|
||||||
|
| **sith/**
|
||||||
|
| Application principale du projet.
|
||||||
|
| **accounting/**
|
||||||
|
| Ajoute un système de comptabilité.
|
||||||
|
| **api/**
|
||||||
|
| Application où mettre les endpoints publiques d'API.
|
||||||
|
| **club/**
|
||||||
|
| Contiens les modèles liés aux clubs associatifs et ajoute leur gestion.
|
||||||
|
| **com/**
|
||||||
|
| Fournis des outils de communications aux clubs (weekmail, affiches…).
|
||||||
|
| **core/**
|
||||||
|
| Application la plus importante. Contiens les principales surcouches
|
||||||
|
| liées au projet comme la gestion des droits et les templates de base.
|
||||||
|
| **counter/**
|
||||||
|
| Ajoute des comptoirs de vente pour les clubs et gère les ventes sur les lieux de vie.
|
||||||
|
| **data/**
|
||||||
|
| Contiens les fichiers statiques ajoutées par les utilisateurs.
|
||||||
|
| N'est pas suivit par Git.
|
||||||
|
| **doc/**
|
||||||
|
| Contiens la documentation du projet.
|
||||||
|
| **eboutic/**
|
||||||
|
| Ajoute le comptoir de vente en ligne. Permet d'acheter en carte bancaire.
|
||||||
|
| **election/**
|
||||||
|
| Ajoute un système d'élection permettant d'élire les représentants étudiants.
|
||||||
|
| **forum/**
|
||||||
|
| Ajoute un forum de discutions.
|
||||||
|
| **launderette/**
|
||||||
|
| Permet la gestion des laveries.
|
||||||
|
| **locale/**
|
||||||
|
| Contiens les fichiers de traduction.
|
||||||
|
| **matmat/**
|
||||||
|
| Système de recherche de membres.
|
||||||
|
| **pedagogy/**
|
||||||
|
| Contiens le guide des UVs.
|
||||||
|
| **rootplace/**
|
||||||
|
| Ajoute des outils destinés aux administrateurs.
|
||||||
|
| **static/**
|
||||||
|
| Contiens l'ensemble des fichiers statiques ajoutés par les développeurs.
|
||||||
|
| Ce dossier est généré par le framework, il est surtout utile en production.
|
||||||
|
| Ce dossier n'es pas suivit par Git.
|
||||||
|
| **stock/**
|
||||||
|
| Système de gestion des stocks.
|
||||||
|
| **subscription/**
|
||||||
|
| Ajoute la gestion des cotisations des membres.
|
||||||
|
| **trombi/**
|
||||||
|
| Permet la génération du trombinoscope des élèves en fin de cursus.
|
||||||
|
| **.coveragec**
|
||||||
|
| Configure l'outil permettant de calculer la couverture des tests sur le projet.
|
||||||
|
| **.gitignore**
|
||||||
|
| Permet de définir quels fichiers sont suivis ou non par Git.
|
||||||
|
| **.gitlab-ci.yml**
|
||||||
|
| Permet de configurer la pipeline automatique de GitLab.
|
||||||
|
| **.readthedocs.yml**
|
||||||
|
| Permet de configurer la génération de documentation sur Readthedocs.
|
||||||
|
| **.db.sqlite3**
|
||||||
|
| Base de données de développement par défaut. Est automatiquement généré
|
||||||
|
| lors de la configuration du projet en local. N'est pas suivis par Git.
|
||||||
|
| **LICENSE**
|
||||||
|
| Licence du projet.
|
||||||
|
| **LICENSE.old**
|
||||||
|
| Ancienne licence du projet.
|
||||||
|
| **manage.py**
|
||||||
|
| Permet de lancer les commandes liées au framework Django.
|
||||||
|
| **migrate.py**
|
||||||
|
| Contiens des scripts de migration à exécuter pour importer les données de l'ancien site.
|
||||||
|
| **README.rst**
|
||||||
|
| Fichier de README. À lire pour avoir des informations sur le projet.
|
||||||
|
| **requirements.txt**
|
||||||
|
| Contiens les dépendances Python du projet.
|
||||||
|
|
||||||
|
|
||||||
|
L'application principale
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
| /sith
|
||||||
|
| **__init__.py**
|
||||||
|
| Permet de définir le dossier comme un package Python.
|
||||||
|
| Ce fichier est vide.
|
||||||
|
| **settings.py**
|
||||||
|
| Contiens les paramètres par défaut du projet.
|
||||||
|
| Ce fichier est versionné et fait partie intégrant de celui-ci.
|
||||||
|
| **settings_curtom.py**
|
||||||
|
| Contiens les paramètres spécifiques à l'installation courante.
|
||||||
|
| Ce fichier n'est pas versionné et surcharges les paramètres par défaut.
|
||||||
|
| **urls.py**
|
||||||
|
| Contiens les routes d'URLs racines du projet.
|
||||||
|
| On y inclus les autres fichiers d'URLs et leur namespace.
|
||||||
|
| **toolbar_debug.py**
|
||||||
|
| Contiens la configuration de la barre de debug à gauche à destination
|
||||||
|
| du site de développement.
|
||||||
|
| **et_keys/**
|
||||||
|
| Contiens la clef publique du système de paiement E-Transactions.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Ne pas mettre de configuration personnelle ni aucun mot de passe dans **settings.py**. Si il y a besoin de ce genre de chose, il faut le mettre dans **settings_custom.py** qui lui n'est pas versionné.
|
||||||
|
|
||||||
|
Le contenu d'une application
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
| /app1
|
||||||
|
| **__init__.py**
|
||||||
|
| Permet de définir le dossier comme un package Python.
|
||||||
|
| Ce fichier est généralement vide.
|
||||||
|
| **models.py**
|
||||||
|
| C'est là que les modèles sont définis. Ces classes définissent
|
||||||
|
| les tables dans la base de donnée.
|
||||||
|
| **views.py**
|
||||||
|
| C'est là où les vues sont définies.
|
||||||
|
| **admin.py**
|
||||||
|
| C'est là que l'on déclare quels modèles doivent apparaître
|
||||||
|
| dans l'interface du module d'administration de Django.
|
||||||
|
| **tests.py**
|
||||||
|
| Ce fichier contiens les tests fonctionnels, unitaires
|
||||||
|
| mais aussi d'intégrations qui sont lancés par la pipeline.
|
||||||
|
| **urls.py**
|
||||||
|
| On y défini les URLs de l'application et on les lies aux vues.
|
||||||
|
| **migrations/**
|
||||||
|
| Ce dossier sert à stocker les fichiers de migration de la base
|
||||||
|
| de données générées par la commande *makemigrations*.
|
||||||
|
| **templates/**
|
||||||
|
| Ce dossier ci contiens généralement des sous dossiers et sert
|
||||||
|
| à accueillir les templates. Les sous dossiers servent de namespace.
|
81
doc/start/translations.rst
Normal file
81
doc/start/translations.rst
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
.. _translations:
|
||||||
|
|
||||||
|
Ajouter une traduction
|
||||||
|
======================
|
||||||
|
|
||||||
|
Le code du site est entièrement écrit en anglais, le texte affiché aux utilisateurs l'est également. La traduction en français se fait ultérieurement avec un fichier de traduction. Voici un petit guide rapide pour apprendre à s'en servir.
|
||||||
|
|
||||||
|
Dans le code du logiciel
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Imaginons que nous souhaitons afficher "Hello" et le traduire en français. Voici comment signaler que ce mot doit être traduit.
|
||||||
|
|
||||||
|
Si le mot est dans le code Python :
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
help_text=_("Hello")
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
Si le mot apparaît dans le template Jinja :
|
||||||
|
|
||||||
|
.. sourcecode:: html+jinja
|
||||||
|
|
||||||
|
{# ... #}
|
||||||
|
|
||||||
|
{% trans %}Hello{% endtrans %}
|
||||||
|
|
||||||
|
{# ... #}
|
||||||
|
|
||||||
|
Générer le fichier django.po
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
La traduction se fait en trois étapes. Il faut d'abord générer un fichier de traductions, l'éditer et enfin le compiler au format binaire pour qu'il soit lu par le serveur.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
./manage.py makemessages --ignore "env/*" -e py,jinja
|
||||||
|
|
||||||
|
Éditer le fichier django.po
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. role:: python(code)
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
# locale/fr/LC_MESSAGES/django.po
|
||||||
|
|
||||||
|
# ...
|
||||||
|
msgid "Hello"
|
||||||
|
msgstr "" # Ligne à modifier
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Si les commentaires suivants apparaissent, pensez à les supprimer. Ils peuvent gêner votre traduction.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Bonjour"
|
||||||
|
|
||||||
|
|
||||||
|
Générer le fichier django.mo
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Il s'agit de la dernière étape. Un fichier binaire est généré à partir du fichier django.mo.
|
||||||
|
|
||||||
|
.. sourcecode:: bash
|
||||||
|
|
||||||
|
./manage.py compilemessages
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pensez à redémarrer le serveur si les traductions ne s'affichent pas
|
@ -20,3 +20,8 @@ python-dateutil
|
|||||||
pygraphviz
|
pygraphviz
|
||||||
sentry_sdk
|
sentry_sdk
|
||||||
# mysqlclient
|
# mysqlclient
|
||||||
|
|
||||||
|
# For documentation
|
||||||
|
Sphinx > 2.0
|
||||||
|
sphinx_rtd_theme
|
||||||
|
sphinx-copybutton
|
||||||
|
@ -577,7 +577,7 @@ SITH_EBOUTIC_HMAC_KEY = binascii.unhexlify(
|
|||||||
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
|
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
|
||||||
)
|
)
|
||||||
SITH_EBOUTIC_PUB_KEY = ""
|
SITH_EBOUTIC_PUB_KEY = ""
|
||||||
with open("./sith/et_keys/pubkey.pem") as f:
|
with open(os.path.join(os.path.dirname(__file__), "et_keys/pubkey.pem")) as f:
|
||||||
SITH_EBOUTIC_PUB_KEY = f.read()
|
SITH_EBOUTIC_PUB_KEY = f.read()
|
||||||
|
|
||||||
# Launderette variables
|
# Launderette variables
|
||||||
|
Loading…
Reference in New Issue
Block a user