mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 09:12:11 +01:00 
			
		
		
		
	Merge branch 'beta' into 'master'
Bugs mineurs, documentation See merge request bde/nk20!162
This commit is contained in:
		@@ -10,7 +10,6 @@ DJANGO_SECRET_KEY=CHANGE_ME
 | 
			
		||||
DJANGO_SETTINGS_MODULE=note_kfet.settings
 | 
			
		||||
CONTACT_EMAIL=tresorerie.bde@localhost
 | 
			
		||||
NOTE_URL=localhost
 | 
			
		||||
DOMAIN=localhost
 | 
			
		||||
 | 
			
		||||
# Config for mails. Only used in production
 | 
			
		||||
NOTE_MAIL=notekfet@localhost
 | 
			
		||||
 
 | 
			
		||||
@@ -279,7 +279,8 @@ Le cahier des charges initial est disponible [sur le Wiki Crans](https://wiki.cr
 | 
			
		||||
La documentation des classes et fonctions est directement dans le code et est explorable à partir de la partie documentation de l'interface d'administration de Django.
 | 
			
		||||
**Commentez votre code !**
 | 
			
		||||
 | 
			
		||||
La documentation plus haut niveau sur le développement est disponible sur [le Wiki associé au dépôt Git](https://gitlab.crans.org/bde/nk20/-/wikis/home).
 | 
			
		||||
La documentation plus haut niveau sur le développement et sur l'utilisation
 | 
			
		||||
est disponible sur <https://note.crans.org/doc> et également dans le dossier `docs`.
 | 
			
		||||
 | 
			
		||||
## FAQ
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,14 @@
 | 
			
		||||
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from rest_framework.serializers import ModelSerializer
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
from member.api.serializers import ProfileSerializer, MembershipSerializer
 | 
			
		||||
from note.api.serializers import NoteSerializer
 | 
			
		||||
from note.models import Alias
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserSerializer(ModelSerializer):
 | 
			
		||||
class UserSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    REST API Serializer for Users.
 | 
			
		||||
    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
 | 
			
		||||
@@ -22,7 +26,7 @@ class UserSerializer(ModelSerializer):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ContentTypeSerializer(ModelSerializer):
 | 
			
		||||
class ContentTypeSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    REST API Serializer for Users.
 | 
			
		||||
    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
 | 
			
		||||
@@ -31,3 +35,42 @@ class ContentTypeSerializer(ModelSerializer):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = ContentType
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OAuthSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    Informations that are transmitted by OAuth.
 | 
			
		||||
    For now, this includes user, profile and valid memberships.
 | 
			
		||||
    This should be better managed later.
 | 
			
		||||
    """
 | 
			
		||||
    normalized_name = serializers.SerializerMethodField()
 | 
			
		||||
 | 
			
		||||
    profile = ProfileSerializer()
 | 
			
		||||
 | 
			
		||||
    note = NoteSerializer()
 | 
			
		||||
 | 
			
		||||
    memberships = serializers.SerializerMethodField()
 | 
			
		||||
 | 
			
		||||
    def get_normalized_name(self, obj):
 | 
			
		||||
        return Alias.normalize(obj.username)
 | 
			
		||||
 | 
			
		||||
    def get_memberships(self, obj):
 | 
			
		||||
        return serializers.ListSerializer(child=MembershipSerializer()).to_representation(
 | 
			
		||||
            obj.memberships.filter(date_start__lte=timezone.now(), date_end__gte=timezone.now()))
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = User
 | 
			
		||||
        fields = (
 | 
			
		||||
            'id',
 | 
			
		||||
            'username',
 | 
			
		||||
            'normalized_name',
 | 
			
		||||
            'first_name',
 | 
			
		||||
            'last_name',
 | 
			
		||||
            'email',
 | 
			
		||||
            'is_superuser',
 | 
			
		||||
            'is_active',
 | 
			
		||||
            'is_staff',
 | 
			
		||||
            'profile',
 | 
			
		||||
            'note',
 | 
			
		||||
            'memberships',
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
from datetime import datetime, date
 | 
			
		||||
from decimal import Decimal
 | 
			
		||||
from urllib.parse import quote_plus
 | 
			
		||||
from warnings import warn
 | 
			
		||||
 | 
			
		||||
@@ -152,6 +153,8 @@ class TestAPI(TestCase):
 | 
			
		||||
                value = value.isoformat()
 | 
			
		||||
            elif isinstance(value, ImageFieldFile):
 | 
			
		||||
                value = value.name
 | 
			
		||||
            elif isinstance(value, Decimal):
 | 
			
		||||
                value = str(value)
 | 
			
		||||
            query = json.dumps({field.name: value})
 | 
			
		||||
 | 
			
		||||
            # Create sample permission
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ from django.conf import settings
 | 
			
		||||
from django.conf.urls import url, include
 | 
			
		||||
from rest_framework import routers
 | 
			
		||||
 | 
			
		||||
from .views import UserInformationView
 | 
			
		||||
from .viewsets import ContentTypeViewSet, UserViewSet
 | 
			
		||||
 | 
			
		||||
# Routers provide an easy way of automatically determining the URL conf.
 | 
			
		||||
@@ -47,5 +48,6 @@ app_name = 'api'
 | 
			
		||||
# Additionally, we include login URLs for the browsable API.
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    url('^', include(router.urls)),
 | 
			
		||||
    url('^me/', UserInformationView.as_view()),
 | 
			
		||||
    url('^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								apps/api/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								apps/api/views.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from rest_framework.generics import RetrieveAPIView
 | 
			
		||||
 | 
			
		||||
from .serializers import OAuthSerializer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserInformationView(RetrieveAPIView):
 | 
			
		||||
    """
 | 
			
		||||
    These fields are give to OAuth authenticators.
 | 
			
		||||
    """
 | 
			
		||||
    serializer_class = OAuthSerializer
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return User.objects.filter(pk=self.request.user.pk)
 | 
			
		||||
 | 
			
		||||
    def get_object(self):
 | 
			
		||||
        return self.request.user
 | 
			
		||||
							
								
								
									
										17
									
								
								apps/member/auth.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								apps/member/auth.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from cas_server.auth import DjangoAuthUser  # pragma: no cover
 | 
			
		||||
from note.models import Alias
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomAuthUser(DjangoAuthUser):  # pragma: no cover
 | 
			
		||||
    """
 | 
			
		||||
    Override Django Auth User model to define a custom Matrix username.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def attributs(self):
 | 
			
		||||
        d = super().attributs()
 | 
			
		||||
        if self.user:
 | 
			
		||||
            d["normalized_name"] = Alias.normalize(self.user.username)
 | 
			
		||||
        return d
 | 
			
		||||
							
								
								
									
										23
									
								
								apps/member/migrations/0007_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								apps/member/migrations/0007_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
# Generated by Django 2.2.19 on 2021-03-13 11:35
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('member', '0006_create_note_account_bde_membership'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='membership',
 | 
			
		||||
            name='roles',
 | 
			
		||||
            field=models.ManyToManyField(related_name='memberships', to='permission.Role', verbose_name='roles'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='profile',
 | 
			
		||||
            name='promotion',
 | 
			
		||||
            field=models.PositiveSmallIntegerField(default=2021, help_text='Year of entry to the school (None if not ENS student)', null=True, verbose_name='promotion'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										19
									
								
								apps/note/migrations/0005_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								apps/note/migrations/0005_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
# Generated by Django 2.2.19 on 2021-03-13 11:35
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('note', '0004_remove_null_tag_on_charfields'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='alias',
 | 
			
		||||
            name='note',
 | 
			
		||||
            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='alias', to='note.Note'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -134,8 +134,6 @@ class PermissionBackend(ModelBackend):
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        sess = get_current_session()
 | 
			
		||||
        if sess is not None and sess.session_key is None:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        if user_obj.is_superuser and sess.get("permission_mask", -1) >= 42:
 | 
			
		||||
            return True
 | 
			
		||||
 
 | 
			
		||||
@@ -3511,6 +3511,7 @@
 | 
			
		||||
				56,
 | 
			
		||||
				57,
 | 
			
		||||
				58,
 | 
			
		||||
				135,
 | 
			
		||||
				137,
 | 
			
		||||
				143,
 | 
			
		||||
				147,
 | 
			
		||||
@@ -3521,8 +3522,7 @@
 | 
			
		||||
				176,
 | 
			
		||||
				177,
 | 
			
		||||
				180,
 | 
			
		||||
				181,
 | 
			
		||||
				182
 | 
			
		||||
				181
 | 
			
		||||
			]
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 
 | 
			
		||||
 Submodule apps/scripts updated: 8ec7d68a16...0c7070aea1
									
								
							
							
								
								
									
										25
									
								
								apps/treasury/migrations/0003_auto_20210321_1034.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								apps/treasury/migrations/0003_auto_20210321_1034.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# Generated by Django 2.2.19 on 2021-03-21 09:34
 | 
			
		||||
 | 
			
		||||
import django.core.validators
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('treasury', '0002_invoice_remove_png_extension'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='product',
 | 
			
		||||
            name='quantity',
 | 
			
		||||
            field=models.DecimalField(decimal_places=2, max_digits=7, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Quantity'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='specialtransactionproxy',
 | 
			
		||||
            name='remittance',
 | 
			
		||||
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transaction_proxies', to='treasury.Remittance', verbose_name='Remittance'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -5,6 +5,7 @@ from datetime import date
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.core.validators import MinValueValidator
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.template.loader import render_to_string
 | 
			
		||||
@@ -131,12 +132,15 @@ class Product(models.Model):
 | 
			
		||||
        verbose_name=_("Designation"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    quantity = models.PositiveIntegerField(
 | 
			
		||||
        verbose_name=_("Quantity")
 | 
			
		||||
    quantity = models.DecimalField(
 | 
			
		||||
        decimal_places=2,
 | 
			
		||||
        max_digits=7,
 | 
			
		||||
        verbose_name=_("Quantity"),
 | 
			
		||||
        validators=[MinValueValidator(0)],
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    amount = models.IntegerField(
 | 
			
		||||
        verbose_name=_("Unit price")
 | 
			
		||||
        verbose_name=_("Unit price"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
{% load escape_tex %}
 | 
			
		||||
{% load escape_tex i18n %}
 | 
			
		||||
{% language fr %}
 | 
			
		||||
\documentclass[a4paper,11pt]{article}
 | 
			
		||||
 | 
			
		||||
\usepackage{fontspec}
 | 
			
		||||
@@ -176,3 +177,4 @@ TVA non applicable, article 293 B du CGI.
 | 
			
		||||
\end{center}
 | 
			
		||||
 | 
			
		||||
\end{document}
 | 
			
		||||
{% endlanguage %}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								apps/wei/migrations/0002_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								apps/wei/migrations/0002_auto_20210313_1235.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
# Generated by Django 2.2.19 on 2021-03-13 11:35
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('wei', '0001_initial'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='weiclub',
 | 
			
		||||
            name='year',
 | 
			
		||||
            field=models.PositiveIntegerField(default=2021, unique=True, verbose_name='year'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='weiregistration',
 | 
			
		||||
            name='information_json',
 | 
			
		||||
            field=models.TextField(default='{}', help_text='Information about the registration (buses for old members, survey for the new members), encoded in JSON', verbose_name='registration information'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								docs/_static/img/create_transaction.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/img/create_transaction.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 143 KiB  | 
@@ -114,7 +114,7 @@ Les filtres disponibles sont indiqués sur chacune des pages de documentation.
 | 
			
		||||
Le résultat est déjà par défaut filtré par droits : seuls les éléments que l'utilisateur à le droit de voir sont affichés.
 | 
			
		||||
Cela est possible grâce à la structure des permissions, générant justement des filtres de requêtes de base de données.
 | 
			
		||||
 | 
			
		||||
Une requête à l'adresse ``/api/<model>/pk/`` affiche directement les informations du modèle demandé au format JSON.
 | 
			
		||||
Une requête à l'adresse ``/api/<model>/<pk>/`` affiche directement les informations du modèle demandé au format JSON.
 | 
			
		||||
 | 
			
		||||
POST
 | 
			
		||||
~~~~
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ ne dépende pas de cette application, on procède de cette manière.
 | 
			
		||||
Graphe
 | 
			
		||||
~~~~~~
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/activity.svg
 | 
			
		||||
.. image:: ../_static/img/graphs/activity.svg
 | 
			
		||||
   :alt: Graphe de l'application activités
 | 
			
		||||
 | 
			
		||||
UI
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ Applications indispensables
 | 
			
		||||
Applications packagées
 | 
			
		||||
----------------------
 | 
			
		||||
* ``polymorphic``
 | 
			
		||||
    Utiliser pour la création de models polymorphiques (``Note`` et ``Transaction`` notamment) cf [Note](Note).
 | 
			
		||||
    Utiliser pour la création de models polymorphiques (``Note`` et ``Transaction`` notamment) cf `Note <note>`_.
 | 
			
		||||
 | 
			
		||||
    L'utilisation des models polymorphiques est détaillé sur la documentation du package:
 | 
			
		||||
    `<https://django-polymorphic.readthedocs.io/en/stable/>`_
 | 
			
		||||
 
 | 
			
		||||
@@ -48,3 +48,10 @@ Exemple de Changelog, pour la création d'une transaction de 42424242 centimes d
 | 
			
		||||
 | 
			
		||||
S'il est préférable de passer en console Postgresql pour parcourir les logs, ils sont trouvables via l'API dans
 | 
			
		||||
``/api/logs``, sous réserve d'avoir les droits suffisants (ie. être respo info).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Graphe
 | 
			
		||||
~~~~~~
 | 
			
		||||
 | 
			
		||||
.. image:: ../_static/img/graphs/logs.svg
 | 
			
		||||
  :alt: Logs graphe
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ génère en effet automatiquement une transaction de l'utilisateur vers le club
 | 
			
		||||
Graphe
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/member.svg
 | 
			
		||||
.. image:: ../_static/img/graphs/member.svg
 | 
			
		||||
   :alt: Graphe de l'application member
 | 
			
		||||
 | 
			
		||||
Adhésions
 | 
			
		||||
@@ -109,15 +109,15 @@ de fin d'adhésion.
 | 
			
		||||
 | 
			
		||||
On peut ajouter une adhésion à un utilisateur dans un club à tout non adhérent de ce club. La personne en charge
 | 
			
		||||
d'adhérer quelqu'un choisit l'utilisateur, les rôles au sein du club et la date de début d'adhésion. Cette date de
 | 
			
		||||
début d'adhésion doit se situer entre les champs ``club``.``membership_start`` et ``club``.``membership_end``,
 | 
			
		||||
si ces champs sont non nuls. Si ``club``.``parent_club`` n'est pas nul, l'utilisateur doit être membre de ce club.
 | 
			
		||||
Le montant de la cotisation est fixé en fonction du statut normalien de l'utilisateur (``club``.``membership_fee_paid``
 | 
			
		||||
centimes pour les élèves et ``club``.``membership_fee_unpaid`` centimes pour les étudiants). La date de fin est calculée
 | 
			
		||||
début d'adhésion doit se situer entre les champs ``club.membership_start`` et ``club.membership_end``,
 | 
			
		||||
si ces champs sont non nuls. Si ``club.parent_club`` n'est pas nul, l'utilisateur doit être membre de ce club.
 | 
			
		||||
Le montant de la cotisation est fixé en fonction du statut normalien de l'utilisateur (``club.membership_fee_paid``
 | 
			
		||||
centimes pour les élèves et ``club.membership_fee_unpaid`` centimes pour les étudiants). La date de fin est calculée
 | 
			
		||||
comme ce qui suit :
 | 
			
		||||
 | 
			
		||||
* Si ``club``.``membership_duration`` est non nul, alors ``date_end`` = ``date_start`` + ``club.membership_duration``
 | 
			
		||||
* Si ``club.membership_duration`` est non nul, alors ``date_end`` = ``date_start`` + ``club.membership_duration``
 | 
			
		||||
* Sinon ``club``, ``date_end`` = ``date_start`` + 424242 jours (suffisant pour tenir au moins une vie)
 | 
			
		||||
* Si ``club``.``membership_end`` est non nul, alors ``date_end`` = min(``date_end``, ``club``.``membership_end``)
 | 
			
		||||
* Si ``club.membership_end`` est non nul, alors ``date_end`` = min(``date_end``, ``club.membership_end``)
 | 
			
		||||
 | 
			
		||||
Si l'utilisateur n'est pas membre du club ``Kfet``, l'adhésion n'est pas possible si le solde disponible sur sa note est
 | 
			
		||||
insuffisant. Une fois toute ces contraintes vérifiées, l'adhésion est créée. Une transaction de type
 | 
			
		||||
@@ -127,13 +127,14 @@ Réadhésions
 | 
			
		||||
~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Pour les clubs nécessitant des adhésions (de durée limitée), il est possible de réadhérer au bout d'un an. Dès lors
 | 
			
		||||
que le jour actuel est après ``club``.``membership_start`` + 1 an, ``club``.``membership_start`` et
 | 
			
		||||
``club``.membership_end`` sont incrémentés d'un an.
 | 
			
		||||
que le jour actuel est après ``club.membership_start`` + 1 an, ``club.membership_start`` et
 | 
			
		||||
``club.membership_end`` sont incrémentés d'un an.
 | 
			
		||||
 | 
			
		||||
Il est possible de réadhérer si :
 | 
			
		||||
* ``membership``.``date_start`` <= ``today`` <= ``membership``.``date_end`` (l'adhésion en cours est valide)
 | 
			
		||||
* ``membership``.``date_start`` < ``club``.``membership_start`` (si la date de début d'adhésion du club est postérieure à la date de début d'adhésion, qui a donc été mise à jour, on a changé d'année)
 | 
			
		||||
* Il n'y a pas encore de réadhésion (pas d'adhésion au même club vérifiant ``new_membership``.``date_start`` >= ``club``.``membership_start``)
 | 
			
		||||
 | 
			
		||||
* ``membership.date_start`` <= ``today`` <= ``membership.date_end`` (l'adhésion en cours est valide)
 | 
			
		||||
* ``membership.date_start`` < ``club.membership_start`` (si la date de début d'adhésion du club est postérieure à la date de début d'adhésion, qui a donc été mise à jour, on a changé d'année)
 | 
			
		||||
* Il n'y a pas encore de réadhésion (pas d'adhésion au même club vérifiant ``new_membership.date_start`` >= ``club.membership_start``)
 | 
			
		||||
 | 
			
		||||
Un bouton ``Réadhérer`` apparaît dans la liste des adhésions si le droit est permis et si ces contraintes sont vérifiées.
 | 
			
		||||
En réadhérant, une nouvelle adhésion est créée pour l'utilisateur avec les mêmes rôles, commençant le lendemain de la
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,8 @@ Elle est disponible à l'adresse ``/note/consos/``, et l'onglet n'est visible qu
 | 
			
		||||
moins un bouton. L'affichage, comme tout le reste de la page, est géré avec Boostrap 4.
 | 
			
		||||
Les boutons que l'utilisateur a le droit de voir sont triés par catégorie.
 | 
			
		||||
 | 
			
		||||
## Sélection des consommations
 | 
			
		||||
Sélection des consommations
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
Lorsque l'utilisateur commence à taper un nom de note, un appel à l'API sur la page ``/api/note/alias`` est fait,
 | 
			
		||||
récupérant les 20 premiers aliases en accord avec la requête. Quand l'utilisateur survole un alias, un appel à la page
 | 
			
		||||
 
 | 
			
		||||
@@ -19,5 +19,6 @@ transferts/dons entre notes est détaillé sur la page `Transferts <transactions
 | 
			
		||||
Graphe
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/note.svg
 | 
			
		||||
.. image:: ../../_static/img/graphs/note.svg
 | 
			
		||||
   :width: 960
 | 
			
		||||
   :alt: Graphe de l'application note
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,8 @@ Une permission est un Model Django dont les principaux attributs sont :
 | 
			
		||||
* ``model`` : Le model sur lequel cette permission va s'appliquer
 | 
			
		||||
* ``type``  : Les différents types d'interaction sont : voir (``view``), modifier (``change``), ajouter (``add``)
 | 
			
		||||
  et supprimer (``delete``).
 | 
			
		||||
* ``query`` : Requete sur la cible, encodé en JSON, traduit en un Q object (cf [Query](#compilation-de-la-query)
 | 
			
		||||
* ``field`` : le champ cible qui pourra etre modifié. (tous les champs si vide)
 | 
			
		||||
* ``query`` : Requête sur la cible, encodé en JSON, traduit en un Q object (cf `Query <#compilation-de-la-query>`_)
 | 
			
		||||
* ``field`` : le champ cible qui pourra être modifié. (tous les champs si vide)
 | 
			
		||||
 | 
			
		||||
Pour savoir si un utilisateur a le droit sur un modèle ou non, la requête est compilée (voir ci-dessous) en un filtre
 | 
			
		||||
de requête dans la base de données, un objet de la classe ``Q`` (En SQL l'objet Q s'interprete comme tout ce qui suit
 | 
			
		||||
@@ -147,5 +147,5 @@ modifiés en comparant l'ancienne et la nouvele instance.
 | 
			
		||||
Graphe des modèles
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/permission.svg
 | 
			
		||||
.. image:: ../_static/img/graphs/permission.svg
 | 
			
		||||
   :alt: Graphe de l'application permission
 | 
			
		||||
 
 | 
			
		||||
@@ -217,5 +217,6 @@ Exemple de validation de crédit Société générale d'un étudiant non payé "
 | 
			
		||||
Diagramme des modèles
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/treasury.svg
 | 
			
		||||
   :alt: Graphe de l'application trésorerie
 | 
			
		||||
.. image:: ../_static/img/graphs/treasury.svg
 | 
			
		||||
   :width: 960
 | 
			
		||||
   :alt: Graphe de l'application trésorerie
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,8 @@ Graphe des modèles
 | 
			
		||||
 | 
			
		||||
Pour une meilleure compréhension, le graphe des modèles de l'application ``member`` ont été ajoutés au schéma.
 | 
			
		||||
 | 
			
		||||
.. image:: /_static/img/graphs/wei.svg
 | 
			
		||||
.. image:: ../_static/img/graphs/wei.svg
 | 
			
		||||
   :width: 960
 | 
			
		||||
   :alt: Graphe des modèles de l'application WEI
 | 
			
		||||
 | 
			
		||||
Fonctionnement
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
# -- Project information -----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
project = 'Note Kfet 2020'
 | 
			
		||||
copyright = '2020, BDE ENS Paris-Saclay'
 | 
			
		||||
copyright = '2020-2021, BDE ENS Paris-Saclay'
 | 
			
		||||
author = 'BDE ENS Paris-Saclay'
 | 
			
		||||
 | 
			
		||||
# The full version, including alpha/beta/rc tags
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								docs/documentation.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								docs/documentation.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
Documentation
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
La documentation est gérée grâce à Sphinx. Le thème est le thème officiel de
 | 
			
		||||
ReadTheDocs ``sphinx-rtd-theme``.
 | 
			
		||||
 | 
			
		||||
Générer localement la documentation
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
On commence par se rendre au bon endroit et installer les bonnes dépendances :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
  cd docs
 | 
			
		||||
  pip install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
La documentation se génère à partir d'appels à ``make``, selon le type de
 | 
			
		||||
documentation voulue.
 | 
			
		||||
 | 
			
		||||
Par exemple, ``make dirhtml`` construit la documentation web,
 | 
			
		||||
``make latexpdf`` construit un livre PDF avec cette documentation.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Documentation automatique
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
Ansible compile et déploie automatiquement la documentation du projet, dans
 | 
			
		||||
le rôle ``8-docs``. Le rôle installe dans le bon environnement les dépendances
 | 
			
		||||
nécessaires, puis appelle sphinx pour placer la documentation compilée dans
 | 
			
		||||
``/var/www/documentation`` :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
  /var/www/note_kfet/env/bin/sphinx-build -b dirhtml /var/www/note_kfet/docs/ /var/www/documentation/
 | 
			
		||||
 | 
			
		||||
Ce dossier est exposé par ``nginx`` sur le chemin
 | 
			
		||||
`/doc <https://note.crans.org/doc>`_.
 | 
			
		||||
							
								
								
									
										80
									
								
								docs/external_services/cas.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								docs/external_services/cas.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
Service d'Authentification Centralisé (CAS)
 | 
			
		||||
===========================================
 | 
			
		||||
 | 
			
		||||
Un `CAS <https://fr.wikipedia.org/wiki/Central_Authentication_Service>`_ est
 | 
			
		||||
déployé sur la Note Kfet. Il est accessible à l'adresse `<https://note.crans.org/cas/>`_.
 | 
			
		||||
Il a pour but uniquement d'authentifier les utilisateurs via la note et ne communique
 | 
			
		||||
que peu d'informations.
 | 
			
		||||
 | 
			
		||||
Configuration
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Le serveur CAS utilisé est implémenté grâce au paquet ``django-cas-server``. Il peut être
 | 
			
		||||
installé soit par PIP soit sur une machine Debian via
 | 
			
		||||
``apt install python3-django-cas-server``.
 | 
			
		||||
 | 
			
		||||
On ajoute ensuite ``cas_server`` aux applications Django installées. On n'oublie pas ni
 | 
			
		||||
d'appliquer les migrations (``./manage.py migrate``) ni de collecter les fichiers
 | 
			
		||||
statiques (``./manage.py collectstatic``).
 | 
			
		||||
 | 
			
		||||
On enregistre les routes dans ``note_kfet/urls.py`` :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   urlpatterns.append(
 | 
			
		||||
        path('cas/', include('cas_server.urls', namespace='cas_server'))
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
Le CAS est désormais déjà prêt à être utilisé. Toutefois, puisque l'on utilise un site
 | 
			
		||||
Django-admin personnalisé, on n'oublie pas d'enregistrer les pages d'administration :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   if "cas_server" in settings.INSTALLED_APPS:
 | 
			
		||||
       from cas_server.admin import *
 | 
			
		||||
       from cas_server.models import *
 | 
			
		||||
       admin_site.register(ServicePattern, ServicePatternAdmin)
 | 
			
		||||
       admin_site.register(FederatedIendityProvider, FederatedIendityProviderAdmin)
 | 
			
		||||
 | 
			
		||||
Enfin, on souhaite pouvoir fournir au besoin le pseudo normalisé. Pour cela, on crée une
 | 
			
		||||
classe dans ``member.auth`` :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   class CustomAuthUser(DjangoAuthUser):
 | 
			
		||||
       def attributs(self):
 | 
			
		||||
           d = super().attributs()
 | 
			
		||||
           if self.user:
 | 
			
		||||
               d["normalized_name"] = Alias.normalize(self.user.username)
 | 
			
		||||
           return d
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Puis on source ce fichier dans les paramètres :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   CAS_AUTH_CLASS = 'member.auth.CustomAuthUser'
 | 
			
		||||
 | 
			
		||||
Utilisation
 | 
			
		||||
-----------
 | 
			
		||||
Le service est accessible sur `<https://note.crans.org/cas/>`_. C'est ce lien qu'il faut
 | 
			
		||||
donner à votre application.
 | 
			
		||||
 | 
			
		||||
L'application doit néanmoins être autorisée à accéder au CAS. Pour cela, rendez-vous
 | 
			
		||||
dans Django-admin (`<https://note.crans.org/cas/admin/>`_), dans
 | 
			
		||||
``Service Central d'Authentification/Motifs de services``, ajoutez une nouvelle entrée.
 | 
			
		||||
Choisissez votre position favorite puis le nom de l'application.
 | 
			
		||||
 | 
			
		||||
Les champs importants sont les deux suivants :
 | 
			
		||||
 | 
			
		||||
* **Motif :** il s'agit d'une expression régulière qui doit reconnaitre le site voulu.
 | 
			
		||||
  Par exemple, pour autoriser Belenios (`<https://belenios.crans.org>`_), on rentrera
 | 
			
		||||
  le motif ``^https?://belenios\.crans\.org/.*$``.
 | 
			
		||||
* **Champ d'utilisateur :** C'est le pseudo que renverra le CAS. Par défaut, il s'agira
 | 
			
		||||
  du nom de note principal, mais il arrive parfois que certains sites supportent mal
 | 
			
		||||
  d'avoir des caractères UTF-8 dans le pseudo. C'est par exemple le cas de Belenios.
 | 
			
		||||
  On rentrera alors ``normalized_name`` dans ce champ, qui correspond à la version
 | 
			
		||||
  normalisée (sans accent ni espace ni aucun caractère non-ASCII) du pseudo, et qui
 | 
			
		||||
  suffit à identifier une personne.
 | 
			
		||||
 | 
			
		||||
On peut également utiliser le ``Single log out`` si besoin.
 | 
			
		||||
							
								
								
									
										28
									
								
								docs/external_services/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								docs/external_services/index.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
Applications externes
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 2
 | 
			
		||||
   :caption: Applications externes
 | 
			
		||||
 | 
			
		||||
   cas
 | 
			
		||||
   oauth2
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
   L'utilisation de la note par des services externes est actuellement en beta. Il est
 | 
			
		||||
   fort à parier que cette utilisation sera revue et améliorée à l'avenir.
 | 
			
		||||
 | 
			
		||||
Puisque la Note Kfet recense tous les comptes des adhérents BDE, les clubs ont alors
 | 
			
		||||
la possibilité de développer leurs propres applications et de les interfacer avec la
 | 
			
		||||
note. De cette façon, chaque application peut authentifier ses utilisateurs via la note,
 | 
			
		||||
et récupérer leurs adhésion, leur nom de note afin d'éventuellement faire des transferts
 | 
			
		||||
via l'API.
 | 
			
		||||
 | 
			
		||||
Deux protocoles d'authentification sont implémentées :
 | 
			
		||||
 | 
			
		||||
 * `CAS <cas>`_
 | 
			
		||||
 * `OAuth2 <oauth2>`_
 | 
			
		||||
 | 
			
		||||
À ce jour, il n'y a pas encore d'exemple d'utilisation d'application qui utilise ce
 | 
			
		||||
mécanisme, mais on peut imaginer par exemple que la Mediatek ou l'AMAP implémentent
 | 
			
		||||
ces protocoles pour récupérer leurs adhérents.
 | 
			
		||||
							
								
								
									
										133
									
								
								docs/external_services/oauth2.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								docs/external_services/oauth2.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
OAuth2
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
L'authentification `OAuth2 <https://fr.wikipedia.org/wiki/OAuth>`_ est supportée par la
 | 
			
		||||
Note Kfet. Elle offre l'avantage non seulement d'identifier les utilisateurs, mais aussi
 | 
			
		||||
de transmettre des informations à un service tiers tels que des informations personnelles,
 | 
			
		||||
le solde de la note ou encore les adhésions de l'utilisateur, en l'avertissant sur
 | 
			
		||||
quelles données sont effectivement collectées.
 | 
			
		||||
 | 
			
		||||
.. danger::
 | 
			
		||||
   L'implémentation actuelle ne permet pas de choisir quels droits on offre. Se connecter
 | 
			
		||||
   par OAuth2 offre actuellement exactement les mêmes permissions que l'on n'aurait
 | 
			
		||||
   normalement, avec le masque le plus haut, y compris en écriture.
 | 
			
		||||
 | 
			
		||||
   Faites alors très attention lorsque vous vous connectez à un service tiers via OAuth2,
 | 
			
		||||
   et contrôlez bien exactement ce que l'application fait de vos données, à savoir si
 | 
			
		||||
   elle ignore bien tout ce dont elle n'a pas besoin.
 | 
			
		||||
 | 
			
		||||
   À l'avenir, la fenêtre d'authentification pourra vous indiquer clairement quels
 | 
			
		||||
   paramètres sont collectés.
 | 
			
		||||
 | 
			
		||||
Configuration du serveur
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
On utilise ``django-oauth-toolkit``, qui peut être installé grâce à PIP ou bien via APT,
 | 
			
		||||
via le paquet ``python3-django-oauth-toolkit``.
 | 
			
		||||
 | 
			
		||||
On commence par ajouter ``oauth2_provider`` aux applications Django installées. On
 | 
			
		||||
n'oublie pas ni d'appliquer les migrations (``./manage.py migrate``) ni de collecter
 | 
			
		||||
les fichiers statiques (``./manage.py collectstatic``).
 | 
			
		||||
 | 
			
		||||
On souhaite que l'API gérée par ``django-rest-framework`` puisse être accessible via
 | 
			
		||||
l'authentification OAuth2. On adapte alors la configuration pour permettre cela :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   REST_FRAMEWORK = {
 | 
			
		||||
       'DEFAULT_AUTHENTICATION_CLASSES': [
 | 
			
		||||
           'rest_framework.authentication.SessionAuthentication',
 | 
			
		||||
           'rest_framework.authentication.TokenAuthentication',
 | 
			
		||||
           'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
 | 
			
		||||
           ...
 | 
			
		||||
       ],
 | 
			
		||||
       ...
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
On ajoute les routes dans ``urls.py`` :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   urlpatterns.append(
 | 
			
		||||
        path('o/', include('oauth2_provider.urls', namespace='oauth2_provider'))
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
L'OAuth2 est désormais prêt à être utilisé.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Configuration client
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
Contrairement au `CAS <cas>`_, n'importe qui peut en théorie créer une application OAuth2.
 | 
			
		||||
En théorie, car pour l'instant les permissions ne leur permettent pas.
 | 
			
		||||
 | 
			
		||||
Pour créer une application, il faut se rendre à la page
 | 
			
		||||
`/o/applications/ <https://note.crans.org/o/applications/>`_. Dans ``client type``,
 | 
			
		||||
rentrez ``public`` (ou ``confidential`` selon vos choix), et vous rentrerez
 | 
			
		||||
généralement ``authorization-code`` dans ``Authorization Grant Type``.
 | 
			
		||||
Le champ ``Redirect Uris`` contient une liste d'adresses URL autorisées pour des
 | 
			
		||||
redirections post-connexion.
 | 
			
		||||
 | 
			
		||||
Il vous suffit de donner à votre application :
 | 
			
		||||
 | 
			
		||||
* L'identifiant client (client-ID)
 | 
			
		||||
* La clé secrète
 | 
			
		||||
* Les scopes : sous-ensemble de ``[read, write]`` (ignoré pour l'instant, cf premier paragraphe)
 | 
			
		||||
* L'URL d'autorisation : `<https://note.crans.org/o/authorize/>`_
 | 
			
		||||
* L'URL d'obtention de jeton : `<https://note.crans.org/o/token/>`_
 | 
			
		||||
* L'URL de récupération des informations de l'utilisateur : `<https://note.crans.org/api/me/>`_
 | 
			
		||||
 | 
			
		||||
N'hésitez pas à consulter la page `<https://note.crans.org/api/me/>`_ pour s'imprégner
 | 
			
		||||
du format renvoyé.
 | 
			
		||||
 | 
			
		||||
Avec Django-allauth
 | 
			
		||||
###################
 | 
			
		||||
 | 
			
		||||
Si vous utilisez Django-allauth pour votre propre application, vous pouvez utiliser
 | 
			
		||||
le module pré-configuré disponible ici :
 | 
			
		||||
`<https://gitlab.crans.org/bde/allauth-note-kfet>`_. Pour l'installer, vous
 | 
			
		||||
pouvez simplement faire :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ pip3 install git+https://gitlab.crans.org/bde/allauth-note-kfet.git
 | 
			
		||||
 | 
			
		||||
L'installation du module se fera automatiquement.
 | 
			
		||||
 | 
			
		||||
Il vous suffit ensuite d'inclure l'application ``allauth_note_kfet`` à vos applications
 | 
			
		||||
installées (sur votre propre client), puis de bien ajouter l'application sociale :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   SOCIALACCOUNT_PROVIDERS = {
 | 
			
		||||
       'notekfet': {
 | 
			
		||||
           # 'DOMAIN': 'note.crans.org',
 | 
			
		||||
       },
 | 
			
		||||
       ...
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
Le paramètre ``DOMAIN`` permet de changer d'instance de Note Kfet. Par défaut, il
 | 
			
		||||
se connectera à ``note.crans.org`` si vous ne renseignez rien.
 | 
			
		||||
 | 
			
		||||
En créant l'application sur la note, vous pouvez renseigner
 | 
			
		||||
``https://monsite.example.com/accounts/notekfet/login/callback/`` en URL de redirection,
 | 
			
		||||
à adapter selon votre configuration.
 | 
			
		||||
 | 
			
		||||
Vous devrez ensuite enregistrer l'application sociale dans la base de données.
 | 
			
		||||
Vous pouvez passer par Django-admin, mais cela peut nécessiter d'avoir déjà un compte,
 | 
			
		||||
alors autant le faire via un shell python :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   from allauth.socialaccount.models import SocialApp
 | 
			
		||||
   SocialApp.objects.create(
 | 
			
		||||
           name="Note Kfet",
 | 
			
		||||
           provider="notekfet",
 | 
			
		||||
           client_id="VOTRECLIENTID",
 | 
			
		||||
           secret="VOTRESECRET",
 | 
			
		||||
           key="",
 | 
			
		||||
   )
 | 
			
		||||
 | 
			
		||||
Si vous avez bien configuré ``django-allauth``, vous êtes désormais prêts par à vous
 | 
			
		||||
connecter via la note :) Par défaut, nom, prénom, pseudo et adresse e-mail sont
 | 
			
		||||
récupérés. Les autres données sont stockées mais inutilisées.
 | 
			
		||||
							
								
								
									
										208
									
								
								docs/faq.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								docs/faq.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,208 @@
 | 
			
		||||
Foire aux questions
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
Des transactions anormales sont apparues sur mon compte.
 | 
			
		||||
--------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Tu dois immédiatement contacter les trésoriers du BDE (voir ci-dessous) pour
 | 
			
		||||
   signaler l'incident. Précise bien ton nom de note, l'heure de la transaction
 | 
			
		||||
   ainsi que l'alias utilisé pour faire la transaction (en plaçant ta souris sur
 | 
			
		||||
   ton pseudo sur la ligne de transaction, l'alias utilisé apparaît). La raison
 | 
			
		||||
   la plus courante est que tu as un alias qui est trop proche d'un autre d'une
 | 
			
		||||
   autre personne. Même si la Note Kfet 2020 essaie d'éviter ça, tu es invité⋅e
 | 
			
		||||
   à supprimer l'alias problématique, ou tout du moins t'assurer que la confusion
 | 
			
		||||
   ne puisse plus arriver.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je souhaite consommer mais le solde de ma note est insuffisant
 | 
			
		||||
--------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Le BDE ne fait pas crédit à ses adhérents. Il est de ton devoir de t'assurer
 | 
			
		||||
   d'avoir en permanence un solde positif sur ta note. Les permanenciers à la
 | 
			
		||||
   Kfet ont la possibilité de refuser une consommation qui fait passer en négatif,
 | 
			
		||||
   et ont obligation de refuser si la consommation est alcoolisée, en accord avec
 | 
			
		||||
   la règlementation en vigueur.
 | 
			
		||||
 | 
			
		||||
   Les trésoriers connaissent la liste des personnes en situation irrégulière et
 | 
			
		||||
   n'hésiteront pas à faire des rappels pour recharger la note.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Comment recharger ma note ?
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Le solde de la note peut être rechargé soit par espèces, par chèque à l'ordre
 | 
			
		||||
   de l'amicale des élèves de l'ENS Cachan, par carte bancaire via un terminal
 | 
			
		||||
   de paiement électronique ou encore par virement bancaire, dont les coordonnées
 | 
			
		||||
   sont à demander auprès des trésoriers BDE.
 | 
			
		||||
 | 
			
		||||
   Les trois premières options sont à faire directement dans la Kfet.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je pars en stage / en vacances. Puis-je bloquer ma note ?
 | 
			
		||||
---------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Bien sûr : il te suffit de te rendre sur ton compte et de cliquer sur le bouton
 | 
			
		||||
   dédié. Ta note ne sera plus affichée par les autres personnes et les transferts
 | 
			
		||||
   seront impossibles, sauf pour les trésoriers BDE et respo info.
 | 
			
		||||
 | 
			
		||||
   Il est toutefois de ton devoir de rembourser tout ce que tu dois.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Quelle est la limite maximale au nombre d'alias d'une note ?
 | 
			
		||||
------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Certains parlent d'une dizaine d'alias par note.
 | 
			
		||||
 | 
			
		||||
   Sois conscient⋅e qu'ajouter des alias ne peut qu'augmenter la probabilité de
 | 
			
		||||
   collisions avec une autre note, et peut aussi retarder la livraison de ta
 | 
			
		||||
   commande lors d'un perm bouffe.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je suis trésorier d'un club, qu'ai-je le droit de faire ?
 | 
			
		||||
---------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Être trésorier d'un club donne la responsabilité de gérer la trésorerie du
 | 
			
		||||
   club, et donc de gérer sa note. Vous obtenez donc le droit d'effectuer
 | 
			
		||||
   n'importe quelle transaction via la note en provenance ou à destination de
 | 
			
		||||
   la note de votre club. Vous pouvez également gérer les adhésions de votre club,
 | 
			
		||||
   en permettant à n'importe quel adhérent BDE de rejoindre votre club, en prélevant
 | 
			
		||||
   d'éventuels frais d'adhésion. Les paramètres du club peuvent être également modifiés.
 | 
			
		||||
 | 
			
		||||
.. danger::
 | 
			
		||||
   Avoir des droits sur la Note Kfet ne signifie pas que vous devez les utiliser.
 | 
			
		||||
   Chaque opération nécessitant des droits doit être fait pour une bonne raison,
 | 
			
		||||
   et doit avoir un lien avec votre club. Vous n'avez par exemple pas le droit
 | 
			
		||||
   d'aller récupérer des informations personnelles d'adhérents pour une raison
 | 
			
		||||
   personnelle. En revanche, faire le lien entre nom/prénom et nom de note est
 | 
			
		||||
   bien sûr permis pour faciliter des transferts. Tout abus de droits constaté
 | 
			
		||||
   pourra mener à des sanctions prises par le bureau du BDE.
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
   Une fonctionnalité pour permettre de gérer plus proprement les remboursements
 | 
			
		||||
   entre amis est en cours de développement. Temporairement et pour des raisons
 | 
			
		||||
   de confort, les trésoriers de clubs ont le droit de prélever n'importe quelle
 | 
			
		||||
   adhérente vers n'importe quelle autre note adhérente, tant que la source ne
 | 
			
		||||
   descend pas sous ``- 50 €``. Ces droits seront retirés d'ici quelques semaines.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je suis trésorier d'un club, je n'arrive pas à voir le solde du club / faire des transactions
 | 
			
		||||
---------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   As-tu bien vérifié que tu t'es connecté⋅e initialement avec tous tes droits ?
 | 
			
		||||
   Sinon, si tes droits sont tout récents, tu dois te déconnecter et te reconnecter
 | 
			
		||||
   pour que tes droits soient bien pris en compte.
 | 
			
		||||
 | 
			
		||||
   La Note permet de se connecter avec différents filtres de permission afin de
 | 
			
		||||
   pouvoir prêter son ordinateur avec une session ouverte pour faire quelques
 | 
			
		||||
   opérations en empêchant l'accès à des opérations trop sensibles.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je suis trésorier d'un club. Puis-je créer un bouton ?
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Oui bien sûr ! Tant qu'il redirige bien vers la note de ton club.
 | 
			
		||||
 | 
			
		||||
   Pour cela, rends-toi à la page `</note/buttons/>`_ pour afficher la liste des
 | 
			
		||||
   boutons, puis tu auras accès à l'interface pour créer un bouton. Une fois le
 | 
			
		||||
   bouton créé, il apparaîtra dans l'onglet ``Consommations``.
 | 
			
		||||
 | 
			
		||||
   Il faut noter que tant qu'il n'y a pas de boutons visibles pour ton club, tu
 | 
			
		||||
   n'auras pas accès à l'interface de consommations, et tu devras nécessairement
 | 
			
		||||
   cliquer sur le lien ci-dessus pour accéder à l'interface d'édition des boutons.
 | 
			
		||||
   Une fois qu'un bouton pour ton club est visible, l'interface consommations
 | 
			
		||||
   devient accessible.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Après passation, je suis trésorier d'un club. Comment récupérer mes droits note ?
 | 
			
		||||
---------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Tu dois pour cela contacter les trésoriers BDE (voir ci-dessous). Ils vous
 | 
			
		||||
   expliqueront en détails vos droits et vos interdits et vous donneront les
 | 
			
		||||
   droits requis.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je souhaite contacter un trésorier
 | 
			
		||||
----------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   Pour contacter un trésorier, il te suffit d'envoyer un mail à l'adresse
 | 
			
		||||
   `tresorerie.bde@lists.crans.org <tresorerie.bde@lists.crans.org>`_. Pense bien
 | 
			
		||||
   à donner ton nom de note, voire à envoyer un scan de ta carte d'identité si ta
 | 
			
		||||
   demande concerne un virement entre le compte du BDE et ton propre compte.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
J'ai trouvé un bug, comment le signaler ?
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   La Note Kfet est développée bénévolement par des membres du BDE. Malgré tous nos
 | 
			
		||||
   efforts pour fournir une plateforme sans erreur et la plus ergonomique possible.
 | 
			
		||||
   Toutefois, il n'est évidemment pas exclu que des bugs soient présents :)
 | 
			
		||||
 | 
			
		||||
   Pour nous soumettre un bug, tu peux envoyer un mail à
 | 
			
		||||
   `notekfet2020@lists.crans.org <notekfet2020@lists.crans.org>`_
 | 
			
		||||
 | 
			
		||||
   Tu peux sinon ouvrir une issue sur `Gitlab <https://gitlab.crans.org/bde/nk20>`_.
 | 
			
		||||
 | 
			
		||||
   N'hésite pas à venir en discuter avec nous à la Kfet, ou bien sur
 | 
			
		||||
   `l'IRC du Crans <https://irc.crans.org/web>`_ sur le canal ``#note`` !
 | 
			
		||||
 | 
			
		||||
   Le même processus s'applique en cas de demande de fonctionnalités.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Je souhaite contribuer
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   La Note Kfet est essentiellement développée par des responsables informatiques du
 | 
			
		||||
   BDE de l'ENS Paris-Saclay. Toutefois, si vous souhaitez contribuer, vous pouvez
 | 
			
		||||
   bien sûr le faire en accord avec la licence GPLv3 avec laquelle la Note Kfet est
 | 
			
		||||
   distribuée. Pour cela, si vous êtes adhérent Crans, vous pouvez proposer une
 | 
			
		||||
   demande de fusion de votre code. Si ce n'est pas le cas, vous pouvez envoyer un
 | 
			
		||||
   mail à `notekfet2020@lists.crans.org <notekfet2020@lists.crans.org>`_.
 | 
			
		||||
   Dans les deux cas, merci de rejoindre le canal ``#note`` sur IRC :)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Contributeurs
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   La version 2020 de la Note Kfet a été développée sous le mandat de la
 | 
			
		||||
   Saper[list]popette. Son développement a commencé à l'été 2019. Après un mois de beta
 | 
			
		||||
   à l'été 2020, son déploiement en production s'est fait le samedi 5 septembre 2020.
 | 
			
		||||
 | 
			
		||||
   Elle succède à presque 6 années de la
 | 
			
		||||
   `Note Kfet 2015 <https://wiki.crans.org/NoteKfet/NoteKfet2015>`_, alors en production
 | 
			
		||||
   depuis le 6 octobre 2014.
 | 
			
		||||
 | 
			
		||||
   Liste des contributeurs majeurs, par ordre alphabétique :
 | 
			
		||||
 | 
			
		||||
   * Pierre-André « PAC » COMBY
 | 
			
		||||
   * Yohann « ÿnérant » D'ANELLO
 | 
			
		||||
   * Benjamin « esum » GRAILLOT
 | 
			
		||||
   * Alexandre « erdnaxe » IOOSS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Hébergement
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
   En accord entre de l'ENS Paris-Saclay et le Crans, l'instance de production présente
 | 
			
		||||
   sur `<https://note.crans.org/>`_ est hébergée sur l'un des serveurs du Crans.
 | 
			
		||||
   Les données sont hébergées à l'adresse :
 | 
			
		||||
 | 
			
		||||
   .. code::
 | 
			
		||||
 | 
			
		||||
      Association Crans
 | 
			
		||||
      ENS Paris-Saclay
 | 
			
		||||
      4 Avenue des Sciences
 | 
			
		||||
      91190 Gif-sur-Yvette
 | 
			
		||||
							
								
								
									
										115
									
								
								docs/getting_started.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								docs/getting_started.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
La note, c'est quoi ?
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
La Note Kfet est un porte-monnaie virtuel proposé gratuitement à tous les adhérents BDE.
 | 
			
		||||
C'est le moyen de paiement privilégié au sein du campus, que ce soit pour payer des
 | 
			
		||||
activités du BDE, ou bien pour faire des remboursements entre amis. La note contient
 | 
			
		||||
également la base d'adhérents du BDE et contient de nombreux outils facilitant la vie
 | 
			
		||||
des différents bureaux de clubs, en particulier les trésoriers et surtout les trésoriers
 | 
			
		||||
BDE.
 | 
			
		||||
 | 
			
		||||
La Note Kfet est accessible à l'adresse `<https://note.crans.org>`_. La version actuelle
 | 
			
		||||
a été développée par le BDE 2020-2021, et est maintenue par les respos infos du BDE de
 | 
			
		||||
l'ENS Paris-Saclay.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Fonctionnement général de la note
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
C'est quoi une note ?
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Chaque adhérent⋅e BDE dispose d'un compte appelé « note », créé lors de son adhésion.
 | 
			
		||||
Une note est associée à un solde en euros, et à un pseudo appelé « nom de note ».
 | 
			
		||||
Le solde associé à la note correspond au solde de l'adhérent⋅e, avec lequel il est
 | 
			
		||||
possible de payer tout ce qui est en lien avec le BDE. Le nom de note suffit à
 | 
			
		||||
identifier une personne, et il suffit par exemple de donner ce nom à un permanencier
 | 
			
		||||
à la Kfet pour acheter un produit.
 | 
			
		||||
 | 
			
		||||
Faire une transaction
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Tout⋅e adhérent⋅e peut faire une transaction de sa note vers n'importe quelle note
 | 
			
		||||
d'un⋅e autre adhérent⋅e, pourvu que le montant de la transaction n'excède pas son
 | 
			
		||||
propre solde. Pour cela, il suffit d'aller sur la page de transferts, qui est la
 | 
			
		||||
page par défaut après connexion : `<https://note.crans.org/note/transfer/>`_
 | 
			
		||||
Le formulaire pour effectuer un transfert apparaît alors. En cliquant sur le bouton
 | 
			
		||||
« Je suis l'émetteur », le champ « Émetteurs » est directement complété avec votre
 | 
			
		||||
propre note. Il vous suffit alors de remplir le champ « Destinataires » avec le ou
 | 
			
		||||
les noms de note que vous voulez créditer, de spécifier le montant et la raison de
 | 
			
		||||
votre transfert, puis de cliquer sur le bouton « Virement ». Après quelques secondes,
 | 
			
		||||
si votre solde est suffisant et que la transaction est acceptée, un message de
 | 
			
		||||
confirmation apparaîtra et la transaction apparaîtra dans l'historique ci-dessous.
 | 
			
		||||
 | 
			
		||||
.. image:: _static/img/create_transaction.png
 | 
			
		||||
   :alt: Créer une transaction
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Consulter ses données personnelles
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
La Note Kfet sert non seulement à faire des transactions d'argent virtuel au sein
 | 
			
		||||
du BDE, mais aussi à permettre au BDE et à ses clubs de gérer leurs adhérents.
 | 
			
		||||
À cet effet, diverses informations personnelles sont collectées par la Note.
 | 
			
		||||
 | 
			
		||||
Pour accéder à votre compte, une fois connecté⋅e, rendez-vous dans le menu en haut
 | 
			
		||||
à droite où se trouve votre pseudo. Votre solde est par ailleurs affiché à côté
 | 
			
		||||
de votre pseudo.
 | 
			
		||||
 | 
			
		||||
L'interface est divisée en trois parties :
 | 
			
		||||
 | 
			
		||||
 * Vos données personnelles dans la partie de gauche
 | 
			
		||||
 * Vos adhésions actives (si existantes) dans la partie haute
 | 
			
		||||
 * Vos transactions récentes dans la partie basse
 | 
			
		||||
 | 
			
		||||
Vous pouvez modifier vos données personnelles que la Note possède sur vous en
 | 
			
		||||
cliquant à tout moment sur le bouton « Modifier le profil ». Les informations
 | 
			
		||||
présentes sont :
 | 
			
		||||
 | 
			
		||||
 * Nom
 | 
			
		||||
 * Prénom
 | 
			
		||||
 * Pseudo
 | 
			
		||||
 * Adresse e-mail
 | 
			
		||||
 * Numéro de téléphone
 | 
			
		||||
 * Section
 | 
			
		||||
 * Département
 | 
			
		||||
 * Promotion
 | 
			
		||||
 * Adresse
 | 
			
		||||
 * Élève/étudiant
 | 
			
		||||
 * Inscription aux listes de diffusion du BDE, du BDA et du BDS
 | 
			
		||||
 | 
			
		||||
Les trois premières informations sont obligatoires pour pouvoir vous contacter
 | 
			
		||||
et pouvoir tenir un registre d'adhérent.
 | 
			
		||||
 | 
			
		||||
Le numéro de téléphone et l'adresse ne sont utilisés uniquement en cas d'urgence,
 | 
			
		||||
notamment en cas de WEI, et ne sont pas des champs obligatoires. De plus,
 | 
			
		||||
promotion, département et section ne sont utilisés sérieusement que en cas
 | 
			
		||||
de WEI, et ne sont pas utilisés sinon.
 | 
			
		||||
 | 
			
		||||
La distinction élève/étudiant permet de distinguer les achats qui peuvent avoir
 | 
			
		||||
des prix différents pour les élèves et pour les étudiants, notamment en cas de
 | 
			
		||||
transferts d'argent, de WEI ou d'adhésion à certains clubs.
 | 
			
		||||
 | 
			
		||||
Hormis le pseudo, toutes ces informations ont un caractère confidentiel qui les
 | 
			
		||||
rend privées et inaccessible aux utilisateurs. Les trésoriers BDE et les respos
 | 
			
		||||
info ont accès à toutes les informations (en cas de besoin uniquement, le cas
 | 
			
		||||
contraire est considéré comme de l'abus de droit qui est punissable), et les
 | 
			
		||||
trésoriers de club ont accès au nom et au prénom afin de faciliter l'association
 | 
			
		||||
à un nom de note.
 | 
			
		||||
 | 
			
		||||
Dans la partie informations personnelles, il est également possible de modifier
 | 
			
		||||
la liste de ses alias (voir la section sur les alias), et de voir son propre
 | 
			
		||||
solde. Il est enfin possible de modifier l'image associée à la note, qui n'a
 | 
			
		||||
quant à elle pas de caractère privée puisqu'elle est affichée à chaque recherche
 | 
			
		||||
de nom de note.
 | 
			
		||||
 | 
			
		||||
Le tableau des adhésions actives sur la partie du haut contient l'ensemble des
 | 
			
		||||
clubs auxquels vous êtes adhérent⋅es, avec les dates de début, de fin, votre
 | 
			
		||||
rôle au sein du club (généralement simple membre, mais cela peut également
 | 
			
		||||
être trésorier⋅ère par exemple) ainsi que la cotisation que vous avez éventuellement
 | 
			
		||||
payée au club.
 | 
			
		||||
 | 
			
		||||
L'historique des transactions contient l'ensemble des transactions qui ont fait
 | 
			
		||||
intervenir votre note, triées par date décroissante. Il est possible en cliquant
 | 
			
		||||
sur le lien « Historique des transactions » d'avoir un meilleur aperçu, notamment
 | 
			
		||||
pour pouvoir filtrer des transactions.
 | 
			
		||||
@@ -2,8 +2,9 @@ Documentation de la Note Kfet 2020
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Bienvenue sur le Wiki de la NoteKfet2020. Ce wiki est plutot orienté vers un public de développeur, qui souhaitent
 | 
			
		||||
contribuer au développement, mais expliquent également aux plus curieux comment fonctionne la NoteKfet2020 sous le capot.
 | 
			
		||||
Bienvenue sur la documentation de la Note Kfet 2020. Cette documentation est à la fois
 | 
			
		||||
destinée aux adhérents BDE pour découvrir le fonctionnement de la note, mais aussi aux
 | 
			
		||||
respos info qui souhaitent découvrir comment fonctionne la note sous le capot.
 | 
			
		||||
 | 
			
		||||
Des informations complémentaires sont également disponibles sur le `Wiki Crans <https://wiki.crans.org/NoteKfet/NoteKfet2020/>`_.
 | 
			
		||||
 | 
			
		||||
@@ -11,4 +12,11 @@ Des informations complémentaires sont également disponibles sur le `Wiki Crans
 | 
			
		||||
   :maxdepth: 2
 | 
			
		||||
   :caption: Développement de la NK20
 | 
			
		||||
 | 
			
		||||
   getting_started
 | 
			
		||||
   apps/index
 | 
			
		||||
   install-dev
 | 
			
		||||
   install
 | 
			
		||||
   documentation
 | 
			
		||||
   scripts
 | 
			
		||||
   faq
 | 
			
		||||
   external_services/index
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										169
									
								
								docs/install-dev.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								docs/install-dev.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
Installer la Note Kfet sur sa propre machine
 | 
			
		||||
============================================
 | 
			
		||||
 | 
			
		||||
Jamais en production tu ne coderas.
 | 
			
		||||
 | 
			
		||||
Pour pouvoir développer sur la Note, il est donc essentiel de pouvoir installer
 | 
			
		||||
localement une instance de la note, avec une base de données vierge et indépendante
 | 
			
		||||
de celle utilisée en production.
 | 
			
		||||
 | 
			
		||||
Toutes les dépendances Python seront installées dans un environnement virtuel,
 | 
			
		||||
afin de ne pas polluer sa machine de dépendances de la note.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Dépendances de base
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
On a néanmoins besoin de dépendances de base.
 | 
			
		||||
 | 
			
		||||
Sur un Ubuntu/Debian :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt update
 | 
			
		||||
   $ sudo apt install --no-install-recommends -y \
 | 
			
		||||
       python3-setuptools python3-venv python3-dev \
 | 
			
		||||
       texlive-xetex gettext libjs-bootstrap4 fonts-font-awesome git
 | 
			
		||||
 | 
			
		||||
Pour Arch Linux :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo pacman -Sy python-setuptools python-virtualenv \
 | 
			
		||||
       texlive-most gettext git
 | 
			
		||||
 | 
			
		||||
Bootstrap 4 n'est pas dans les paquets officiels de Arch Linux, mais peut-être
 | 
			
		||||
trouvé dans l'AUR grâce au paquet ``bootstrap``. Néanmoins, il faut pour l'instant
 | 
			
		||||
penser à créer un lien symbolique :
 | 
			
		||||
``sudo ln -s /usr/share/javascript/bootstrap /usr/share/javascript/bootstrap4``.
 | 
			
		||||
 | 
			
		||||
Néanmoins, font-awesome n'est pas disponible dans les paquets Arch Linux, mais non
 | 
			
		||||
essentiel en développement (n'ajoute que les symbole à côté des boutons).
 | 
			
		||||
 | 
			
		||||
À noter que bootstrap et texlive sont optionnels également selon vos besoins.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Téléchargement de la note
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
On récupère le dépôt Git de la note :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ git clone git@gitlab.crans.org:bde/nk20.git
 | 
			
		||||
   Clonage dans 'nk20'...
 | 
			
		||||
   remote: Enumerating objects: 203, done.
 | 
			
		||||
   remote: Counting objects: 100% (203/203), done.
 | 
			
		||||
   remote: Compressing objects: 100% (125/125), done.
 | 
			
		||||
   remote: Total 13438 (delta 98), reused 170 (delta 74), pack-reused 13235
 | 
			
		||||
   Réception d\'objets: 100% (13438/13438), 9.39 Mio | 5.50 Mio/s, fait.
 | 
			
		||||
   Résolution des deltas: 100% (9028/9028), fait.
 | 
			
		||||
   $ cd nk20
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   Pour apprendre à utiliser Git, on peut regarder la page wiki dédiée :
 | 
			
		||||
   `<https://wiki.crans.org/WikiInformatique/HowToGit>`_,
 | 
			
		||||
   ou bien regarder les séminaires Crans dédiés :
 | 
			
		||||
   `<https://wiki.crans.org/CransTechnique/CransApprentis/SeminairesTechniques>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Création d'un environnement virtuel Python
 | 
			
		||||
------------------------------------------
 | 
			
		||||
 | 
			
		||||
Une fois le projet cloné, on peut créer un environnement virtuel qui contiendra
 | 
			
		||||
toutes les dépendances Python.
 | 
			
		||||
 | 
			
		||||
Pour cela, on peut simplement faire :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ python3 -m venv env
 | 
			
		||||
   $ source env/bin/activate
 | 
			
		||||
   (env) $
 | 
			
		||||
 | 
			
		||||
À noter que ``source`` peut s'abbréger par ``.`` uniquement.
 | 
			
		||||
 | 
			
		||||
Vous êtes donc dans un environnement virtuel Python. Pour installer les dépendances
 | 
			
		||||
de la note :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   (env) $ pip install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
Les dépendances s'installeront ensuite dans le dossier ``env``.
 | 
			
		||||
 | 
			
		||||
Au besoin, l'environnement peut être quitté en tapant ``deactivate`` et rejoint en
 | 
			
		||||
resourçant ``env/bin/activate``.
 | 
			
		||||
 | 
			
		||||
Plus d'informations sur les environnements virtuels dans la documentation officielle
 | 
			
		||||
de Python : `<https://docs.python.org/fr/3/tutorial/venv.html>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Lancement de la note
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
La partie Python (qui peut s'appliquer au développement de n'importe quel projet
 | 
			
		||||
Python) est terminée, on peut commencer à s'occuper de Django.
 | 
			
		||||
 | 
			
		||||
Pour rappel, Django est un cadre de développement web open source en Python extrêment
 | 
			
		||||
puissant. Il a pour but de rendre le développement web simple et rapide.
 | 
			
		||||
 | 
			
		||||
La documentation officielle de Django, complète, excellente et même en français,
 | 
			
		||||
peut être trouvée ici : `<https://docs.djangoproject.com/fr/>`_.
 | 
			
		||||
 | 
			
		||||
Pour lancer un serveur de développement, on peut donc commencer par compiler les
 | 
			
		||||
traductions :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   (env) $ ./manage.py compilemessages
 | 
			
		||||
 | 
			
		||||
On applique les migrations de la base de données (de test, qui sera créée) :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   (env) $ ./manage.py migrate
 | 
			
		||||
 | 
			
		||||
On importe quelques données de base et utiles :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   (env) $ ./manage.py loaddata initial
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   Ces données sont stockées au format JSON dans les différents fichiers
 | 
			
		||||
   ``apps/{app}/fixtures/initial.json``.
 | 
			
		||||
 | 
			
		||||
Enfin, on peut lancer le serveur web de développement :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   (env) $ ./manage.py runserver
 | 
			
		||||
   Watching for file changes with StatReloader
 | 
			
		||||
   Performing system checks...
 | 
			
		||||
 | 
			
		||||
   System check identified no issues (0 silenced).
 | 
			
		||||
   April 15, 2021 - 15:14:37
 | 
			
		||||
   Django version 2.2.20, using settings 'note_kfet.settings'
 | 
			
		||||
   Starting development server at http://127.0.0.1:8000/
 | 
			
		||||
   Quit the server with CONTROL-C.
 | 
			
		||||
 | 
			
		||||
Ouvrez votre navigateur, tapez `<http://localhost:8000/>`_, enjoy :)
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   En lançant le serveur web de la sorte, Django va recevoir un signal dès lors qu'un
 | 
			
		||||
   fichier a été modifié. Vous n'avez donc pas besoin de redémarrer le serveur après
 | 
			
		||||
   chaque modification, sauf erreurs.
 | 
			
		||||
 | 
			
		||||
   Attention : ce serveur n'est destiné qu'à des fins de développement et n'est pas
 | 
			
		||||
   optimisé pour recevoir des requêtes en parallèle ou être utilisé en production.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Créer un super-utilisateur
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
La commande ``./manage.py createsuperuser`` vous permettra de créer un super-utilisateur
 | 
			
		||||
initial.
 | 
			
		||||
							
								
								
									
										640
									
								
								docs/install.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										640
									
								
								docs/install.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,640 @@
 | 
			
		||||
Installer la Note Kfet en production
 | 
			
		||||
====================================
 | 
			
		||||
 | 
			
		||||
Cette page détaille comment installer la Note Kfet sur un serveur de production,
 | 
			
		||||
dédié uniquement à l'utilisation de la note. On supposera que le serveur tourne
 | 
			
		||||
avec un Debian Buster à jour.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Ajout des dépôts buster-backports
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
Debian c'est bien, c'est stable, mais les paquets sont vite obsolètes.
 | 
			
		||||
En particulier, la version stable de Django dans la version stable de Debian est la
 | 
			
		||||
version 1.11, qui n'est plus maintenue par Django depuis déjà quelques mois.
 | 
			
		||||
Les versions stables de Django sont les versions 2.2 et 3.2, Debian Bullseye
 | 
			
		||||
utilisant la version 2.2.
 | 
			
		||||
 | 
			
		||||
Afin de permettre à ses utilisateurs d'utiliser les dernières fonctionnalités de
 | 
			
		||||
certains paquets, Debian a créé une distribution particulière, appelée
 | 
			
		||||
``buster-backports``. Cette distribution contient des paquets de la distribution
 | 
			
		||||
à venir « ``testing`` » (``bullseye`` à l'heure où cette documentation est écrite)
 | 
			
		||||
recompilés et réadapter pour fonctionner avec les paquets de la distribution stable
 | 
			
		||||
(``buster``). Ce qui nous intéresse est de pouvoir récupérer Django 2.2 depuis
 | 
			
		||||
cette distribution, et avoir donc une version maintenue de Django.
 | 
			
		||||
 | 
			
		||||
Plus de détails sur le wiki de Debian : `<https://wiki.debian.org/fr/Backports>`_.
 | 
			
		||||
 | 
			
		||||
Pour activer les backports, il suffit d'ajouter dans le fichier ``/etc/apt/sources.list`` :
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
   deb     $MIRROR/debian buster-backports main contrib
 | 
			
		||||
 | 
			
		||||
où ``$MIRROR`` est votre miroir Debian favori, comme ``http://ftp.debian.org`` ou
 | 
			
		||||
``http://mirror.crans.org`` pour ce qui est de la version utilisée en production au BDE
 | 
			
		||||
sur les serveurs du Crans. Il suffit ensuite de faire un ``sudo apt update``.
 | 
			
		||||
Vérifiez que les paquets sont bien récupérés, en cherchant cette ligne :
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
   Get:4 http://mirror.crans.org/debian buster-backports InRelease [46.7 kB]
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
   Avis aux futurs respos info : pensez à bien actualiser cette documentation lorsque
 | 
			
		||||
   Debian Bullseye sera sorti. En particulier, il ne sera pas déconnant de continuer
 | 
			
		||||
   à utiliser non pas buster-backports mais bullseye-backports pour installer la
 | 
			
		||||
   note avec Django 3.2 et non Django 2.2.
 | 
			
		||||
 | 
			
		||||
   Bien sûr, vous testerez sur un serveur qui n'est pas celui utilisé avant :)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Installation des dépendances nécessaires
 | 
			
		||||
----------------------------------------
 | 
			
		||||
 | 
			
		||||
On s'efforce pour récupérer le plus possible de dépendances via les paquets Debian
 | 
			
		||||
plutôt que via ``pip`` afin de faciliter les mises à jour et avoir une installation
 | 
			
		||||
plus propre. On peut donc installer tout ce dont on a besoin, depuis buster-backports :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt update
 | 
			
		||||
   $ sudo apt install -t buster-backports --no-install-recommends \
 | 
			
		||||
       gettext git ipython3 \  # Dépendances basiques
 | 
			
		||||
       fonts-font-awesome libjs-bootstrap4 \  # Pour l'affichage web
 | 
			
		||||
       python3-bs4 python3-django python3-django-crispy-forms python3-django-extensions \
 | 
			
		||||
       python3-django-filters python3-django-oauth-toolkit python3-django-polymorphic \
 | 
			
		||||
       python3-djangorestframework python3-memcache python3-phonenumbers \
 | 
			
		||||
       python3-pil python3-pip python3-psycopg2 python3-setuptools python3-venv \
 | 
			
		||||
       texlive-xetex memcached
 | 
			
		||||
 | 
			
		||||
Ces paquets fournissent une bonne base sur laquelle travailler.
 | 
			
		||||
 | 
			
		||||
Pour les mettre à jour, il suffit de faire ``sudo apt update`` puis ``sudo apt upgrade``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Téléchargement de la note
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
Tout comme en développement, on utilise directement le Gitlab du Crans pour récupérer
 | 
			
		||||
les sources.
 | 
			
		||||
 | 
			
		||||
On suppose que l'on veut cloner le projet dans le dossier ``/var/www/note_kfet``.
 | 
			
		||||
 | 
			
		||||
On clone donc le dépôt en tant que ``www-data`` :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo -u www-data git clone https://gitlab.crans.org/bde/nk20.git /var/www/note_kfet
 | 
			
		||||
 | 
			
		||||
Par défaut, le dépôt est configuré pour suivre la branche ``master``, qui est la branche
 | 
			
		||||
stable, notamment installée sur `<https://note.crans.org/>`_. Pour changer de branche,
 | 
			
		||||
notamment passer sur la branche ``beta`` sur un serveur de pré-production (un peu comme
 | 
			
		||||
`<https://note-dev.crans.org/>`_), on peut faire :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo -u www-data git checkout beta
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
   Avis aux successeurs : notamment pour le serveur de production derrière
 | 
			
		||||
   `<https://note.crans.org>`_, il peut être intéressant de créer un paquet Python
 | 
			
		||||
   de sorte à pouvoir installer la note en faisant directement
 | 
			
		||||
   ``pip install git+https://gitlab.crans.org/bde/nk20.git``, et avoir ainsi une
 | 
			
		||||
   installation plus propre en décourageant le développement en production.
 | 
			
		||||
 | 
			
		||||
   Voir par exemple comment le futur site d'inscription du Crans, Constellation,
 | 
			
		||||
   gère cela : `<https://gitlab.crans.org/nounous/constellation>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Installation des dépendances Python non présentes dans les dépôts APT
 | 
			
		||||
---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Même s'il est préférable d'installer les dépendances Python via les paquets APT,
 | 
			
		||||
tous ne sont malheureusement pas disponibles.
 | 
			
		||||
 | 
			
		||||
On doit donc récupérer les dépendances manquantes via pip.
 | 
			
		||||
 | 
			
		||||
Tout comme en développement, on préfère avoir un environnement virtuel dédié,
 | 
			
		||||
les ``sudo pip`` étant rarement compatibles avec les dépendances APT.
 | 
			
		||||
 | 
			
		||||
On construit donc un environnement virtuel et on installe les dépendances manquantes
 | 
			
		||||
dans cet environnement :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ cd /var/www/note_kfet
 | 
			
		||||
   $ python3 -m venv env
 | 
			
		||||
   $ . env/bin/activate
 | 
			
		||||
   (env) $ pip install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
Normalement, seules les dépendances manquantes sont installées, les autres sont trouvées
 | 
			
		||||
globalement.
 | 
			
		||||
 | 
			
		||||
Plus d'informations sur les environnements virtuels dans la documentation officielle
 | 
			
		||||
de Python : `<https://docs.python.org/fr/3/tutorial/venv.html>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Configuration de la note
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
La configuration de la note se gère essentiellement via des paramètres d'environnement.
 | 
			
		||||
Ceux-ci sont lus via le fichier ``.env`` s'il existe, qui doit être placé à la racine
 | 
			
		||||
du projet cloné (donc dans ``/var/www/note_kfet/.env``). Un fichier d'exemple est situé
 | 
			
		||||
dans le fichier ``.env_example``, on peut donc faire un ``sudo cp .env_example .env``.
 | 
			
		||||
 | 
			
		||||
Attention aux permissions : le fichier doit être lu par ``www-data`` et écrit (rien
 | 
			
		||||
n'empêche de l'écrire en tant que root).
 | 
			
		||||
 | 
			
		||||
Le contenu de ce fichier :
 | 
			
		||||
 | 
			
		||||
.. code:: env
 | 
			
		||||
 | 
			
		||||
   DJANGO_APP_STAGE=prod
 | 
			
		||||
   DJANGO_DEV_STORE_METHOD=sqlite
 | 
			
		||||
   DJANGO_DB_HOST=localhost
 | 
			
		||||
   DJANGO_DB_NAME=note_db
 | 
			
		||||
   DJANGO_DB_USER=note
 | 
			
		||||
   DJANGO_DB_PASSWORD=CHANGE_ME
 | 
			
		||||
   DJANGO_DB_PORT=
 | 
			
		||||
   DJANGO_SECRET_KEY=CHANGE_ME
 | 
			
		||||
   DJANGO_SETTINGS_MODULE=note_kfet.settings
 | 
			
		||||
   CONTACT_EMAIL=tresorerie.bde@localhost
 | 
			
		||||
   NOTE_URL=localhost
 | 
			
		||||
   NOTE_MAIL=notekfet@localhost
 | 
			
		||||
   EMAIL_HOST=smtp.localhost
 | 
			
		||||
   EMAIL_PORT=25
 | 
			
		||||
   EMAIL_USER=notekfet@localhost
 | 
			
		||||
   EMAIL_PASSWORD=CHANGE_ME
 | 
			
		||||
   WIKI_USER=NoteKfet2020
 | 
			
		||||
   WIKI_PASSWORD=
 | 
			
		||||
 | 
			
		||||
Le paramètre ``DJANGO_APP_STAGE`` accepte comme valeur ``dev`` ou ``prod``.
 | 
			
		||||
En développement, les mails ne sont pas envoyés mais affichés dans les logs du
 | 
			
		||||
serveur. Les messages d'erreur sont directement affichés au lieu d'être envoyés
 | 
			
		||||
par mail. Les paramètres d'envoi de mail n'ont donc aucun effet. En développement,
 | 
			
		||||
il est également possible de choisir si l'on souhaite une base de données sqlite
 | 
			
		||||
(par défaut) ou si on veut se connecter à une base de données PostgreSQL (rentrer
 | 
			
		||||
``postgres`` dans ``DJANGO_DEV_STORE_METHOD``), auquel cas les paramètres de
 | 
			
		||||
base de données seront interprétés.
 | 
			
		||||
 | 
			
		||||
Les champs ``DJANGO_DB_`` sont relatifs à la connexion à la base de données PostgreSQL.
 | 
			
		||||
 | 
			
		||||
Le champ ``DJANGO_SECRET_KEY`` est utilisé pour la protection CSRF (voir la documentation
 | 
			
		||||
`<https://docs.djangoproject.com/fr/3.2/ref/csrf/>`_ pour plus de détails). Il s'agit d'une
 | 
			
		||||
clé sous forme de chaîne de caractère suffisamment longue (64 caractères paraît bien)
 | 
			
		||||
qui n'est pas à transmettre et qui évite d'autres sites malveillants de faire des requêtes
 | 
			
		||||
directement sur la note.
 | 
			
		||||
 | 
			
		||||
Le champ ``CONTACT_EMAIL`` correspond l'adresse mail que les adhérent⋅e⋅s peuvent contacter
 | 
			
		||||
en cas de problème. C'est là où le champ ``Nous contacter`` redirigera.
 | 
			
		||||
 | 
			
		||||
Le champ ``NOTE_URL`` correspond au nom de domaine autorisé à accéder au site. C'est également
 | 
			
		||||
le nom de domaine qui sera utilisé dans l'envoi de mails pour générer des liens. En
 | 
			
		||||
production, cela vaut ``note.crans.org``.
 | 
			
		||||
 | 
			
		||||
Le champ ``NOTE_MAIL`` correspond au champ expéditeur des mails envoyés, que ce soit
 | 
			
		||||
pour les rapports quotidiens / hebdomadaires / mensuels ou les mails d'erreur.
 | 
			
		||||
En production, ce champ vaut ``notekfet2020@crans.org``.
 | 
			
		||||
 | 
			
		||||
Les champs ``EMAIL_`` sont relatifs à la connexion au serveur SMTP pour l'envoi de mails.
 | 
			
		||||
En production, ``EMAIL_HOST`` vaut ``smtp.crans.org``, ``EMAIL_PORT`` vaut 25 (on reste sur
 | 
			
		||||
le réseau interne du Crans) et ``EMAIL_USER`` et ``EMAIL_PASSWORD`` sont vides (ce qui est
 | 
			
		||||
valide car la note est sur le réseau du Crans, qui est déjà pré-autorisé à envoyer des mails).
 | 
			
		||||
 | 
			
		||||
Les champs ``WIKI_USER`` et ``WIKI_PASSWORD`` servent à s'authentifier sur le compte Wiki
 | 
			
		||||
Crans ``NoteKfet2020``, pour notamment exporter automatiquement la liste des activités sur
 | 
			
		||||
le wiki.
 | 
			
		||||
 | 
			
		||||
Pour configurer la note, il est également possible de créer un fichier
 | 
			
		||||
``note_kfet/settings/secrets.py`` qui redéfinit certains paramètres, notamment la
 | 
			
		||||
liste des administrateurs ou certaines applications optionnelles, ou encore certains
 | 
			
		||||
éventuels mots de passe.
 | 
			
		||||
 | 
			
		||||
En production, ce fichier contient :
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
   OPTIONAL_APPS = [
 | 
			
		||||
      'cas_server',
 | 
			
		||||
   #    'debug_toolbar'
 | 
			
		||||
   ]
 | 
			
		||||
 | 
			
		||||
   # When a server error occured, send an email to these addresses
 | 
			
		||||
   ADMINS = (
 | 
			
		||||
       ('Note Kfet', 'notekfet2020@lists.crans.org'),
 | 
			
		||||
   )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Configuration des tâches récurrentes
 | 
			
		||||
------------------------------------
 | 
			
		||||
 | 
			
		||||
Certaines opérations se font périodiquement, comme le rappel hebdomadaire pour les
 | 
			
		||||
personnes en négatif. On utilise pour cela un cron. Il suffit pour cela de copier
 | 
			
		||||
le fichier ``note.cron`` vers ``/etc/cron.d/note``, en veillant à ce qu'il appartienne
 | 
			
		||||
bien à ``root``.
 | 
			
		||||
 | 
			
		||||
Ce fichier contient l'ensemble des tâches récurrentes associées à la note.
 | 
			
		||||
Une page de documentation dédiée fera bientôt son apparition.
 | 
			
		||||
 | 
			
		||||
Sur un serveur de pré-production, on peut ne pas souhaiter activer ces tâches récurrentes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Installation de la base de données PostgreSQL
 | 
			
		||||
---------------------------------------------
 | 
			
		||||
 | 
			
		||||
En production, on utilise une vraie base de données PostgreSQL et non un fichier
 | 
			
		||||
sqlite. Beaucoup plus facile pour faire éventuellement des requêtes (bien que pas
 | 
			
		||||
adapté pour Django) mais surtout bien mieux optimisé pour un serveur de production.
 | 
			
		||||
 | 
			
		||||
Pour installer la base de données, on commence par installer PostgreSQL :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt install --no-install-recommends postgresql postgresql-contrib
 | 
			
		||||
 | 
			
		||||
PostgreSQL est désormais installé et lancé. On crée un compte ``note``, avec un
 | 
			
		||||
bon mot de passe (le même que donné à Django) :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo -u postgres createuser -P note
 | 
			
		||||
 | 
			
		||||
Et on crée enfin une base de données nommée ``note_db`` appartenant à ``note``.
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo -u postgres createdb note_db -O note
 | 
			
		||||
 | 
			
		||||
La base de données est désormais prête à être utilisée.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Finir l'installation de Django
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
On commence par construire la base de données à partir des migrations enregistrées :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py migrate
 | 
			
		||||
 | 
			
		||||
On doit compiler les traductions (pour pouvoir les lire plus vite par la suite) :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py compilemessages
 | 
			
		||||
 | 
			
		||||
Les fichiers statiques (fiches de style, fichiers Javascript, images, ...) doivent
 | 
			
		||||
être exportées dans le dossier ``static`` :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py collectstatic
 | 
			
		||||
 | 
			
		||||
Et on peut enfin importer certaines données de base :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py loaddata initial
 | 
			
		||||
 | 
			
		||||
La note est désormais prête à être utilisée. Ne reste qu'à configurer un serveur Web.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Configuration de UWSGI
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
On dispose d'une instance de la note fonctionnelle et bien configurée. Cependant, nous
 | 
			
		||||
n'avons pas encore de socket permettant d'intéragir avec le serveur. C'est le travail
 | 
			
		||||
de UWSGI.
 | 
			
		||||
 | 
			
		||||
On rappelle que la commande ``./manage.py runserver`` n'est pas conçue pour des serveurs
 | 
			
		||||
de production, contrairement à UWSGI.
 | 
			
		||||
 | 
			
		||||
On commence par installer UWSGI :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt install --no-install-recommends uwsgi uwsgi-plugin-python3
 | 
			
		||||
 | 
			
		||||
On place ensuite le fichier de configuration UWSGI dans les applications installées.
 | 
			
		||||
Un fichier de configuration est présent à la racine du projet, contenant :
 | 
			
		||||
 | 
			
		||||
.. code:: ini
 | 
			
		||||
 | 
			
		||||
   [uwsgi]
 | 
			
		||||
   uid             = www-data
 | 
			
		||||
   gid             = www-data
 | 
			
		||||
   # Django-related settings
 | 
			
		||||
   # the base directory (full path)
 | 
			
		||||
   chdir           = /var/www/note_kfet
 | 
			
		||||
   # the virtualenv (full path)
 | 
			
		||||
   home            = /var/www/note_kfet/env
 | 
			
		||||
   wsgi-file       = /var/www/note_kfet/note_kfet/wsgi.py
 | 
			
		||||
   plugin          = python3
 | 
			
		||||
   # process-related settings
 | 
			
		||||
   # master
 | 
			
		||||
   master          = true
 | 
			
		||||
   # maximum number of worker processes
 | 
			
		||||
   processes       = 10
 | 
			
		||||
   # the socket (use the full path to be safe
 | 
			
		||||
   socket          = /var/www/note_kfet/note_kfet.sock
 | 
			
		||||
   # ... with appropriate permissions - may be needed
 | 
			
		||||
   chmod-socket    = 664
 | 
			
		||||
   # clear environment on exit
 | 
			
		||||
   vacuum          = true
 | 
			
		||||
   # Touch reload
 | 
			
		||||
   touch-reload    = /var/www/note_kfet/note_kfet/settings/__init__.py
 | 
			
		||||
   # Enable threads
 | 
			
		||||
   enable-threads  = true
 | 
			
		||||
 | 
			
		||||
Il suffit donc de créer le lien symbolique :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo ln -s /var/www/note_kfet/uwsgi_note.ini /etc/uwsgi/apps-enabled/uwsgi_note.ini
 | 
			
		||||
 | 
			
		||||
On peut désormais relancer UWSGI :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo systemctl restart uwsgi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Configuration de NGINX
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
Nous avons désormais un socket qui nous permet de faire des connexions au serveur web,
 | 
			
		||||
placé dans ``/var/www/note_kfet/note_kfet.sock``. Cependant, ce socket n'est pas accessible
 | 
			
		||||
au reste du monde, et ne doit pas l'être : on veut un serveur Web Nginx qui s'occupe des
 | 
			
		||||
connexions entrantes et qui peut servir de reverse-proxy, notamment utile pour desservir
 | 
			
		||||
les fichiers statiques ou d'autres sites sur le même serveur.
 | 
			
		||||
 | 
			
		||||
On commence donc par installer Nginx :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt install nginx
 | 
			
		||||
 | 
			
		||||
On place ensuite dans ``/etc/nginx/sites-available/nginx_note.conf`` le fichier de
 | 
			
		||||
configuration Nginx qui va bien, en remplaçant ``note.crans.org`` par ce qu'il faut :
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
    # the upstream component nginx needs to connect to
 | 
			
		||||
    upstream note {
 | 
			
		||||
        server unix:///var/www/note_kfet/note_kfet.sock; # file socket
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Redirect HTTP to nk20 HTTPS
 | 
			
		||||
    server {
 | 
			
		||||
        listen 80 default_server;
 | 
			
		||||
        listen [::]:80 default_server;
 | 
			
		||||
 | 
			
		||||
        location / {
 | 
			
		||||
            return 301 https://note.crans.org$request_uri;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Redirect all HTTPS to nk20 HTTPS
 | 
			
		||||
    server {
 | 
			
		||||
        listen 443 ssl default_server;
 | 
			
		||||
        listen [::]:443 ssl default_server;
 | 
			
		||||
 | 
			
		||||
        location / {
 | 
			
		||||
            return 301 https://note.crans.org$request_uri;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ssl_certificate /etc/letsencrypt/live/note.crans.org/fullchain.pem;
 | 
			
		||||
        ssl_certificate_key /etc/letsencrypt/live/note.crans.org/privkey.pem;
 | 
			
		||||
        include /etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # configuration of the server
 | 
			
		||||
    server {
 | 
			
		||||
        listen 443 ssl;
 | 
			
		||||
        listen [::]:443 ssl;
 | 
			
		||||
 | 
			
		||||
        # the port your site will be served on
 | 
			
		||||
        # the domain name it will serve for
 | 
			
		||||
        server_name note.crans.org;
 | 
			
		||||
        charset     utf-8;
 | 
			
		||||
 | 
			
		||||
        # max upload size
 | 
			
		||||
        client_max_body_size 75M;
 | 
			
		||||
 | 
			
		||||
        # Django media
 | 
			
		||||
        location /media  {
 | 
			
		||||
            alias /var/www/note_kfet/media;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        location /static {
 | 
			
		||||
            alias /var/www/note_kfet/static;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        location /doc {
 | 
			
		||||
            alias /var/www/documentation;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # Finally, send all non-media requests to the Django server.
 | 
			
		||||
        location / {
 | 
			
		||||
            uwsgi_pass note;
 | 
			
		||||
            include /etc/nginx/uwsgi_params;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ssl_certificate /etc/letsencrypt/live/note.crans.org/fullchain.pem;
 | 
			
		||||
        ssl_certificate_key /etc/letsencrypt/live/note.crans.org/privkey.pem;
 | 
			
		||||
        include /etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
On peut enfin activer le site :
 | 
			
		||||
 | 
			
		||||
.. code::
 | 
			
		||||
 | 
			
		||||
   $ sudo ln -s /etc/nginx/sites-available/nginx_note.conf /etc/nginx/sites-enabled/nginx_note.conf
 | 
			
		||||
 | 
			
		||||
Si on peut se dire que recharger Nginx suffira, il n'en est rien : voir paragraphe suivant.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Génération d'un certificat SSL
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
Nginx va essayer de lire les certificats présents dans
 | 
			
		||||
``/etc/letsencrypt/live/note.crans.org/``, mais ce dossier n'existe pas encore.
 | 
			
		||||
 | 
			
		||||
On doit donc générer un certificat pour permettre les connexions HTTPS. Cela est permis
 | 
			
		||||
grâce à ``certbot``, qu'on s'empresse d'installer :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo apt install certbot python3-certbot-nginx
 | 
			
		||||
 | 
			
		||||
Le plugin pour nginx permet de certifier que le serveur a bien les droits pour
 | 
			
		||||
``note.crans.org`` grâce à Nginx, le BDE n'ayant a priori aucune raison de pouvoir
 | 
			
		||||
gérer le nom de domaine ``crans.org``.
 | 
			
		||||
 | 
			
		||||
On place dans le dossier ``/etc/letsencrypt/conf.d`` (qu'on crée au besoin) un fichier
 | 
			
		||||
nommé ``nk20.ini`` :
 | 
			
		||||
 | 
			
		||||
.. code:: ini
 | 
			
		||||
 | 
			
		||||
    # To generate the certificate, please use the following command
 | 
			
		||||
    # certbot --config /etc/letsencrypt/conf.d/nk20.ini certonly
 | 
			
		||||
 | 
			
		||||
    # Use a 4096 bit RSA key instead of 2048
 | 
			
		||||
    rsa-key-size = 4096
 | 
			
		||||
 | 
			
		||||
    # Always use the staging/testing server
 | 
			
		||||
    # server = https://acme-staging.api.letsencrypt.org/directory
 | 
			
		||||
 | 
			
		||||
    # Uncomment and update to register with the specified e-mail address
 | 
			
		||||
    email = notekfet2020@lists.crans.org
 | 
			
		||||
 | 
			
		||||
    # Uncomment to use a text interface instead of ncurses
 | 
			
		||||
    text = True
 | 
			
		||||
 | 
			
		||||
    # Use Nginx challenge
 | 
			
		||||
    authenticator = nginx
 | 
			
		||||
 | 
			
		||||
En exécutant ``certbot``, il va lire les fichiers de configuration Nginx et générer les
 | 
			
		||||
certificats qu'il faut en créant un point d'entrée pour le serveur.
 | 
			
		||||
 | 
			
		||||
Il faut néanmoins que la configuration soit valide. Les certificats n'existant pas encore,
 | 
			
		||||
la configuration nginx est donc pour l'instant invalide. Il faut alors temporairement
 | 
			
		||||
commenter les parties de la configuration qui traitent des certificats et relancer ``nginx``
 | 
			
		||||
(``sudo systemctl reload nginx``).
 | 
			
		||||
 | 
			
		||||
On peut ensuite exécuter ``certbot`` :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ certbot --config /etc/letsencrypt/conf.d/nk20.ini certonly
 | 
			
		||||
 | 
			
		||||
L'instruction ``certonly`` indique à ``certbot`` qu'il se contente de générer le certificat,
 | 
			
		||||
sans chercher à l'installer. Si tout s'est bien passé, l'installation se fait simplement
 | 
			
		||||
en décommentant les lignes préalablement commentées.
 | 
			
		||||
 | 
			
		||||
Un certificat généré de la sorte expire au bout de 3 mois. Néanmoins, certbot tourne
 | 
			
		||||
régulièrement pour renouveler les certificats actifs automatiquement. Il n'y a donc
 | 
			
		||||
plus rien à faire.
 | 
			
		||||
 | 
			
		||||
Après avoir rechargé la configuration de ``Nginx``, rendez-vous sur
 | 
			
		||||
`<https://note.crans.org>`_ (ou votre site) pour vérifier que tout fonctionne correctement :)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Mettre à jour la note
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Pour mettre à jour la note, il suffit a priori, après avoir mis à jour les paquets APT,
 | 
			
		||||
de faire un ``git pull`` dans le dossier ``/var/www/note_kfet``.
 | 
			
		||||
 | 
			
		||||
Les éventuelles nouvelles migrations de la base de données doivent être appliquées :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py migrate
 | 
			
		||||
 | 
			
		||||
Les nouvelles traductions compilées :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py compilemessages
 | 
			
		||||
 | 
			
		||||
Les nouveaux fichiers statiques collectés :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py collectstatic
 | 
			
		||||
 | 
			
		||||
Et enfin les nouvelles fixtures installées :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ ./manage.py loaddata initial
 | 
			
		||||
 | 
			
		||||
Une fois tout cela fait, il suffit de relancer le serveur UWSGI :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   $ sudo systemctl restart uwsgi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Avec Ansible
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Tout ce travail peut sembler très laborieux et peut mériter d'être automatisé.
 | 
			
		||||
Toutefois, il est essentiel de bien comprendre comment chaque étape de l'installation
 | 
			
		||||
fonctionne.
 | 
			
		||||
 | 
			
		||||
Un playbook Ansible a été écrit permettant de réaliser toutes les tâches décrites ci-dessus.
 | 
			
		||||
Il se trouve dans le dossier ``ansible``.
 | 
			
		||||
 | 
			
		||||
Ansible s'installe sur votre propre machine (et non sur le serveur) en installant simplement
 | 
			
		||||
le paquet ``ansible``.
 | 
			
		||||
 | 
			
		||||
Pour déployer la note sur un serveur vierge, commencez par copier le fichier ``hosts_example``
 | 
			
		||||
en le nommant ``hosts``. Ajoutez votre propre serveur, dans la section correspondante.
 | 
			
		||||
 | 
			
		||||
Dans le dossier ``host_vars``, créez un fichier dont le nom est l'adresse du serveur, avec
 | 
			
		||||
l'extension ``.yml``.
 | 
			
		||||
 | 
			
		||||
Dans ce fichier, remplissez :
 | 
			
		||||
 | 
			
		||||
.. code:: yaml
 | 
			
		||||
 | 
			
		||||
   ---
 | 
			
		||||
   note:
 | 
			
		||||
     server_name: note.crans.org
 | 
			
		||||
     git_branch: master
 | 
			
		||||
     cron_enabled: true
 | 
			
		||||
     email: notekfet2020@lists.crans.org
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
en adaptant à votre configuration.
 | 
			
		||||
 | 
			
		||||
Il suffit ensuite de lancer ``./base.yml -l urldevotreserveur``.
 | 
			
		||||
 | 
			
		||||
Pour une première installation, vous devrez renseigner le mot de passe de la base de données
 | 
			
		||||
pour créer le compte ``note``. Vous devrez ensuite également refaire quelques ajustements
 | 
			
		||||
pour générer le certificat, voir la partie ``certbot``. La configuration du fichier
 | 
			
		||||
``.env`` sera également à faire à la main.
 | 
			
		||||
 | 
			
		||||
Cependant, pour mettre à jour, lancer cette commande suffit.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Copier une base de données
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
On peut vouloir périodiquement copier la base de données de production vers le serveur
 | 
			
		||||
de développement, afin de travailler avec des données à jour.
 | 
			
		||||
 | 
			
		||||
On aura besoin de pouvoir accéder aux deux bases de données. On commence donc si ce n'est
 | 
			
		||||
pas déjà fait par créer un utilisateur sur les deux serveurs :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   ynerant@bde-note:~$ sudo -u postgres createuser -l ynerant
 | 
			
		||||
 | 
			
		||||
On réinitialise **sur le serveur de développement** la base de données présente, en
 | 
			
		||||
éteignant tout d'abord le serveur Web :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   ynerant@bde-note-dev:~$ sudo systemctl stop uwsgi
 | 
			
		||||
   ynerant@bde-note-dev:~$ sudo -u postgres dropdb note_db
 | 
			
		||||
   ynerant@bde-note-dev:~$ sudo -u postgres createdb -O note note_db
 | 
			
		||||
 | 
			
		||||
Et on copie enfin la base de données, en une seule ligne via SSH :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   ynerant@bde-note:~$ pg_dump note_db | ssh note-dev.crans.org "psql note_db -f -"
 | 
			
		||||
 | 
			
		||||
On peut enfin redémarrer le serveur Web. Les données ont bien été copiées.
 | 
			
		||||
 | 
			
		||||
.. caution::
 | 
			
		||||
 | 
			
		||||
   On ne copiera **jamais** des données d'adhérent⋅e⋅s sur une machine personnelle.
 | 
			
		||||
   Ce type d'opération doit s'effectuer impérativement entre des serveurs du BDE.
 | 
			
		||||
							
								
								
									
										308
									
								
								docs/scripts.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								docs/scripts.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
			
		||||
Les scripts de la Note Kfet 2020
 | 
			
		||||
================================
 | 
			
		||||
 | 
			
		||||
Django permet la création de scripts permettant l'interaction en ligne de commande
 | 
			
		||||
avec le site. Les scripts sont gérés dans un projet à part :
 | 
			
		||||
`nk20-scripts <https://gitlab.crans.org/bde/nk20-scripts>`_.
 | 
			
		||||
 | 
			
		||||
Il s'agit d'un module Python à part contenant tous les scripts interagissant avec la note.
 | 
			
		||||
Pour l'installer, il suffit d'importer le sous module (``git submodule init apps/scripts``)
 | 
			
		||||
ou bien d'avoir ajouté l'option ``--recursive`` lorsque le dépôt a été cloné. Il faut
 | 
			
		||||
ensuite ajouter le module au tableau ``INSTALLED_APPS`` dans les paramètres.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Scripts Python
 | 
			
		||||
##############
 | 
			
		||||
 | 
			
		||||
Structure d'un script
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Un script est un fichier Python placé dans ``apps/scripts/management/commands``. Le nom
 | 
			
		||||
de fichier sans l'extension ``.py`` caractérise le nom du script. On supposera dans la suite
 | 
			
		||||
qu'on aura créé le script ``toto.py``. Pour lancer le script, il suffira de lancer
 | 
			
		||||
``./manage.py toto``. Django se charge de trouver l'emplacement du script. Un simple
 | 
			
		||||
``./manage.py`` affichera par ailleurs la liste des scripts par application.
 | 
			
		||||
 | 
			
		||||
Ce fichier Python doit contenir une classe nommée ``Command`` héritant de
 | 
			
		||||
``django.core.management.base.BaseCommand``.
 | 
			
		||||
 | 
			
		||||
Il suffit enfin de créer une fonction ``handle(self, *args, **options) -> None``.
 | 
			
		||||
C'est cette fonction qui servira à l'exécution du script. ``options`` contient
 | 
			
		||||
l'ensemble des options transmises.
 | 
			
		||||
 | 
			
		||||
Pour gérer les options, créez une fonction ``add_arguments(self, parser)``.
 | 
			
		||||
``parser`` vous permet de gérer vos arguments. Plus d'informations dans la documentation
 | 
			
		||||
du module ``argparse`` de Python : https://docs.python.org/fr/3/library/argparse.html
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
   Bonne pratique : si votre script doit écrire sur la base de données, pensez à
 | 
			
		||||
   ajouter un décorateur ``@transaction.atomic`` (du module ``django.db``) sur
 | 
			
		||||
   votre fonction ``handle``. Cela aura pour effet de ne pas effectuer les modifications
 | 
			
		||||
   indiquées en cas d'erreur dans le script. Cela évite de vous retrouver avec une base
 | 
			
		||||
   de données dans un état instable en cas d'erreur dans le script, ou en développement
 | 
			
		||||
   (sur un serveur de développement bien sûr).
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
   Par défaut, chaque commande dispose d'un certain nombre d'options, dont ``--help`` qui
 | 
			
		||||
   affiche l'aide et les options disponibles, et ``--verbosity {0, 1, 2, 3}`` qui permet
 | 
			
		||||
   de contrôler la verbosité du script. Il est important d'en tenir compte, en particulier
 | 
			
		||||
   un niveau de verbosité nul ne devrait afficher rien d'autre que des erreurs.
 | 
			
		||||
 | 
			
		||||
Plus d'informations dans la documentation officielle :
 | 
			
		||||
https://docs.djangoproject.com/fr/2.2/howto/custom-management-commands/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Anonymisation de données
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``anonymize_data``.
 | 
			
		||||
 | 
			
		||||
Ce script était utilisé lors de la beta de la Note Kfet 2020, afin d'anonymiser certaines
 | 
			
		||||
données personnelles et limiter le risque de fuites de données. Ainsi, les noms, prénoms,
 | 
			
		||||
adresses électroniques, numéros de téléphone et adresses étaient normalisées.
 | 
			
		||||
 | 
			
		||||
Ce script étant dangereux, l'option ``--force`` est requise.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Vérification de l'intégrité des données
 | 
			
		||||
---------------------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``check_consistency``.
 | 
			
		||||
 | 
			
		||||
Son but est de s'assurer que la somme des montants de toutes les notes vaut bien zéro,
 | 
			
		||||
et que pour chaque note, la somme des transactions donne bien le solde de la note.
 | 
			
		||||
 | 
			
		||||
En cas de problème, les erreurs détectées sont affichées.
 | 
			
		||||
 | 
			
		||||
Le script prend plusieurs options :
 | 
			
		||||
 | 
			
		||||
* ``--sum-all, -s`` : vérifie si la somme des notes vaut bien 0
 | 
			
		||||
* ``--check-all, -a`` : vérifie si le solde de toutes les notes est cohérent
 | 
			
		||||
* ``--check, -c`` : si l'option précédente n'est pas présente, indique les identifiants
 | 
			
		||||
  des notes à vérifier
 | 
			
		||||
* ``--fix, -f`` : Rétablit le solde des notes à la somme des transactions. À n'utiliser
 | 
			
		||||
  qu'après avoir identifié le problème.
 | 
			
		||||
 | 
			
		||||
Ce script est appelé tous les jours à 4h du matin avec les options ``--sum-all --check-all``,
 | 
			
		||||
et en cas d'erreur un mail est envoyé.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Compilation des messages JavaScript
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``compilejsmessages``.
 | 
			
		||||
 | 
			
		||||
Django gère nativement la traduction des chaînes de caractères, avec notamment les scripts
 | 
			
		||||
``makemessages`` et ``compilemessages``. Django permet également de gérer la traduction
 | 
			
		||||
dans les fichiers statiques JavaScript, comme l'indique la documentation officielle :
 | 
			
		||||
https://docs.djangoproject.com/fr/2.2/topics/i18n/translation/#internationalization-in-javascript-code
 | 
			
		||||
 | 
			
		||||
Comme l'indique cette documentation, cela revient à ajouter un fichier Javascript contenant
 | 
			
		||||
l'ensemble des traductions et le navigateur s'occupe de récupérer les bonnes traductions.
 | 
			
		||||
 | 
			
		||||
Cependant, la façon standard de gérer cela est d'avoir une vue dédiée qui générera le bon
 | 
			
		||||
fichier Javascript. Les traductions ne changeant pas souvent (à chaque mise à jour
 | 
			
		||||
uniquement), il n'est pas essentiel de les recompiler à chaque chargement de page.
 | 
			
		||||
 | 
			
		||||
Le protocole choisi est donc de générer des fichiers statiques, qui seront donc directement
 | 
			
		||||
servis par Nginx (et éventuellement mis en cache par le client) et non recalculés à chaque
 | 
			
		||||
fois. On optimise donc les requêtes.
 | 
			
		||||
 | 
			
		||||
Pour rappel, pour générer les fichiers de traduction Javascript :
 | 
			
		||||
 | 
			
		||||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
   ./manage.py makemessages -i env -e js -d djangojs
 | 
			
		||||
 | 
			
		||||
Et on peut donc appeler ce script ``compilejsmessages`` pour créer les fichiers Javascript
 | 
			
		||||
correspondant et le placer dans le dossier des fichiers statiques.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Extraction des listes de diffusion
 | 
			
		||||
----------------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``extract_ml_registrations``.
 | 
			
		||||
 | 
			
		||||
Il a pour but d'extraire une liste d'adresses mail pour les inclure directement dans les listes
 | 
			
		||||
de diffusion utiles.
 | 
			
		||||
 | 
			
		||||
Il prend 2 options :
 | 
			
		||||
 | 
			
		||||
* ``--type``, qui prend en argument ``members`` (défaut), ``clubs``, ``events``, ``art``,
 | 
			
		||||
  ``sport``, qui permet respectivement de sortir la liste des adresses mails des adhérents
 | 
			
		||||
  actuels (pour la liste ``adherents.bde@lists.crans.org), des clubs (pour
 | 
			
		||||
  ``clubs@lists.crans.org``), des personnes à abonner à ``evenements@lists.crans.org``,
 | 
			
		||||
  à ``all.bda@lists.crans.org`` et enfin à ``bds@lists.crans.org``.
 | 
			
		||||
* ``--lang``, qui prend en argument ``fr`` ou ``en``. N'est utile que pour la ML événements,
 | 
			
		||||
  qui a pour projet d'être disponible à la fois en anglais et en français.
 | 
			
		||||
 | 
			
		||||
Le script sort sur la sortie standard la liste des adresses mails à inscrire.
 | 
			
		||||
 | 
			
		||||
Attention : il y a parfois certains cas particuliers à prendre en compte, il n'est
 | 
			
		||||
malheureusement pas aussi simple que de simplement supposer que ces listes sont exhaustives.
 | 
			
		||||
 | 
			
		||||
À terme, il pourrait être envisageable de synchroniser automatiquement les listes avec la note.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Suppression d'un utilisateur
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``force_delete_user``.
 | 
			
		||||
 | 
			
		||||
.. caution::
 | 
			
		||||
 | 
			
		||||
   Ce script est dangereux. À n'utiliser qu'avec de très grosses pincettes si vous savez
 | 
			
		||||
   ce que vous faites. Seul cas d'usage pour l'instant recensé : supprimer des comptes en
 | 
			
		||||
   double qui se sont malencontreusement retrouvés validés pour raison de Sogé et de mauvaise
 | 
			
		||||
   communication au sein des trésorier⋅ère⋅s.
 | 
			
		||||
 | 
			
		||||
   Il n'est certainement pas prévu de supprimer des vrais comptes existants via ce script.
 | 
			
		||||
   On ne supprime pas l'historique. Si jamais quelqu'un demanderait à supprimer son compte,
 | 
			
		||||
   on se contente de l'anonymiser, et non de le supprimer.
 | 
			
		||||
 | 
			
		||||
Ce script est utile lorsqu'il faut supprimer un compte créer par erreur. Tant que la validation
 | 
			
		||||
n'est pas faite, il suffit en général de cliquer sur le bouton « Supprimer le compte » sur
 | 
			
		||||
l'interface de validation. Cela supprimera l'utilisateur et le profil associé, sans toucher
 | 
			
		||||
à une quelconque note puisqu'elle ne sera pas créée.
 | 
			
		||||
 | 
			
		||||
Ce script supprime donc un compte ainsi que toutes les données associées (note, alias,
 | 
			
		||||
transactions). Il n'est donc pas à prendre à la légère, et vous devez savoir ce que vous
 | 
			
		||||
faites.
 | 
			
		||||
 | 
			
		||||
Il prend en arguments les identifiants numériques ou un alias de la ou des personnes à
 | 
			
		||||
supprimer.
 | 
			
		||||
 | 
			
		||||
Sans rien ajouter, il affichera uniquement les éléments qui seront supprimés.
 | 
			
		||||
 | 
			
		||||
Avec l'option ``--force``, il commencera à créer une transaction dans la base de données
 | 
			
		||||
pour supprimer tout ce qu'il faut, et une validation manuelle sera requise pour confirmer
 | 
			
		||||
la suppression. L'option ``--doit`` évite cette confirmation manuelle.
 | 
			
		||||
**Vous n'avez jamais à utiliser cette option en théorie.**
 | 
			
		||||
 | 
			
		||||
À la fin du processus, un mail est envoyé aux administrateurs pour les prévenir des
 | 
			
		||||
élements supprimés.
 | 
			
		||||
 | 
			
		||||
Des données réelles jamais tu ne supprimeras.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Importation de la Note Kfet 2015
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
Les scripts commençant par ``import_`` sont destinés à l'import des données depuis
 | 
			
		||||
la Note Kfet 2015.
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
   TODO: Pour la postérité et la conservation d'archives, documenter comment l'import
 | 
			
		||||
   s'est déroulé.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Ajouter un super-utilisateur
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``make_su``.
 | 
			
		||||
 | 
			
		||||
Il prend en argument un pseudo.
 | 
			
		||||
 | 
			
		||||
Avec l'option ``--SUPER, -S``, la personne avec ce pseudo devient super-utilisateur,
 | 
			
		||||
et obtiens donc les pleins pouvoirs sur la note. À ne donner qu'aux respos info.
 | 
			
		||||
 | 
			
		||||
Avec l'option ``--STAFF, -s``, la personne avec ce pseudo acquiert le statut équipe,
 | 
			
		||||
et obtiens l'accès à django-admin. À ne donner qu'aux respos info.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Rafraîchissement des activités
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``refresh_activities``.
 | 
			
		||||
 | 
			
		||||
Il a pour but de mettre à jour le Wiki du Crans automatiquement en ajoutant les
 | 
			
		||||
activités de la Note Kfet sur le calendrier, à savoir les pages
 | 
			
		||||
`<https://wiki.crans.org/VieBde/PlanningSoirees>`_ et
 | 
			
		||||
`<https://wiki.crans.org/VieBde/PlanningSoirees/LeCalendrier>`_.
 | 
			
		||||
 | 
			
		||||
Il prend diverses options :
 | 
			
		||||
 | 
			
		||||
* ``--human, -H`` : met à jour la version lisible de la page des activités
 | 
			
		||||
* ``--raw, -r`` : met à jour la version brute de la page des activités, interprétable
 | 
			
		||||
  par le calendrier
 | 
			
		||||
* ``--comment, -c`` : définit le commentaire à ajouter à la modification du wiki
 | 
			
		||||
* ``--stdout, -o`` : affiche la page sur la sortie standard
 | 
			
		||||
* ``--wiki, -w`` : applique effectivement les modifications sur le wiki
 | 
			
		||||
 | 
			
		||||
Ce script est appelé tous les jours à 5h30 avec les options
 | 
			
		||||
``--raw --human --comment refresh --wiki``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Rafraîchissement des boutons mis en avant
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``refresh_highlighted_buttons``.
 | 
			
		||||
 | 
			
		||||
Il permet d'actualiser la liste des boutons mis en avant sur la page de consommations
 | 
			
		||||
qui servent de raccourcis.
 | 
			
		||||
 | 
			
		||||
Ce script récupère la liste des 10 boutons les plus cliqués les 30 derniers jours et
 | 
			
		||||
les met en avant.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Envoi des rappels de négatif
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``send_mail_to_negative_balances``.
 | 
			
		||||
 | 
			
		||||
Il sert à rappeler aux adhérent⋅e⋅s et clubs en négatif qu'ils le sont, mais également
 | 
			
		||||
à envoyer aux trésorier⋅ère⋅s et respos info la liste des adhérent⋅e⋅s en négatif.
 | 
			
		||||
 | 
			
		||||
Il prend les options suivantes :
 | 
			
		||||
 | 
			
		||||
* ``--spam, -s`` : envoie à chaque adhérent⋅e en négatif un rappel par mail pour recharger
 | 
			
		||||
* ``--report, -r`` : envoie le rapport aux trésorier⋅ère⋅s et respos info
 | 
			
		||||
* ``--negative-amount,-n`` : définit le solde maximal en-dessous duquel les notes
 | 
			
		||||
  apparaitront sur le rapport / seront spammées
 | 
			
		||||
* ``--add-years, -y`` : ajoute également les adhérent⋅e⋅s des ``n`` dernières années
 | 
			
		||||
 | 
			
		||||
Ce script est appelé tous les mardis à 5h00 pour spammer les utilisateur⋅rice⋅s en
 | 
			
		||||
négatif et tous les 6 du mois pour envoyer le rapport des notes d'adhérent⋅e⋅s ou de
 | 
			
		||||
vieux/vieilles adhérent⋅e⋅s de moins d'un an sous -10 €.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Envoi des rapports
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
Le script s'appelle ``send_reports``.
 | 
			
		||||
 | 
			
		||||
Les utilisateurs ont la possibilité de recevoir sur demande un rapport à la fréquence de
 | 
			
		||||
leur choix (en jours) des transactions effectuées sur leur note.
 | 
			
		||||
 | 
			
		||||
Le script prend 2 options :
 | 
			
		||||
 | 
			
		||||
* ``--notes, -n`` : sélectionne les notes auxquelles envoyer un rapport. Si non spécifié,
 | 
			
		||||
  envoie un mail à toutes les notes demandant un rapport.
 | 
			
		||||
* ``--debug, -d`` : affiche les rapports dans la sortie standard sans les envoyer par mail.
 | 
			
		||||
  Les dates de dernier rapport ne sont pas actualisées.
 | 
			
		||||
 | 
			
		||||
Ce script est appelé tous les jours à 6h55.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Scripts bash
 | 
			
		||||
############
 | 
			
		||||
 | 
			
		||||
À quelques fins utiles, certains scripts bash sont également présents, dans le dossier
 | 
			
		||||
``scripts/shell``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Sauvegardes de la base de données
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
Le script ``backup_db`` permet de faire une sauvegarde de la base de données PostgreSQL
 | 
			
		||||
et l'envoie sur ``club-bde@zamok.crans.org``. Le script doit être lancé en tant que root.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Tabularasa
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
Ce script n'a un intérêt qu'en développement, afin de détruire la base de données et la
 | 
			
		||||
recréer en appliquant les migrations et en chargeant les données initiales.
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
if [ -z ${NOTE_URL+x} ]; then
 | 
			
		||||
  echo "Warning: your env files are not configurated."
 | 
			
		||||
else
 | 
			
		||||
  sed -i -e "s/example.com/$DOMAIN/g" /var/www/note_kfet/apps/member/fixtures/initial.json
 | 
			
		||||
  sed -i -e "s/example.com/$NOTE_URL/g" /var/www/note_kfet/apps/member/fixtures/initial.json
 | 
			
		||||
  sed -i -e "s/localhost/$NOTE_URL/g" /var/www/note_kfet/note_kfet/fixtures/initial.json
 | 
			
		||||
  sed -i -e "s/\"\.\*\"/\"https?:\/\/$NOTE_URL\/.*\"/g" /var/www/note_kfet/note_kfet/fixtures/cas.json
 | 
			
		||||
  sed -i -e "s/REPLACEME/La Note Kfet \\\\ud83c\\\\udf7b/g" /var/www/note_kfet/note_kfet/fixtures/cas.json
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								note.cron
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								note.cron
									
									
									
									
									
								
							@@ -1,24 +1,27 @@
 | 
			
		||||
# {{ ansible_managed }}
 | 
			
		||||
# Les cronjobs dont a besoin la Note Kfet
 | 
			
		||||
 | 
			
		||||
# Envoi des mails aux respos info
 | 
			
		||||
MAILTO=notekfet2020@lists.crans.org
 | 
			
		||||
 | 
			
		||||
# m  h   dom mon dow     user   command
 | 
			
		||||
# Envoyer les mails en attente
 | 
			
		||||
 *   *     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail -c 1
 | 
			
		||||
 *   *     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py retry_deferred -c 1
 | 
			
		||||
 00  0     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py purge_mail_log 7 -c 1
 | 
			
		||||
 *   *     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail -v 0
 | 
			
		||||
 *   *     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py retry_deferred -v 0
 | 
			
		||||
 00  0     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py purge_mail_log 7 -v 0
 | 
			
		||||
# Faire une sauvegarde de la base de données
 | 
			
		||||
 00  2     *   *   *     root   cd /var/www/note_kfet && apps/scripts/shell/backup_db
 | 
			
		||||
# Vérifier la cohérence de la base et mailer en cas de problème
 | 
			
		||||
 00  4     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py check_consistency --sum-all --check-all --mail
 | 
			
		||||
 00  4     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py check_consistency --sum-all --check-all --mail -v 0
 | 
			
		||||
# Mettre à jour le wiki (modification sans (dé)validation, activités passées)
 | 
			
		||||
 30  5     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py refresh_activities --raw --human --comment refresh --wiki
 | 
			
		||||
 30  5     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py refresh_activities --raw --human --comment refresh --wiki -v 0
 | 
			
		||||
# Spammer les gens en négatif
 | 
			
		||||
 00  5     *   *   2     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --spam
 | 
			
		||||
 00  5     *   *   2     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --spam --negative-amount 0 -v 0
 | 
			
		||||
# Envoyer le rapport mensuel aux trésoriers et respos info
 | 
			
		||||
 00  8     6   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report
 | 
			
		||||
 00  8     6   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_mail_to_negative_balances --report --add-years 1 -v 0
 | 
			
		||||
# Envoyer les rapports aux gens
 | 
			
		||||
 55  6     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_reports
 | 
			
		||||
 55  6     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py send_reports -v 0
 | 
			
		||||
# Mettre à jour les boutons mis en avant
 | 
			
		||||
 00  9     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py refresh_highlighted_buttons
 | 
			
		||||
 00  9     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py refresh_highlighted_buttons -v 0
 | 
			
		||||
# Vider les tokens Oauth2
 | 
			
		||||
 00  6     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py cleartokens
 | 
			
		||||
 00  6     *   *   *     root   cd /var/www/note_kfet && env/bin/python manage.py cleartokens -v 0
 | 
			
		||||
 
 | 
			
		||||
@@ -52,3 +52,9 @@ if "rest_framework" in settings.INSTALLED_APPS:
 | 
			
		||||
    from rest_framework.authtoken.admin import *
 | 
			
		||||
    from rest_framework.authtoken.models import *
 | 
			
		||||
    admin_site.register(Token, TokenAdmin)
 | 
			
		||||
 | 
			
		||||
if "cas_server" in settings.INSTALLED_APPS:
 | 
			
		||||
    from cas_server.admin import *
 | 
			
		||||
    from cas_server.models import *
 | 
			
		||||
    admin_site.register(ServicePattern, ServicePatternAdmin)
 | 
			
		||||
    admin_site.register(FederatedIendityProvider, FederatedIendityProviderAdmin)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ def read_env():
 | 
			
		||||
    directory.
 | 
			
		||||
    """
 | 
			
		||||
    try:
 | 
			
		||||
        with open('.env') as f:
 | 
			
		||||
        with open(os.path.join(BASE_DIR, '.env')) as f:
 | 
			
		||||
            content = f.read()
 | 
			
		||||
    except IOError:
 | 
			
		||||
        content = ''
 | 
			
		||||
@@ -30,6 +30,7 @@ def read_env():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Try to load environment variables from project .env
 | 
			
		||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 | 
			
		||||
read_env()
 | 
			
		||||
 | 
			
		||||
# Load base settings
 | 
			
		||||
 
 | 
			
		||||
@@ -239,6 +239,7 @@ REST_FRAMEWORK = {
 | 
			
		||||
    'DEFAULT_AUTHENTICATION_CLASSES': [
 | 
			
		||||
        'rest_framework.authentication.SessionAuthentication',
 | 
			
		||||
        'rest_framework.authentication.TokenAuthentication',
 | 
			
		||||
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
 | 
			
		||||
    ],
 | 
			
		||||
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
 | 
			
		||||
    'PAGE_SIZE': 20,
 | 
			
		||||
@@ -273,3 +274,6 @@ PIC_RATIO = 1
 | 
			
		||||
# Custom phone number format
 | 
			
		||||
PHONENUMBER_DB_FORMAT = 'NATIONAL'
 | 
			
		||||
PHONENUMBER_DEFAULT_REGION = 'FR'
 | 
			
		||||
 | 
			
		||||
# We add custom information to CAS, in order to give a normalized name to other services
 | 
			
		||||
CAS_AUTH_CLASS = 'member.auth.CustomAuthUser'
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,11 @@ if "oauth2_provider" in settings.INSTALLED_APPS:
 | 
			
		||||
        path('o/', include('oauth2_provider.urls', namespace='oauth2_provider'))
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
if "cas_server" in settings.INSTALLED_APPS:
 | 
			
		||||
    urlpatterns.append(
 | 
			
		||||
        path('cas/', include('cas_server.urls', namespace='cas_server'))
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
if "debug_toolbar" in settings.INSTALLED_APPS:
 | 
			
		||||
    import debug_toolbar
 | 
			
		||||
    urlpatterns = [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
beautifulsoup4~=4.7.1
 | 
			
		||||
Django~=2.2.15
 | 
			
		||||
django-bootstrap-datepicker-plus~=3.0.5
 | 
			
		||||
django-cas-server~=1.2.0
 | 
			
		||||
django-colorfield~=0.3.2
 | 
			
		||||
django-crispy-forms~=1.7.2
 | 
			
		||||
django-extensions~=2.1.4
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user