diff --git a/README.md b/README.md index d1dd108..bdd9784 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,3 @@ git push heroku master You may need to upgrade Python since Heroku tends to deprecate old patch versions rather quickly. In this case, edit `runtime.txt`. - diff --git a/envs/local.env.dist b/envs/local.env.dist index 8fa6bba..ede7dd7 100644 --- a/envs/local.env.dist +++ b/envs/local.env.dist @@ -7,4 +7,4 @@ SERVER_EMAIL=server@example.com AUTHORIZED_EMAILS=user1@example.com,user2@example.com LIBRARIAN_EMAILS=user3@example.com,user4@example.com MAILGUN_ACCESS_KEY=access-key -MAILGUN_SERVER_NAME=mg.example.com \ No newline at end of file +MAILGUN_SERVER_NAME=mg.example.com diff --git a/healthcheck.py b/healthcheck.py index 711261c..a259a2d 100644 --- a/healthcheck.py +++ b/healthcheck.py @@ -5,11 +5,11 @@ import requests def main(): - port = os.getenv('PORT', 8000) - res = requests.get(f'http://127.0.0.1:{port}/') + port = os.getenv("PORT", 8000) + res = requests.get(f"http://127.0.0.1:{port}/") if res.status_code >= 400: sys.exit(1) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/manuels/admin.py b/manuels/admin.py index b2ba938..b926226 100644 --- a/manuels/admin.py +++ b/manuels/admin.py @@ -1,57 +1,78 @@ from django.contrib import admin, messages from django.db.models import Prefetch -from import_export import resources, fields +from import_export import fields, resources from import_export.admin import ExportMixin -from import_export.widgets import IntegerWidget, DecimalWidget +from import_export.widgets import DecimalWidget, IntegerWidget -from manuels.models import Teacher, Book, Level, Editor, SuppliesRequirement, CommonSupply, ISBNError +from manuels.models import ( + Book, + CommonSupply, + Editor, + ISBNError, + Level, + SuppliesRequirement, + Teacher, +) class TeacherResource(resources.ModelResource): class Meta: model = Teacher - fields = ('first_name', 'last_name', 'email', 'phone_number') + fields = ("first_name", "last_name", "email", "phone_number") @admin.register(Teacher) class TeacherAdmin(ExportMixin, admin.ModelAdmin): resource_class = TeacherResource - list_display = ['full_name', 'email', 'phone_number', 'has_confirmed_list'] + list_display = ["full_name", "email", "phone_number", "has_confirmed_list"] def send_link(self, request, queryset): for teacher in queryset: teacher.send_link(request) - messages.success(request, f'Le lien a bien été envoyé aux {queryset.count()} coordonateur(s) sélectionné(s).') + messages.success( + request, + f"Le lien a bien été envoyé aux {queryset.count()} coordonateur(s) sélectionné(s).", + ) - send_link.short_description = 'Envoyer le lien' + send_link.short_description = "Envoyer le lien" actions = [send_link] class LevelResource(resources.ModelResource): - non_acquired_book_count = fields.Field(attribute='non_acquired_book_count', widget=IntegerWidget()) - non_acquired_book_price = fields.Field(attribute='non_acquired_book_price', widget=DecimalWidget()) - non_acquired_consumable_count = fields.Field(attribute='non_acquired_consumable_count', widget=IntegerWidget()) - non_acquired_consumable_price = fields.Field(attribute='non_acquired_consumable_price', widget=DecimalWidget()) - non_acquired_total_price = fields.Field(attribute='non_acquired_total_price', widget=DecimalWidget()) + non_acquired_book_count = fields.Field( + attribute="non_acquired_book_count", widget=IntegerWidget() + ) + non_acquired_book_price = fields.Field( + attribute="non_acquired_book_price", widget=DecimalWidget() + ) + non_acquired_consumable_count = fields.Field( + attribute="non_acquired_consumable_count", widget=IntegerWidget() + ) + non_acquired_consumable_price = fields.Field( + attribute="non_acquired_consumable_price", widget=DecimalWidget() + ) + non_acquired_total_price = fields.Field( + attribute="non_acquired_total_price", widget=DecimalWidget() + ) class Meta: model = Level fields = ( - 'name', - 'non_acquired_book_count', - 'non_acquired_book_price', - 'non_acquired_consumable_count', - 'non_acquired_consumable_price', - 'non_acquired_total_price', + "name", + "non_acquired_book_count", + "non_acquired_book_price", + "non_acquired_consumable_count", + "non_acquired_consumable_price", + "non_acquired_total_price", ) export_order = ( - 'name', - 'non_acquired_book_count', - 'non_acquired_book_price', - 'non_acquired_consumable_count', - 'non_acquired_consumable_price', - 'non_acquired_total_price', + "name", + "non_acquired_book_count", + "non_acquired_book_price", + "non_acquired_consumable_count", + "non_acquired_consumable_price", + "non_acquired_total_price", ) @@ -59,87 +80,160 @@ class LevelResource(resources.ModelResource): class LevelAdmin(ExportMixin, admin.ModelAdmin): resource_class = LevelResource list_display = [ - 'name', - 'order', - 'non_acquired_book_count', - 'non_acquired_book_price', - 'non_acquired_consumable_count', - 'non_acquired_consumable_price', - 'non_acquired_total_price', + "name", + "order", + "non_acquired_book_count", + "non_acquired_book_price", + "non_acquired_consumable_count", + "non_acquired_consumable_price", + "non_acquired_total_price", ] - list_editable = ['order'] - list_display_links = ['name'] + list_editable = ["order"] + list_display_links = ["name"] def get_queryset(self, request): - return super(LevelAdmin, self).get_queryset(request).prefetch_related( - Prefetch("book_set", to_attr="prefetched_books")) + return ( + super(LevelAdmin, self) + .get_queryset(request) + .prefetch_related(Prefetch("book_set", to_attr="prefetched_books")) + ) def non_acquired_book_count(self, obj: Level): return obj.non_acquired_book_count - non_acquired_book_count.short_description = 'Nombre de livres à acheter (hors consommables)' + non_acquired_book_count.short_description = ( + "Nombre de livres à acheter (hors consommables)" + ) def non_acquired_book_price(self, obj: Level): - return f'{obj.non_acquired_book_price:.2f}€' + return f"{obj.non_acquired_book_price:.2f}€" - non_acquired_book_price.short_description = 'Coût des livres à acheter (hors consommables)' + non_acquired_book_price.short_description = ( + "Coût des livres à acheter (hors consommables)" + ) def non_acquired_consumable_count(self, obj: Level): return obj.non_acquired_consumable_count - non_acquired_consumable_count.short_description = 'Nombre de consommables à acheter' + non_acquired_consumable_count.short_description = "Nombre de consommables à acheter" def non_acquired_consumable_price(self, obj: Level): - return f'{obj.non_acquired_consumable_price:.2f}€' + return f"{obj.non_acquired_consumable_price:.2f}€" - non_acquired_consumable_price.short_description = 'Coût des consommables à acheter' + non_acquired_consumable_price.short_description = "Coût des consommables à acheter" def non_acquired_total_price(self, obj: Level): - return f'{obj.non_acquired_total_price:.2f}€' + return f"{obj.non_acquired_total_price:.2f}€" - non_acquired_total_price.short_description = 'Coût total à acheter' + non_acquired_total_price.short_description = "Coût total à acheter" class BookResource(resources.ModelResource): - decitre_url = fields.Field(attribute='decitre_url') + decitre_url = fields.Field(attribute="decitre_url") class Meta: model = Book - fields = ('title', 'authors', 'editor__name', 'publication_year', 'isbn', 'comments', 'other_editor', - 'price', 'previously_acquired', 'teacher__first_name', 'teacher__last_name', 'level__name', 'field', - 'consumable', "decitre_url") - export_order = ('level__name', 'field', 'title', 'authors', 'editor__name', 'publication_year', 'isbn', 'price', - 'other_editor', 'previously_acquired', 'teacher__first_name', 'teacher__last_name', 'comments', - 'consumable', "decitre_url") + fields = ( + "title", + "authors", + "editor__name", + "publication_year", + "isbn", + "comments", + "other_editor", + "price", + "previously_acquired", + "teacher__first_name", + "teacher__last_name", + "level__name", + "field", + "consumable", + "decitre_url", + ) + export_order = ( + "level__name", + "field", + "title", + "authors", + "editor__name", + "publication_year", + "isbn", + "price", + "other_editor", + "previously_acquired", + "teacher__first_name", + "teacher__last_name", + "comments", + "consumable", + "decitre_url", + ) @admin.register(Book) class BookAdmin(ExportMixin, admin.ModelAdmin): resource_class = BookResource - list_display = ['level', 'field', 'title', 'authors', 'editor', 'other_editor', 'publication_year', 'isbn', - 'price', 'previously_acquired', 'teacher', 'done', 'consumable'] - list_editable = ['done'] - list_filter = ['done', 'previously_acquired', 'consumable', 'level', 'editor', 'teacher'] - list_display_links = ['title'] - fieldsets = [ - ('Infos livre', { - 'fields': ('title', 'consumable', 'authors', ('editor', 'other_editor'), 'publication_year', - 'isbn', 'created_at', 'updated_at', 'comments') - }), - ('Élève', { - 'fields': ('price', 'previously_acquired',) - }), - ('Coordonnateur', { - 'fields': ('teacher', 'level', 'field') - }), - ('Gestion', { - 'fields': ('done',) - }), + list_display = [ + "level", + "field", + "title", + "authors", + "editor", + "other_editor", + "publication_year", + "isbn", + "price", + "previously_acquired", + "teacher", + "done", + "consumable", ] - readonly_fields = ['created_at', 'updated_at'] + list_editable = ["done"] + list_filter = [ + "done", + "previously_acquired", + "consumable", + "level", + "editor", + "teacher", + ] + list_display_links = ["title"] + fieldsets = [ + ( + "Infos livre", + { + "fields": ( + "title", + "consumable", + "authors", + ("editor", "other_editor"), + "publication_year", + "isbn", + "created_at", + "updated_at", + "comments", + ) + }, + ), + ( + "Élève", + { + "fields": ( + "price", + "previously_acquired", + ) + }, + ), + ("Coordonnateur", {"fields": ("teacher", "level", "field")}), + ("Gestion", {"fields": ("done",)}), + ] + readonly_fields = ["created_at", "updated_at"] def get_queryset(self, request): - return super(BookAdmin, self).get_queryset(request).select_related("editor", "level", "teacher") + return ( + super(BookAdmin, self) + .get_queryset(request) + .select_related("editor", "level", "teacher") + ) def update_with_decitre(self, request, queryset): for book in queryset: @@ -147,15 +241,15 @@ class BookAdmin(ExportMixin, admin.ModelAdmin): book.update_from_decitre() messages.success( request, - f'Mise à jour réussie du livre "{book.title}" ({book.level.name} - {book.field})' + f'Mise à jour réussie du livre "{book.title}" ({book.level.name} - {book.field})', ) except ISBNError as e: messages.warning( request, - f'Erreur lors de la mise à jour du livre "{book.title}" ({book.level.name} - {book.field}) : {e.data.get("error")}' + f'Erreur lors de la mise à jour du livre "{book.title}" ({book.level.name} - {book.field}) : {e.data.get("error")}', ) - update_with_decitre.short_description = 'Mettre à jour avec Decitre' + update_with_decitre.short_description = "Mettre à jour avec Decitre" def mark_as_done(self, request, queryset): queryset.update(done=True) @@ -171,25 +265,41 @@ class EditorAdmin(admin.ModelAdmin): @admin.register(CommonSupply) class CommonSupplyAdmin(admin.ModelAdmin): - list_display = ['name', 'order'] - list_display_links = ['name'] - list_editable = ['order'] + list_display = ["name", "order"] + list_display_links = ["name"] + list_editable = ["order"] class SuppliesResource(resources.ModelResource): class Meta: model = SuppliesRequirement - fields = ('supplies', 'field', 'level__name', 'teacher__first_name', 'teacher__last_name') - export_order = ('level__name', 'field', 'supplies', 'teacher__first_name', 'teacher__last_name') + fields = ( + "supplies", + "field", + "level__name", + "teacher__first_name", + "teacher__last_name", + ) + export_order = ( + "level__name", + "field", + "supplies", + "teacher__first_name", + "teacher__last_name", + ) @admin.register(SuppliesRequirement) class SuppliesRequirementAdmin(ExportMixin, admin.ModelAdmin): resource_class = SuppliesResource - list_display = ['id', 'teacher', 'level', 'field', 'supplies', 'done'] - list_editable = ['done'] - readonly_fields = ['created_at', 'updated_at'] - list_filter = ['done', 'teacher', 'level'] + list_display = ["id", "teacher", "level", "field", "supplies", "done"] + list_editable = ["done"] + readonly_fields = ["created_at", "updated_at"] + list_filter = ["done", "teacher", "level"] def get_queryset(self, request): - return super(SuppliesRequirementAdmin, self).get_queryset(request).select_related("level", "teacher") + return ( + super(SuppliesRequirementAdmin, self) + .get_queryset(request) + .select_related("level", "teacher") + ) diff --git a/manuels/apps.py b/manuels/apps.py index 7596237..d60f07b 100644 --- a/manuels/apps.py +++ b/manuels/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class ManuelsConfig(AppConfig): - name = 'manuels' + name = "manuels" diff --git a/manuels/context_processors.py b/manuels/context_processors.py index bf38854..379fd9a 100644 --- a/manuels/context_processors.py +++ b/manuels/context_processors.py @@ -2,4 +2,4 @@ from django.conf import settings def authorized_mails(request): - return {'authorized_mails': settings.AUTHORIZED_EMAILS} + return {"authorized_mails": settings.AUTHORIZED_EMAILS} diff --git a/manuels/forms.py b/manuels/forms.py index 1a9e84b..b6902fc 100644 --- a/manuels/forms.py +++ b/manuels/forms.py @@ -1,93 +1,136 @@ from django import forms from django.core.exceptions import ValidationError -from manuels.models import Book, SuppliesRequirement, Level +from manuels.models import Book, Level, SuppliesRequirement class EditBookForm(forms.ModelForm): class Meta: model = Book - fields = ['teacher', 'level', 'field', 'no_book', 'see_later', 'title', 'authors', 'editor', 'other_editor', - 'publication_year', 'isbn', 'price', 'previously_acquired', 'comments', 'consumable'] + fields = [ + "teacher", + "level", + "field", + "no_book", + "see_later", + "title", + "authors", + "editor", + "other_editor", + "publication_year", + "isbn", + "price", + "previously_acquired", + "comments", + "consumable", + ] - no_book = forms.BooleanField(label='Pas de livre pour cette classe/matière', required=False, initial=False) + no_book = forms.BooleanField( + label="Pas de livre pour cette classe/matière", required=False, initial=False + ) see_later = forms.BooleanField( - label='Voir à la rentrée', help_text="Notamment en cas de désaccord sur l'adoption ou non d'un manuel", - required=False, initial=False + label="Voir à la rentrée", + help_text="Notamment en cas de désaccord sur l'adoption ou non d'un manuel", + required=False, + initial=False, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['title'].widget = forms.TextInput() - self.fields['authors'].widget = forms.TextInput() - self.fields['comments'].widget.attrs.update(rows=3) - self.fields['teacher'].widget.attrs.update({'class': 'custom-select'}) - self.fields['editor'].widget.attrs.update({'class': 'custom-select'}) - self.fields['previously_acquired'].widget.attrs.update({'class': 'custom-select'}) - self.fields['consumable'].widget.attrs.update({'class': 'custom-select'}) - if 'level' in self.fields: - self.fields['level'].widget.attrs.update({'class': 'custom-select'}) + self.fields["title"].widget = forms.TextInput() + self.fields["authors"].widget = forms.TextInput() + self.fields["comments"].widget.attrs.update(rows=3) + self.fields["teacher"].widget.attrs.update({"class": "custom-select"}) + self.fields["editor"].widget.attrs.update({"class": "custom-select"}) + self.fields["previously_acquired"].widget.attrs.update( + {"class": "custom-select"} + ) + self.fields["consumable"].widget.attrs.update({"class": "custom-select"}) + if "level" in self.fields: + self.fields["level"].widget.attrs.update({"class": "custom-select"}) def clean(self): - editor = self.cleaned_data['editor'] - other_editor = self.cleaned_data['other_editor'] - title = self.cleaned_data['title'] + editor = self.cleaned_data["editor"] + other_editor = self.cleaned_data["other_editor"] + title = self.cleaned_data["title"] - if (editor - and 'autre' in editor.name.lower() - and not other_editor - and title not in ['PAS DE LIVRE POUR CETTE CLASSE', 'VOIR À LA RENTRÉE']): + if ( + editor + and "autre" in editor.name.lower() + and not other_editor + and title not in ["PAS DE LIVRE POUR CETTE CLASSE", "VOIR À LA RENTRÉE"] + ): self.add_error( - 'other_editor', + "other_editor", ValidationError( "Vous devez préciser l'éditeur si vous n'en choisissez pas un parmi la liste.", - code='missing' - ) + code="missing", + ), ) def clean_previously_acquired(self): - data = self.cleaned_data['previously_acquired'] - if data is None or data == '': - raise ValidationError('Vous devez choisir une valeur') + data = self.cleaned_data["previously_acquired"] + if data is None or data == "": + raise ValidationError("Vous devez choisir une valeur") return data class AddBookForm(EditBookForm): class Meta(EditBookForm.Meta): - fields = ['teacher', 'levels', 'field', 'no_book', 'see_later', 'title', 'authors', 'editor', 'other_editor', - 'publication_year', 'isbn', 'price', 'previously_acquired', 'comments', 'add_another', 'consumable'] + fields = [ + "teacher", + "levels", + "field", + "no_book", + "see_later", + "title", + "authors", + "editor", + "other_editor", + "publication_year", + "isbn", + "price", + "previously_acquired", + "comments", + "add_another", + "consumable", + ] - add_another = forms.BooleanField(label='Ajouter un autre livre', required=False, initial=True) + add_another = forms.BooleanField( + label="Ajouter un autre livre", required=False, initial=True + ) levels = forms.ModelMultipleChoiceField( queryset=Level.objects.all(), - label='Classes', + label="Classes", required=True, - help_text='Maintenez la touche Ctrl (ou Cmd) enfoncée pour en sélectionner plusieurs.' + help_text="Maintenez la touche Ctrl (ou Cmd) enfoncée pour en sélectionner plusieurs.", ) class EditSuppliesForm(forms.ModelForm): class Meta: model = SuppliesRequirement - fields = ['teacher', 'level', 'field', 'supplies'] + fields = ["teacher", "level", "field", "supplies"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['supplies'].widget.attrs.update(rows=3) - self.fields['teacher'].widget.attrs.update({'class': 'custom-select'}) - if 'level' in self.fields: - self.fields['level'].widget.attrs.update({'class': 'custom-select'}) + self.fields["supplies"].widget.attrs.update(rows=3) + self.fields["teacher"].widget.attrs.update({"class": "custom-select"}) + if "level" in self.fields: + self.fields["level"].widget.attrs.update({"class": "custom-select"}) class AddSuppliesForm(EditSuppliesForm): class Meta(EditSuppliesForm.Meta): - fields = ['teacher', 'levels', 'field', 'supplies'] + fields = ["teacher", "levels", "field", "supplies"] - add_another = forms.BooleanField(label="Ajouter d'autres fournitures", required=False, initial=True) + add_another = forms.BooleanField( + label="Ajouter d'autres fournitures", required=False, initial=True + ) levels = forms.ModelMultipleChoiceField( queryset=Level.objects.all(), - label='Classes', + label="Classes", required=True, - help_text='Maintenez la touche Ctrl (ou Cmd) enfoncée pour en sélectionner plusieurs.' + help_text="Maintenez la touche Ctrl (ou Cmd) enfoncée pour en sélectionner plusieurs.", ) diff --git a/manuels/management/commands/clearcache.py b/manuels/management/commands/clearcache.py index c1f0595..ef0ac8e 100644 --- a/manuels/management/commands/clearcache.py +++ b/manuels/management/commands/clearcache.py @@ -3,7 +3,7 @@ from django.core.management import BaseCommand class Command(BaseCommand): - help = 'Clears django cache' + help = "Clears django cache" def handle(self, *args, **options): cache.clear() diff --git a/manuels/migrations/0001_initial.py b/manuels/migrations/0001_initial.py index 80868e1..49d77a3 100644 --- a/manuels/migrations/0001_initial.py +++ b/manuels/migrations/0001_initial.py @@ -1,71 +1,142 @@ # Generated by Django 2.0.5 on 2018-05-21 22:47 -from django.db import migrations, models -import django.db.models.deletion -import manuels.models import uuid +import django.db.models.deletion +from django.db import migrations, models + +import manuels.models + class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Book', + name="Book", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field', models.CharField(max_length=100, verbose_name='matière')), - ('title', models.TextField(verbose_name='titre')), - ('authors', models.TextField(verbose_name='auteurs')), - ('editor', models.CharField(max_length=200, verbose_name='éditeur')), - ('collection', models.CharField(blank=True, max_length=200, verbose_name='collection')), - ('publication_year', models.PositiveIntegerField(verbose_name='année de publication')), - ('isbn', models.CharField(max_length=20, validators=[manuels.models.isbn_validator], verbose_name='ISBN/EAN')), - ('price', models.PositiveIntegerField(verbose_name='prix')), - ('previously_acquired', models.BooleanField(choices=[(True, 'Oui'), (False, 'Non')], verbose_name="manuel acquis précédemment par l'élève")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field", models.CharField(max_length=100, verbose_name="matière")), + ("title", models.TextField(verbose_name="titre")), + ("authors", models.TextField(verbose_name="auteurs")), + ("editor", models.CharField(max_length=200, verbose_name="éditeur")), + ( + "collection", + models.CharField( + blank=True, max_length=200, verbose_name="collection" + ), + ), + ( + "publication_year", + models.PositiveIntegerField(verbose_name="année de publication"), + ), + ( + "isbn", + models.CharField( + max_length=20, + validators=[manuels.models.isbn_validator], + verbose_name="ISBN/EAN", + ), + ), + ("price", models.PositiveIntegerField(verbose_name="prix")), + ( + "previously_acquired", + models.BooleanField( + choices=[(True, "Oui"), (False, "Non")], + verbose_name="manuel acquis précédemment par l'élève", + ), + ), ], options={ - 'verbose_name': 'livre', - 'verbose_name_plural': 'livres', + "verbose_name": "livre", + "verbose_name_plural": "livres", }, ), migrations.CreateModel( - name='Level', + name="Level", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=10, verbose_name='nom')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=10, verbose_name="nom")), ], options={ - 'verbose_name': 'classe', - 'verbose_name_plural': 'classes', + "verbose_name": "classe", + "verbose_name_plural": "classes", }, ), migrations.CreateModel( - name='Teacher', + name="Teacher", fields=[ - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('first_name', models.CharField(max_length=100, verbose_name='prénom')), - ('last_name', models.CharField(max_length=100, verbose_name='nom')), - ('phone_number', models.CharField(help_text="En cas d'urgence", max_length=10, verbose_name='numéro de téléphone')), - ('email', models.EmailField(help_text='Utilisée pour vous transmettre votre lien personnel', max_length=254, unique=True, verbose_name='adresse email')), + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("first_name", models.CharField(max_length=100, verbose_name="prénom")), + ("last_name", models.CharField(max_length=100, verbose_name="nom")), + ( + "phone_number", + models.CharField( + help_text="En cas d'urgence", + max_length=10, + verbose_name="numéro de téléphone", + ), + ), + ( + "email", + models.EmailField( + help_text="Utilisée pour vous transmettre votre lien personnel", + max_length=254, + unique=True, + verbose_name="adresse email", + ), + ), ], options={ - 'verbose_name': 'enseignant', - 'verbose_name_plural': 'enseignants', + "verbose_name": "enseignant", + "verbose_name_plural": "enseignants", }, ), migrations.AddField( - model_name='book', - name='level', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manuels.Level', verbose_name='classe'), + model_name="book", + name="level", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="manuels.Level", + verbose_name="classe", + ), ), migrations.AddField( - model_name='book', - name='teacher', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manuels.Teacher', verbose_name='enseignant'), + model_name="book", + name="teacher", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="manuels.Teacher", + verbose_name="enseignant", + ), ), ] diff --git a/manuels/migrations/0002_auto_20180522_0132.py b/manuels/migrations/0002_auto_20180522_0132.py index 555438f..d32cdc8 100644 --- a/manuels/migrations/0002_auto_20180522_0132.py +++ b/manuels/migrations/0002_auto_20180522_0132.py @@ -1,30 +1,43 @@ # Generated by Django 2.0.5 on 2018-05-21 23:32 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0001_initial'), + ("manuels", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Editor', + name="Editor", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50, verbose_name='nom')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50, verbose_name="nom")), ], options={ - 'verbose_name': 'éditeur', - 'verbose_name_plural': 'éditeurs', + "verbose_name": "éditeur", + "verbose_name_plural": "éditeurs", }, ), migrations.AlterField( - model_name='book', - name='editor', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manuels.Editor', verbose_name='éditeur'), + model_name="book", + name="editor", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="manuels.Editor", + verbose_name="éditeur", + ), ), ] diff --git a/manuels/migrations/0003_auto_20180522_0145.py b/manuels/migrations/0003_auto_20180522_0145.py index 5e80aec..0124d93 100644 --- a/manuels/migrations/0003_auto_20180522_0145.py +++ b/manuels/migrations/0003_auto_20180522_0145.py @@ -1,58 +1,66 @@ # Generated by Django 2.0.5 on 2018-05-21 23:45 -from django.db import migrations, models import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0002_auto_20180522_0132'), + ("manuels", "0002_auto_20180522_0132"), ] operations = [ migrations.AddField( - model_name='book', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + model_name="book", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), preserve_default=False, ), migrations.AddField( - model_name='book', - name='updated_at', + model_name="book", + name="updated_at", field=models.DateTimeField(auto_now=True), ), migrations.AddField( - model_name='editor', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + model_name="editor", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), preserve_default=False, ), migrations.AddField( - model_name='editor', - name='updated_at', + model_name="editor", + name="updated_at", field=models.DateTimeField(auto_now=True), ), migrations.AddField( - model_name='level', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + model_name="level", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), preserve_default=False, ), migrations.AddField( - model_name='level', - name='updated_at', + model_name="level", + name="updated_at", field=models.DateTimeField(auto_now=True), ), migrations.AddField( - model_name='teacher', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + model_name="teacher", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), preserve_default=False, ), migrations.AddField( - model_name='teacher', - name='updated_at', + model_name="teacher", + name="updated_at", field=models.DateTimeField(auto_now=True), ), ] diff --git a/manuels/migrations/0004_auto_20180522_0148.py b/manuels/migrations/0004_auto_20180522_0148.py index 37a7a02..1c03cf9 100644 --- a/manuels/migrations/0004_auto_20180522_0148.py +++ b/manuels/migrations/0004_auto_20180522_0148.py @@ -6,48 +6,48 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0003_auto_20180522_0145'), + ("manuels", "0003_auto_20180522_0145"), ] operations = [ migrations.AlterField( - model_name='book', - name='created_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='créé le'), + model_name="book", + name="created_at", + field=models.DateTimeField(auto_now_add=True, verbose_name="créé le"), ), migrations.AlterField( - model_name='book', - name='updated_at', - field=models.DateTimeField(auto_now=True, verbose_name='mis à jour le'), + model_name="book", + name="updated_at", + field=models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), ), migrations.AlterField( - model_name='editor', - name='created_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='créé le'), + model_name="editor", + name="created_at", + field=models.DateTimeField(auto_now_add=True, verbose_name="créé le"), ), migrations.AlterField( - model_name='editor', - name='updated_at', - field=models.DateTimeField(auto_now=True, verbose_name='mis à jour le'), + model_name="editor", + name="updated_at", + field=models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), ), migrations.AlterField( - model_name='level', - name='created_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='créé le'), + model_name="level", + name="created_at", + field=models.DateTimeField(auto_now_add=True, verbose_name="créé le"), ), migrations.AlterField( - model_name='level', - name='updated_at', - field=models.DateTimeField(auto_now=True, verbose_name='mis à jour le'), + model_name="level", + name="updated_at", + field=models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), ), migrations.AlterField( - model_name='teacher', - name='created_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='créé le'), + model_name="teacher", + name="created_at", + field=models.DateTimeField(auto_now_add=True, verbose_name="créé le"), ), migrations.AlterField( - model_name='teacher', - name='updated_at', - field=models.DateTimeField(auto_now=True, verbose_name='mis à jour le'), + model_name="teacher", + name="updated_at", + field=models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), ), ] diff --git a/manuels/migrations/0005_suppliesrequirement.py b/manuels/migrations/0005_suppliesrequirement.py index f604619..e8c290f 100644 --- a/manuels/migrations/0005_suppliesrequirement.py +++ b/manuels/migrations/0005_suppliesrequirement.py @@ -1,29 +1,59 @@ # Generated by Django 2.0.5 on 2018-05-22 07:34 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0004_auto_20180522_0148'), + ("manuels", "0004_auto_20180522_0148"), ] operations = [ migrations.CreateModel( - name='SuppliesRequirement', + name="SuppliesRequirement", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='créé le')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='mis à jour le')), - ('supplies', models.TextField(verbose_name='fournitures')), - ('level', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manuels.Level', verbose_name='classe')), - ('teacher', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manuels.Teacher', verbose_name='enseignant')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="créé le"), + ), + ( + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), + ), + ("supplies", models.TextField(verbose_name="fournitures")), + ( + "level", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="manuels.Level", + verbose_name="classe", + ), + ), + ( + "teacher", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="manuels.Teacher", + verbose_name="enseignant", + ), + ), ], options={ - 'verbose_name': 'demande de fournitures', - 'verbose_name_plural': 'demandes de fournitures', + "verbose_name": "demande de fournitures", + "verbose_name_plural": "demandes de fournitures", }, ), ] diff --git a/manuels/migrations/0006_auto_20180522_1009.py b/manuels/migrations/0006_auto_20180522_1009.py index d9b79ae..309ee9e 100644 --- a/manuels/migrations/0006_auto_20180522_1009.py +++ b/manuels/migrations/0006_auto_20180522_1009.py @@ -6,13 +6,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0005_suppliesrequirement'), + ("manuels", "0005_suppliesrequirement"), ] operations = [ migrations.AlterField( - model_name='book', - name='previously_acquired', - field=models.BooleanField(choices=[(True, 'Oui'), (False, 'Non')], default=False, verbose_name="manuel acquis précédemment par l'élève"), + model_name="book", + name="previously_acquired", + field=models.BooleanField( + choices=[(True, "Oui"), (False, "Non")], + default=False, + verbose_name="manuel acquis précédemment par l'élève", + ), ), ] diff --git a/manuels/migrations/0007_auto_20180522_1026.py b/manuels/migrations/0007_auto_20180522_1026.py index 82c0fb6..0efa5f3 100644 --- a/manuels/migrations/0007_auto_20180522_1026.py +++ b/manuels/migrations/0007_auto_20180522_1026.py @@ -6,13 +6,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0006_auto_20180522_1009'), + ("manuels", "0006_auto_20180522_1009"), ] operations = [ migrations.AlterField( - model_name='book', - name='previously_acquired', - field=models.BooleanField(choices=[(False, 'Non'), (True, 'Oui')], default=False, verbose_name="manuel acquis précédemment par l'élève"), + model_name="book", + name="previously_acquired", + field=models.BooleanField( + choices=[(False, "Non"), (True, "Oui")], + default=False, + verbose_name="manuel acquis précédemment par l'élève", + ), ), ] diff --git a/manuels/migrations/0008_auto_20180522_1051.py b/manuels/migrations/0008_auto_20180522_1051.py index 944c03a..46cc57d 100644 --- a/manuels/migrations/0008_auto_20180522_1051.py +++ b/manuels/migrations/0008_auto_20180522_1051.py @@ -1,39 +1,64 @@ # Generated by Django 2.0.5 on 2018-05-22 08:51 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0007_auto_20180522_1026'), + ("manuels", "0007_auto_20180522_1026"), ] operations = [ migrations.AlterField( - model_name='book', - name='editor', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Editor', verbose_name='éditeur'), + model_name="book", + name="editor", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Editor", + verbose_name="éditeur", + ), ), migrations.AlterField( - model_name='book', - name='level', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Level', verbose_name='classe'), + model_name="book", + name="level", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Level", + verbose_name="classe", + ), ), migrations.AlterField( - model_name='book', - name='teacher', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Teacher', verbose_name='enseignant'), + model_name="book", + name="teacher", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Teacher", + verbose_name="enseignant", + ), ), migrations.AlterField( - model_name='suppliesrequirement', - name='level', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Level', verbose_name='classe'), + model_name="suppliesrequirement", + name="level", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Level", + verbose_name="classe", + ), ), migrations.AlterField( - model_name='suppliesrequirement', - name='teacher', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Teacher', verbose_name='enseignant'), + model_name="suppliesrequirement", + name="teacher", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Teacher", + verbose_name="enseignant", + ), ), ] diff --git a/manuels/migrations/0009_suppliesrequirement_field.py b/manuels/migrations/0009_suppliesrequirement_field.py index 515d3bf..5e15a87 100644 --- a/manuels/migrations/0009_suppliesrequirement_field.py +++ b/manuels/migrations/0009_suppliesrequirement_field.py @@ -6,14 +6,14 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0008_auto_20180522_1051'), + ("manuels", "0008_auto_20180522_1051"), ] operations = [ migrations.AddField( - model_name='suppliesrequirement', - name='field', - field=models.CharField(default='', max_length=100, verbose_name='matière'), + model_name="suppliesrequirement", + name="field", + field=models.CharField(default="", max_length=100, verbose_name="matière"), preserve_default=False, ), ] diff --git a/manuels/migrations/0010_remove_book_collection.py b/manuels/migrations/0010_remove_book_collection.py index 3f6f3dc..7318d36 100644 --- a/manuels/migrations/0010_remove_book_collection.py +++ b/manuels/migrations/0010_remove_book_collection.py @@ -6,12 +6,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0009_suppliesrequirement_field'), + ("manuels", "0009_suppliesrequirement_field"), ] operations = [ migrations.RemoveField( - model_name='book', - name='collection', + model_name="book", + name="collection", ), ] diff --git a/manuels/migrations/0011_auto_20180524_0013.py b/manuels/migrations/0011_auto_20180524_0013.py index 673c4d4..996d0ed 100644 --- a/manuels/migrations/0011_auto_20180524_0013.py +++ b/manuels/migrations/0011_auto_20180524_0013.py @@ -1,19 +1,25 @@ # Generated by Django 2.0.5 on 2018-05-23 22:13 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0010_remove_book_collection'), + ("manuels", "0010_remove_book_collection"), ] operations = [ migrations.AlterField( - model_name='teacher', - name='phone_number', - field=models.CharField(help_text="En cas d'urgence, 10 chiffres.", max_length=10, validators=[manuels.models.phone_validator], verbose_name='numéro de téléphone'), + model_name="teacher", + name="phone_number", + field=models.CharField( + help_text="En cas d'urgence, 10 chiffres.", + max_length=10, + validators=[manuels.models.phone_validator], + verbose_name="numéro de téléphone", + ), ), ] diff --git a/manuels/migrations/0012_auto_20180524_0014.py b/manuels/migrations/0012_auto_20180524_0014.py index 604295c..6ffa47a 100644 --- a/manuels/migrations/0012_auto_20180524_0014.py +++ b/manuels/migrations/0012_auto_20180524_0014.py @@ -1,19 +1,25 @@ # Generated by Django 2.0.5 on 2018-05-23 22:14 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0011_auto_20180524_0013'), + ("manuels", "0011_auto_20180524_0013"), ] operations = [ migrations.AlterField( - model_name='book', - name='isbn', - field=models.CharField(help_text='Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X', max_length=20, validators=[manuels.models.isbn_validator], verbose_name='ISBN/EAN'), + model_name="book", + name="isbn", + field=models.CharField( + help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X", + max_length=20, + validators=[manuels.models.isbn_validator], + verbose_name="ISBN/EAN", + ), ), ] diff --git a/manuels/migrations/0013_auto_20180524_0016.py b/manuels/migrations/0013_auto_20180524_0016.py index fe8b02f..6a6c759 100644 --- a/manuels/migrations/0013_auto_20180524_0016.py +++ b/manuels/migrations/0013_auto_20180524_0016.py @@ -6,28 +6,28 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0012_auto_20180524_0014'), + ("manuels", "0012_auto_20180524_0014"), ] operations = [ migrations.AlterField( - model_name='book', - name='field', - field=models.CharField(max_length=200, verbose_name='matière'), + model_name="book", + name="field", + field=models.CharField(max_length=200, verbose_name="matière"), ), migrations.AlterField( - model_name='editor', - name='name', - field=models.CharField(max_length=100, verbose_name='nom'), + model_name="editor", + name="name", + field=models.CharField(max_length=100, verbose_name="nom"), ), migrations.AlterField( - model_name='level', - name='name', - field=models.CharField(max_length=50, verbose_name='nom'), + model_name="level", + name="name", + field=models.CharField(max_length=50, verbose_name="nom"), ), migrations.AlterField( - model_name='suppliesrequirement', - name='field', - field=models.CharField(max_length=200, verbose_name='matière'), + model_name="suppliesrequirement", + name="field", + field=models.CharField(max_length=200, verbose_name="matière"), ), ] diff --git a/manuels/migrations/0014_auto_20180524_0034.py b/manuels/migrations/0014_auto_20180524_0034.py index 5b595d4..ec7368f 100644 --- a/manuels/migrations/0014_auto_20180524_0034.py +++ b/manuels/migrations/0014_auto_20180524_0034.py @@ -6,13 +6,13 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0013_auto_20180524_0016'), + ("manuels", "0013_auto_20180524_0016"), ] operations = [ migrations.RenameField( - model_name='suppliesrequirement', - old_name='field', - new_name='fields', + model_name="suppliesrequirement", + old_name="field", + new_name="fields", ), ] diff --git a/manuels/migrations/0015_auto_20180524_0035.py b/manuels/migrations/0015_auto_20180524_0035.py index b34b0c5..eec599d 100644 --- a/manuels/migrations/0015_auto_20180524_0035.py +++ b/manuels/migrations/0015_auto_20180524_0035.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0014_auto_20180524_0034'), + ("manuels", "0014_auto_20180524_0034"), ] operations = [ migrations.AlterField( - model_name='suppliesrequirement', - name='fields', - field=models.TextField(verbose_name='matières'), + model_name="suppliesrequirement", + name="fields", + field=models.TextField(verbose_name="matières"), ), ] diff --git a/manuels/migrations/0016_auto_20180530_1801.py b/manuels/migrations/0016_auto_20180530_1801.py index 8a17686..a816947 100644 --- a/manuels/migrations/0016_auto_20180530_1801.py +++ b/manuels/migrations/0016_auto_20180530_1801.py @@ -6,18 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0015_auto_20180524_0035'), + ("manuels", "0015_auto_20180524_0035"), ] operations = [ migrations.AlterField( - model_name='book', - name='field', - field=models.CharField(max_length=200, verbose_name='discipline'), + model_name="book", + name="field", + field=models.CharField(max_length=200, verbose_name="discipline"), ), migrations.AlterField( - model_name='suppliesrequirement', - name='fields', - field=models.TextField(verbose_name='disciplines'), + model_name="suppliesrequirement", + name="fields", + field=models.TextField(verbose_name="disciplines"), ), ] diff --git a/manuels/migrations/0017_auto_20180530_1804.py b/manuels/migrations/0017_auto_20180530_1804.py index a4d9e1a..34ee2c9 100644 --- a/manuels/migrations/0017_auto_20180530_1804.py +++ b/manuels/migrations/0017_auto_20180530_1804.py @@ -6,18 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0016_auto_20180530_1801'), + ("manuels", "0016_auto_20180530_1801"), ] operations = [ migrations.AddField( - model_name='book', - name='done', - field=models.BooleanField(default=False, verbose_name='Traité'), + model_name="book", + name="done", + field=models.BooleanField(default=False, verbose_name="Traité"), ), migrations.AddField( - model_name='suppliesrequirement', - name='done', - field=models.BooleanField(default=False, verbose_name='Traité'), + model_name="suppliesrequirement", + name="done", + field=models.BooleanField(default=False, verbose_name="Traité"), ), ] diff --git a/manuels/migrations/0018_book_comments.py b/manuels/migrations/0018_book_comments.py index 97a6d27..9a7fc34 100644 --- a/manuels/migrations/0018_book_comments.py +++ b/manuels/migrations/0018_book_comments.py @@ -6,14 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0017_auto_20180530_1804'), + ("manuels", "0017_auto_20180530_1804"), ] operations = [ migrations.AddField( - model_name='book', - name='comments', - field=models.TextField(default='', help_text="Ce message sera visible par la documentaliste. Vous pouvez l'utiliser par exemple si vous souhaitez saisir un éditeur qui n'est pas proposé.", verbose_name='commentaires'), + model_name="book", + name="comments", + field=models.TextField( + default="", + help_text="Ce message sera visible par la documentaliste. Vous pouvez l'utiliser par exemple si vous souhaitez saisir un éditeur qui n'est pas proposé.", + verbose_name="commentaires", + ), preserve_default=False, ), ] diff --git a/manuels/migrations/0019_auto_20180531_0815.py b/manuels/migrations/0019_auto_20180531_0815.py index deb96cd..3d9048b 100644 --- a/manuels/migrations/0019_auto_20180531_0815.py +++ b/manuels/migrations/0019_auto_20180531_0815.py @@ -6,13 +6,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0018_book_comments'), + ("manuels", "0018_book_comments"), ] operations = [ migrations.AlterField( - model_name='book', - name='comments', - field=models.TextField(blank=True, help_text="Ce message sera visible par la documentaliste. Vous pouvez l'utiliser par exemple si vous souhaitez saisir un éditeur qui n'est pas proposé.", verbose_name='commentaires'), + model_name="book", + name="comments", + field=models.TextField( + blank=True, + help_text="Ce message sera visible par la documentaliste. Vous pouvez l'utiliser par exemple si vous souhaitez saisir un éditeur qui n'est pas proposé.", + verbose_name="commentaires", + ), ), ] diff --git a/manuels/migrations/0020_auto_20180602_1630.py b/manuels/migrations/0020_auto_20180602_1630.py index abe1859..224058b 100644 --- a/manuels/migrations/0020_auto_20180602_1630.py +++ b/manuels/migrations/0020_auto_20180602_1630.py @@ -1,28 +1,41 @@ # Generated by Django 2.0.5 on 2018-06-02 14:30 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0019_auto_20180531_0815'), + ("manuels", "0019_auto_20180531_0815"), ] operations = [ migrations.AlterModelOptions( - name='teacher', - options={'verbose_name': 'coordonnateur', 'verbose_name_plural': 'coordonnateurs'}, + name="teacher", + options={ + "verbose_name": "coordonnateur", + "verbose_name_plural": "coordonnateurs", + }, ), migrations.AlterField( - model_name='book', - name='teacher', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Teacher', verbose_name='coordonnateur'), + model_name="book", + name="teacher", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Teacher", + verbose_name="coordonnateur", + ), ), migrations.AlterField( - model_name='suppliesrequirement', - name='teacher', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='manuels.Teacher', verbose_name='coordonnateur'), + model_name="suppliesrequirement", + name="teacher", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manuels.Teacher", + verbose_name="coordonnateur", + ), ), ] diff --git a/manuels/migrations/0021_auto_20180602_1638.py b/manuels/migrations/0021_auto_20180602_1638.py index e1c57cf..0367001 100644 --- a/manuels/migrations/0021_auto_20180602_1638.py +++ b/manuels/migrations/0021_auto_20180602_1638.py @@ -6,16 +6,24 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0020_auto_20180602_1630'), + ("manuels", "0020_auto_20180602_1630"), ] operations = [ migrations.AlterModelOptions( - name='editor', - options={'ordering': ['name'], 'verbose_name': 'éditeur', 'verbose_name_plural': 'éditeurs'}, + name="editor", + options={ + "ordering": ["name"], + "verbose_name": "éditeur", + "verbose_name_plural": "éditeurs", + }, ), migrations.AlterModelOptions( - name='teacher', - options={'ordering': ['first_name'], 'verbose_name': 'coordonnateur', 'verbose_name_plural': 'coordonnateurs'}, + name="teacher", + options={ + "ordering": ["first_name"], + "verbose_name": "coordonnateur", + "verbose_name_plural": "coordonnateurs", + }, ), ] diff --git a/manuels/migrations/0022_teacher_has_confirmed_list.py b/manuels/migrations/0022_teacher_has_confirmed_list.py index 592c7c8..b40cfcf 100644 --- a/manuels/migrations/0022_teacher_has_confirmed_list.py +++ b/manuels/migrations/0022_teacher_has_confirmed_list.py @@ -6,13 +6,15 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0021_auto_20180602_1638'), + ("manuels", "0021_auto_20180602_1638"), ] operations = [ migrations.AddField( - model_name='teacher', - name='has_confirmed_list', - field=models.BooleanField(default=False, verbose_name='a confirmé les listes'), + model_name="teacher", + name="has_confirmed_list", + field=models.BooleanField( + default=False, verbose_name="a confirmé les listes" + ), ), ] diff --git a/manuels/migrations/0023_auto_20180604_1827.py b/manuels/migrations/0023_auto_20180604_1827.py index 3b4f141..bf1e6ed 100644 --- a/manuels/migrations/0023_auto_20180604_1827.py +++ b/manuels/migrations/0023_auto_20180604_1827.py @@ -1,19 +1,23 @@ # Generated by Django 2.0.5 on 2018-06-04 16:27 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0022_teacher_has_confirmed_list'), + ("manuels", "0022_teacher_has_confirmed_list"), ] operations = [ migrations.AlterField( - model_name='book', - name='price', - field=models.FloatField(validators=[manuels.models.positive_float_validator], verbose_name='prix'), + model_name="book", + name="price", + field=models.FloatField( + validators=[manuels.models.positive_float_validator], + verbose_name="prix", + ), ), ] diff --git a/manuels/migrations/0024_book_other_editor.py b/manuels/migrations/0024_book_other_editor.py index bfb1372..7e386c1 100644 --- a/manuels/migrations/0024_book_other_editor.py +++ b/manuels/migrations/0024_book_other_editor.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0023_auto_20180604_1827'), + ("manuels", "0023_auto_20180604_1827"), ] operations = [ migrations.AddField( - model_name='book', - name='other_editor', - field=models.CharField(blank=True, max_length=100, verbose_name='préciser'), + model_name="book", + name="other_editor", + field=models.CharField(blank=True, max_length=100, verbose_name="préciser"), ), ] diff --git a/manuels/migrations/0025_auto_20180607_0746.py b/manuels/migrations/0025_auto_20180607_0746.py index 4fbe86d..f24d6d1 100644 --- a/manuels/migrations/0025_auto_20180607_0746.py +++ b/manuels/migrations/0025_auto_20180607_0746.py @@ -6,13 +6,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0024_book_other_editor'), + ("manuels", "0024_book_other_editor"), ] operations = [ migrations.AlterField( - model_name='book', - name='comments', - field=models.TextField(blank=True, help_text='Ce message sera visible par la documentaliste.', verbose_name='commentaires'), + model_name="book", + name="comments", + field=models.TextField( + blank=True, + help_text="Ce message sera visible par la documentaliste.", + verbose_name="commentaires", + ), ), ] diff --git a/manuels/migrations/0026_auto_20180616_0916.py b/manuels/migrations/0026_auto_20180616_0916.py index fbc46a3..4b7ebc7 100644 --- a/manuels/migrations/0026_auto_20180616_0916.py +++ b/manuels/migrations/0026_auto_20180616_0916.py @@ -1,19 +1,25 @@ # Generated by Django 2.0.6 on 2018-06-16 07:16 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0025_auto_20180607_0746'), + ("manuels", "0025_auto_20180607_0746"), ] operations = [ migrations.AlterField( - model_name='book', - name='isbn', - field=models.CharField(help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à13 chiffres (ou EAN)", max_length=20, validators=[manuels.models.isbn_validator], verbose_name='ISBN/EAN'), + model_name="book", + name="isbn", + field=models.CharField( + help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à13 chiffres (ou EAN)", + max_length=20, + validators=[manuels.models.isbn_validator], + verbose_name="ISBN/EAN", + ), ), ] diff --git a/manuels/migrations/0027_auto_20190401_2036.py b/manuels/migrations/0027_auto_20190401_2036.py index 92fb48a..6ed3c67 100644 --- a/manuels/migrations/0027_auto_20190401_2036.py +++ b/manuels/migrations/0027_auto_20190401_2036.py @@ -6,28 +6,34 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0026_auto_20180616_0916'), + ("manuels", "0026_auto_20180616_0916"), ] operations = [ migrations.AlterField( - model_name='book', - name='done', - field=models.BooleanField(blank=True, default=False, verbose_name='Traité'), + model_name="book", + name="done", + field=models.BooleanField(blank=True, default=False, verbose_name="Traité"), ), migrations.AlterField( - model_name='book', - name='previously_acquired', - field=models.BooleanField(choices=[(None, '------------'), (False, 'Non'), (True, 'Oui')], default=None, verbose_name="manuel acquis précédemment par l'élève"), + model_name="book", + name="previously_acquired", + field=models.BooleanField( + choices=[(None, "------------"), (False, "Non"), (True, "Oui")], + default=None, + verbose_name="manuel acquis précédemment par l'élève", + ), ), migrations.AlterField( - model_name='suppliesrequirement', - name='done', - field=models.BooleanField(blank=True, default=False, verbose_name='Traité'), + model_name="suppliesrequirement", + name="done", + field=models.BooleanField(blank=True, default=False, verbose_name="Traité"), ), migrations.AlterField( - model_name='teacher', - name='has_confirmed_list', - field=models.BooleanField(blank=True, default=False, verbose_name='a confirmé les listes'), + model_name="teacher", + name="has_confirmed_list", + field=models.BooleanField( + blank=True, default=False, verbose_name="a confirmé les listes" + ), ), ] diff --git a/manuels/migrations/0028_auto_20190406_1901.py b/manuels/migrations/0028_auto_20190406_1901.py index 809c119..e6e26df 100644 --- a/manuels/migrations/0028_auto_20190406_1901.py +++ b/manuels/migrations/0028_auto_20190406_1901.py @@ -6,23 +6,31 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0027_auto_20190401_2036'), + ("manuels", "0027_auto_20190401_2036"), ] operations = [ migrations.AlterModelOptions( - name='level', - options={'ordering': ['order', 'name'], 'verbose_name': 'classe', 'verbose_name_plural': 'classes'}, + name="level", + options={ + "ordering": ["order", "name"], + "verbose_name": "classe", + "verbose_name_plural": "classes", + }, ), migrations.AddField( - model_name='book', - name='consumable', - field=models.BooleanField(default=False, help_text="Exemple : un cahier d'exercices est un consommable", verbose_name='consommable'), + model_name="book", + name="consumable", + field=models.BooleanField( + default=False, + help_text="Exemple : un cahier d'exercices est un consommable", + verbose_name="consommable", + ), preserve_default=False, ), migrations.AddField( - model_name='level', - name='order', - field=models.IntegerField(default=0, verbose_name='ordre'), + model_name="level", + name="order", + field=models.IntegerField(default=0, verbose_name="ordre"), ), ] diff --git a/manuels/migrations/0029_auto_20190406_1904.py b/manuels/migrations/0029_auto_20190406_1904.py index a1ce6d9..f6ad178 100644 --- a/manuels/migrations/0029_auto_20190406_1904.py +++ b/manuels/migrations/0029_auto_20190406_1904.py @@ -6,13 +6,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0028_auto_20190406_1901'), + ("manuels", "0028_auto_20190406_1901"), ] operations = [ migrations.AlterField( - model_name='book', - name='consumable', - field=models.BooleanField(choices=[(None, '------------'), (False, 'Non'), (True, 'Oui')], default=None, help_text="Exemple : un cahier d'exercices est un consommable", verbose_name='consommable'), + model_name="book", + name="consumable", + field=models.BooleanField( + choices=[(None, "------------"), (False, "Non"), (True, "Oui")], + default=None, + help_text="Exemple : un cahier d'exercices est un consommable", + verbose_name="consommable", + ), ), ] diff --git a/manuels/migrations/0030_auto_20190406_1912.py b/manuels/migrations/0030_auto_20190406_1912.py index b2cd359..31a5fb1 100644 --- a/manuels/migrations/0030_auto_20190406_1912.py +++ b/manuels/migrations/0030_auto_20190406_1912.py @@ -6,13 +6,13 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0029_auto_20190406_1904'), + ("manuels", "0029_auto_20190406_1904"), ] operations = [ migrations.RenameField( - model_name='suppliesrequirement', - old_name='fields', - new_name='field', + model_name="suppliesrequirement", + old_name="fields", + new_name="field", ), ] diff --git a/manuels/migrations/0031_auto_20190406_1912.py b/manuels/migrations/0031_auto_20190406_1912.py index 482c44d..593b146 100644 --- a/manuels/migrations/0031_auto_20190406_1912.py +++ b/manuels/migrations/0031_auto_20190406_1912.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0030_auto_20190406_1912'), + ("manuels", "0030_auto_20190406_1912"), ] operations = [ migrations.AlterField( - model_name='suppliesrequirement', - name='field', - field=models.CharField(max_length=50, verbose_name='disciplines'), + model_name="suppliesrequirement", + name="field", + field=models.CharField(max_length=50, verbose_name="disciplines"), ), ] diff --git a/manuels/migrations/0032_auto_20190406_1913.py b/manuels/migrations/0032_auto_20190406_1913.py index 5d283a3..ea52709 100644 --- a/manuels/migrations/0032_auto_20190406_1913.py +++ b/manuels/migrations/0032_auto_20190406_1913.py @@ -6,13 +6,13 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0031_auto_20190406_1912'), + ("manuels", "0031_auto_20190406_1912"), ] operations = [ migrations.AlterField( - model_name='suppliesrequirement', - name='field', - field=models.CharField(max_length=50, verbose_name='discipline'), + model_name="suppliesrequirement", + name="field", + field=models.CharField(max_length=50, verbose_name="discipline"), ), ] diff --git a/manuels/migrations/0033_auto_20190406_1919.py b/manuels/migrations/0033_auto_20190406_1919.py index 1b359a8..60a0a13 100644 --- a/manuels/migrations/0033_auto_20190406_1919.py +++ b/manuels/migrations/0033_auto_20190406_1919.py @@ -1,19 +1,25 @@ # Generated by Django 2.2 on 2019-04-06 17:19 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0032_auto_20190406_1913'), + ("manuels", "0032_auto_20190406_1913"), ] operations = [ migrations.AlterField( - model_name='book', - name='isbn', - field=models.CharField(help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à 13 chiffres (ou EAN)", max_length=20, validators=[manuels.models.isbn_validator], verbose_name='ISBN/EAN'), + model_name="book", + name="isbn", + field=models.CharField( + help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à 13 chiffres (ou EAN)", + max_length=20, + validators=[manuels.models.isbn_validator], + verbose_name="ISBN/EAN", + ), ), ] diff --git a/manuels/migrations/0034_commonsupply.py b/manuels/migrations/0034_commonsupply.py index cbeb924..968fec0 100644 --- a/manuels/migrations/0034_commonsupply.py +++ b/manuels/migrations/0034_commonsupply.py @@ -6,21 +6,35 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0033_auto_20190406_1919'), + ("manuels", "0033_auto_20190406_1919"), ] operations = [ migrations.CreateModel( - name='CommonSupply', + name="CommonSupply", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='créé le')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='mis à jour le')), - ('name', models.CharField(max_length=200, verbose_name='nom')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="créé le"), + ), + ( + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="mis à jour le"), + ), + ("name", models.CharField(max_length=200, verbose_name="nom")), ], options={ - 'verbose_name': 'fourniture commune', - 'verbose_name_plural': 'fournitures communes', + "verbose_name": "fourniture commune", + "verbose_name_plural": "fournitures communes", }, ), ] diff --git a/manuels/migrations/0035_commonsupply_order.py b/manuels/migrations/0035_commonsupply_order.py index c2d4f0b..961b1f7 100644 --- a/manuels/migrations/0035_commonsupply_order.py +++ b/manuels/migrations/0035_commonsupply_order.py @@ -6,14 +6,14 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0034_commonsupply'), + ("manuels", "0034_commonsupply"), ] operations = [ migrations.AddField( - model_name='commonsupply', - name='order', - field=models.IntegerField(default=0, verbose_name='ordre'), + model_name="commonsupply", + name="order", + field=models.IntegerField(default=0, verbose_name="ordre"), preserve_default=False, ), ] diff --git a/manuels/migrations/0036_auto_20190615_1114.py b/manuels/migrations/0036_auto_20190615_1114.py index 78adc3f..1d0fbf5 100644 --- a/manuels/migrations/0036_auto_20190615_1114.py +++ b/manuels/migrations/0036_auto_20190615_1114.py @@ -6,12 +6,16 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0035_commonsupply_order'), + ("manuels", "0035_commonsupply_order"), ] operations = [ migrations.AlterModelOptions( - name='commonsupply', - options={'ordering': ('order',), 'verbose_name': 'fourniture commune', 'verbose_name_plural': 'fournitures communes'}, + name="commonsupply", + options={ + "ordering": ("order",), + "verbose_name": "fourniture commune", + "verbose_name_plural": "fournitures communes", + }, ), ] diff --git a/manuels/migrations/0037_auto_20190627_1905.py b/manuels/migrations/0037_auto_20190627_1905.py index 9a13cdb..f9fb27d 100644 --- a/manuels/migrations/0037_auto_20190627_1905.py +++ b/manuels/migrations/0037_auto_20190627_1905.py @@ -8,18 +8,27 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('manuels', '0036_auto_20190615_1114'), + ("manuels", "0036_auto_20190615_1114"), ] operations = [ migrations.AlterModelOptions( - name='commonsupply', - options={'ordering': ('order', 'name'), 'verbose_name': 'fourniture commune', 'verbose_name_plural': 'fournitures communes'}, + name="commonsupply", + options={ + "ordering": ("order", "name"), + "verbose_name": "fourniture commune", + "verbose_name_plural": "fournitures communes", + }, ), CITextExtension(), migrations.AlterField( - model_name='teacher', - name='email', - field=django.contrib.postgres.fields.citext.CIEmailField(help_text='Utilisée pour vous transmettre votre lien personnel', max_length=254, unique=True, verbose_name='adresse email'), + model_name="teacher", + name="email", + field=django.contrib.postgres.fields.citext.CIEmailField( + help_text="Utilisée pour vous transmettre votre lien personnel", + max_length=254, + unique=True, + verbose_name="adresse email", + ), ), ] diff --git a/manuels/migrations/0038_auto_20210510_0854.py b/manuels/migrations/0038_auto_20210510_0854.py index 91002bd..69a2508 100644 --- a/manuels/migrations/0038_auto_20210510_0854.py +++ b/manuels/migrations/0038_auto_20210510_0854.py @@ -1,19 +1,25 @@ # Generated by Django 3.0.7 on 2021-05-10 06:54 from django.db import migrations, models + import manuels.models class Migration(migrations.Migration): dependencies = [ - ('manuels', '0037_auto_20190627_1905'), + ("manuels", "0037_auto_20190627_1905"), ] operations = [ migrations.AlterField( - model_name='book', - name='isbn', - field=models.CharField(help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à 13 chiffres (ou EAN)", max_length=20, validators=[manuels.models.isbn_validator], verbose_name='ISBN/EAN du manuel élève (hors specimen)'), + model_name="book", + name="isbn", + field=models.CharField( + help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à 13 chiffres (ou EAN)", + max_length=20, + validators=[manuels.models.isbn_validator], + verbose_name="ISBN/EAN du manuel élève (hors specimen)", + ), ), ] diff --git a/manuels/models.py b/manuels/models.py index 473432f..23a3bbb 100644 --- a/manuels/models.py +++ b/manuels/models.py @@ -28,101 +28,105 @@ class BaseModel(models.Model): class Meta: abstract = True - created_at = models.DateTimeField('créé le', auto_now_add=True) - updated_at = models.DateTimeField('mis à jour le', auto_now=True) + created_at = models.DateTimeField("créé le", auto_now_add=True) + updated_at = models.DateTimeField("mis à jour le", auto_now=True) def phone_validator(value): - regex = re.compile(r'^\d{10}$') + regex = re.compile(r"^\d{10}$") if not regex.match(value): raise ValidationError( "%(value)s n'est pas un numéro de téléphone valide. Format attendu : 10 chiffres.", - params={'value': value} + params={"value": value}, ) class Teacher(BaseModel): class Meta: - verbose_name = 'coordonnateur' - verbose_name_plural = 'coordonnateurs' - ordering = ['first_name'] + verbose_name = "coordonnateur" + verbose_name_plural = "coordonnateurs" + ordering = ["first_name"] uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - first_name = models.CharField('prénom', max_length=100) - last_name = models.CharField('nom', max_length=100) + first_name = models.CharField("prénom", max_length=100) + last_name = models.CharField("nom", max_length=100) phone_number = models.CharField( - 'numéro de téléphone', + "numéro de téléphone", help_text="En cas d'urgence, 10 chiffres.", max_length=10, - validators=[phone_validator] + validators=[phone_validator], ) email = CIEmailField( - 'adresse email', - help_text='Utilisée pour vous transmettre votre lien personnel', - unique=True + "adresse email", + help_text="Utilisée pour vous transmettre votre lien personnel", + unique=True, ) has_confirmed_list = models.BooleanField( - 'a confirmé les listes', - default=False, - blank=True + "a confirmé les listes", default=False, blank=True ) def get_absolute_url(self): from django.urls import reverse - return reverse('list_books', kwargs={'pk': str(self.pk)}) + + return reverse("list_books", kwargs={"pk": str(self.pk)}) @property def full_name(self): - return f'{self.first_name} {self.last_name}' + return f"{self.first_name} {self.last_name}" def __str__(self): return self.full_name def send_link(self, request): dest = self.email - link = request.build_absolute_uri(reverse('list_books', args=[str(self.pk)])) + link = request.build_absolute_uri(reverse("list_books", args=[str(self.pk)])) msg = EmailMultiAlternatives( - subject='Gestion des manuels scolaires', - body=f'Bonjour {self.first_name},\n' - f'Voici votre lien pour la gestion des manuels scolaires : {link}', + subject="Gestion des manuels scolaires", + body=f"Bonjour {self.first_name},\n" + f"Voici votre lien pour la gestion des manuels scolaires : {link}", from_email=settings.SERVER_EMAIL, to=[dest], ) - reply_to = [os.getenv('REPLY_TO')] + reply_to = [os.getenv("REPLY_TO")] if reply_to: msg.reply_to = reply_to msg.attach_alternative( - render_to_string('manuels/emails_link.html', {'link': link, 'teacher': self}), "text/html" + render_to_string( + "manuels/emails_link.html", {"link": link, "teacher": self} + ), + "text/html", ) msg.send() def send_confirmation(self, request): dest = settings.LIBRARIAN_EMAILS - link = request.build_absolute_uri(reverse('home_page')) + link = request.build_absolute_uri(reverse("home_page")) msg = EmailMultiAlternatives( subject="Gestion des manuels scolaires - Confirmation d'un coordonnateur", - body=f'Bonjour,\n' - f'{self.first_name} a confirmé ses listes sur {link}', + body=f"Bonjour,\n" f"{self.first_name} a confirmé ses listes sur {link}", from_email=settings.SERVER_EMAIL, to=dest, ) - reply_to = [os.getenv('REPLY_TO')] + reply_to = [os.getenv("REPLY_TO")] if reply_to: msg.reply_to = reply_to msg.attach_alternative( - render_to_string('manuels/emails_confirmation.html', {'link': link, 'teacher': self}), "text/html" + render_to_string( + "manuels/emails_confirmation.html", {"link": link, "teacher": self} + ), + "text/html", ) msg.send() class Level(BaseModel): class Meta: - verbose_name = 'classe' - verbose_name_plural = 'classes' - ordering = ['order', 'name'] + verbose_name = "classe" + verbose_name_plural = "classes" + ordering = ["order", "name"] - name = models.CharField('nom', max_length=50) - order = models.IntegerField('ordre', default=0) + name = models.CharField("nom", max_length=50) + order = models.IntegerField("ordre", default=0) def __str__(self): return self.name @@ -130,7 +134,10 @@ class Level(BaseModel): @property def non_acquired_consumables(self): if hasattr(self, "prefetched_books"): - return filter(lambda book: book.consumable and not book.previously_acquired, self.prefetched_books) + return filter( + lambda book: book.consumable and not book.previously_acquired, + self.prefetched_books, + ) return self.book_set.filter(consumable=True, previously_acquired=False) @property @@ -143,13 +150,17 @@ class Level(BaseModel): def non_acquired_consumable_price(self): if hasattr(self, "prefetched_books"): return sum(map(lambda book: book.price, self.non_acquired_consumables)) - return self.non_acquired_consumables.aggregate(Sum('price')).get( - 'price__sum', 0) + return self.non_acquired_consumables.aggregate(Sum("price")).get( + "price__sum", 0 + ) @property def non_acquired_books(self): if hasattr(self, "prefetched_books"): - return filter(lambda book: not book.consumable and not book.previously_acquired, self.prefetched_books) + return filter( + lambda book: not book.consumable and not book.previously_acquired, + self.prefetched_books, + ) return self.book_set.filter(consumable=False, previously_acquired=False) @property @@ -162,39 +173,41 @@ class Level(BaseModel): def non_acquired_book_price(self): if hasattr(self, "prefetched_books"): return sum(map(lambda book: book.price, self.non_acquired_books)) - return self.non_acquired_books.aggregate(Sum('price')).get( - 'price__sum', 0) + return self.non_acquired_books.aggregate(Sum("price")).get("price__sum", 0) @property def non_acquired_items(self): if hasattr(self, "prefetched_books"): - return filter(lambda book: not book.previously_acquired, self.prefetched_books) + return filter( + lambda book: not book.previously_acquired, self.prefetched_books + ) return self.book_set.filter(previously_acquired=False) @property def non_acquired_total_price(self): if hasattr(self, "prefetched_books"): return sum(map(lambda book: book.price, self.non_acquired_items)) - return self.non_acquired_items.aggregate(Sum('price')).get( - 'price__sum', 0) + return self.non_acquired_items.aggregate(Sum("price")).get("price__sum", 0) class Editor(BaseModel): class Meta: - verbose_name = 'éditeur' - verbose_name_plural = 'éditeurs' - ordering = ['name'] + verbose_name = "éditeur" + verbose_name_plural = "éditeurs" + ordering = ["name"] - name = models.CharField('nom', max_length=100) + name = models.CharField("nom", max_length=100) def __str__(self): return self.name def isbn_validator(value): - regex = re.compile(r'(\d-?){10,13}X?') + regex = re.compile(r"(\d-?){10,13}X?") if not regex.match(value): - raise ValidationError("%(value)s n'est pas un ISBN valide.", params={'value': value}) + raise ValidationError( + "%(value)s n'est pas un ISBN valide.", params={"value": value} + ) def positive_float_validator(value): @@ -209,30 +222,36 @@ def positive_float_validator(value): class Book(BaseModel): class Meta: - verbose_name = 'livre' - verbose_name_plural = 'livres' + verbose_name = "livre" + verbose_name_plural = "livres" - teacher = models.ForeignKey(verbose_name='coordonnateur', to=Teacher, on_delete=models.PROTECT, null=True) - level = models.ForeignKey(verbose_name='classe', to=Level, on_delete=models.PROTECT, null=True) - field = models.CharField('discipline', max_length=200) - title = models.TextField('titre') - authors = models.TextField('auteurs') - editor = models.ForeignKey(verbose_name='éditeur', to=Editor, on_delete=models.PROTECT, null=True) - other_editor = models.CharField(verbose_name='préciser', max_length=100, blank=True) - publication_year = models.PositiveIntegerField('année de publication') + teacher = models.ForeignKey( + verbose_name="coordonnateur", to=Teacher, on_delete=models.PROTECT, null=True + ) + level = models.ForeignKey( + verbose_name="classe", to=Level, on_delete=models.PROTECT, null=True + ) + field = models.CharField("discipline", max_length=200) + title = models.TextField("titre") + authors = models.TextField("auteurs") + editor = models.ForeignKey( + verbose_name="éditeur", to=Editor, on_delete=models.PROTECT, null=True + ) + other_editor = models.CharField(verbose_name="préciser", max_length=100, blank=True) + publication_year = models.PositiveIntegerField("année de publication") isbn = models.CharField( - 'ISBN/EAN du manuel élève (hors specimen)', + "ISBN/EAN du manuel élève (hors specimen)", max_length=20, help_text="Format attendu : 10 ou 13 chiffres, éventuellement séparés par des tirets et éventuellement " - "suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à " - "13 chiffres (ou EAN)", - validators=[isbn_validator] + "suivis de la lettre X. La recherche sur Decitre ne fonctionnera qu'avec un code ISBN à " + "13 chiffres (ou EAN)", + validators=[isbn_validator], ) - price = models.FloatField('prix', validators=[positive_float_validator]) + price = models.FloatField("prix", validators=[positive_float_validator]) YES_NO_CHOICE = ( - (None, '------------'), - (False, 'Non'), - (True, 'Oui'), + (None, "------------"), + (False, "Non"), + (True, "Oui"), ) previously_acquired = models.BooleanField( "manuel acquis précédemment par l'élève", @@ -240,18 +259,14 @@ class Book(BaseModel): blank=False, default=None, ) - done = models.BooleanField( - 'Traité', - blank=True, - default=False - ) + done = models.BooleanField("Traité", blank=True, default=False) comments = models.TextField( - 'commentaires', + "commentaires", blank=True, - help_text="Ce message sera visible par la documentaliste." + help_text="Ce message sera visible par la documentaliste.", ) consumable = models.BooleanField( - 'consommable', + "consommable", help_text="Exemple : un cahier d'exercices est un consommable", choices=YES_NO_CHOICE, blank=False, @@ -261,32 +276,35 @@ class Book(BaseModel): @property def previously_acquired_text(self): if self.previously_acquired: - return 'Oui' + return "Oui" else: - return 'Non' + return "Non" @property def consumable_text(self): if self.consumable: - return 'Oui' + return "Oui" else: - return 'Non' + return "Non" def __str__(self): - return f'{self.title} ({self.authors}) - {self.isbn}' + return f"{self.title} ({self.authors}) - {self.isbn}" def get_absolute_url(self): from django.urls import reverse - return reverse('edit_book', kwargs={'teacher_pk': str(self.teacher.pk), 'pk': str(self.pk)}) + + return reverse( + "edit_book", kwargs={"teacher_pk": str(self.teacher.pk), "pk": str(self.pk)} + ) def update_from_decitre(self): decitre_data = self.fetch_from_decitre(self.isbn) - self.title = decitre_data.get('title') - self.authors = decitre_data.get('authors') - self.price = decitre_data.get('price') - self.publication_year = decitre_data.get('year') + self.title = decitre_data.get("title") + self.authors = decitre_data.get("authors") + self.price = decitre_data.get("price") + self.publication_year = decitre_data.get("year") - editor = decitre_data.get('editor') + editor = decitre_data.get("editor") potential_editor = ( Editor.objects.filter(name__iexact=editor).first() or Editor.objects.filter(name__icontains=editor).first() @@ -302,31 +320,35 @@ class Book(BaseModel): @property def decitre_url(self): - isbn = self.isbn.strip().replace('-', '') + isbn = self.isbn.strip().replace("-", "") if not validate_isbn(isbn) or len(isbn) == 10: return "" - return f'https://www.decitre.fr/livres/{isbn}.html' + return f"https://www.decitre.fr/livres/{isbn}.html" @staticmethod def fetch_from_decitre(isbn: str): - isbn = isbn.strip().replace('-', '') + isbn = isbn.strip().replace("-", "") if not validate_isbn(isbn): - raise ISBNError({ - 'error': "L'ISBN saisi n'est pas valide." - }) + raise ISBNError({"error": "L'ISBN saisi n'est pas valide."}) if len(isbn) == 10: - raise ISBNError({ - 'error': "La recherche sur Decitre ne fonctionne qu'avec un ISBN 13 (ou EAN)." - }) + raise ISBNError( + { + "error": "La recherche sur Decitre ne fonctionne qu'avec un ISBN 13 (ou EAN)." + } + ) try: - res = requests.get(f'https://www.decitre.fr/livres/{isbn}.html', timeout=10) + res = requests.get(f"https://www.decitre.fr/livres/{isbn}.html", timeout=10) except requests.exceptions.Timeout as exc: - raise ISBNError({ - 'error': "Decitre n'a pas répondu dans les temps. Message : {}".format(str(exc)) - }) + raise ISBNError( + { + "error": "Decitre n'a pas répondu dans les temps. Message : {}".format( + str(exc) + ) + } + ) try: res.raise_for_status() @@ -334,89 +356,92 @@ class Book(BaseModel): message = ( "Erreur lors de la recherche. Il se peut que le livre n'existe pas dans la base de connaissances " "de Decitre ou que vous ayez mal saisi l'ISBN. Vous pouvez toujours saisir " - "les informations du livre à la main. Message : {}").format(str(exc)) - raise ISBNError({ - 'error': message - }) + "les informations du livre à la main. Message : {}" + ).format(str(exc)) + raise ISBNError({"error": message}) decitre_soup = bs4.BeautifulSoup(res.text, "html.parser") - title = decitre_soup.select('h1.product-title') + title = decitre_soup.select("h1.product-title") if title: title = title[0] if title.span: title.span.extract() title = title.get_text(strip=True) - authors = decitre_soup.select('.authors') + authors = decitre_soup.select(".authors") if authors: authors = authors[0] authors = authors.get_text(strip=True) - price = decitre_soup.select('.fp-top--add-to-cart div.price span.final-price') + price = decitre_soup.select(".fp-top--add-to-cart div.price span.final-price") if price: price = price[0] - price = price.get_text().replace('€', '').replace(',', '.').strip() + price = price.get_text().replace("€", "").replace(",", ".").strip() year = None editor = None - extra_info = decitre_soup.select('.informations-container') - logger.debug('raw extra_info') + extra_info = decitre_soup.select(".informations-container") + logger.debug("raw extra_info") logger.debug(extra_info) if not extra_info: - logger.debug('#fiche-technique') - extra_info = decitre_soup.select('#fiche-technique') - logger.debug('raw extra_info fiche technique') + logger.debug("#fiche-technique") + extra_info = decitre_soup.select("#fiche-technique") + logger.debug("raw extra_info fiche technique") logger.debug(extra_info) if extra_info: extra_info = extra_info[0].get_text(strip=True) - logger.debug('extra_info') + logger.debug("extra_info") logger.debug(extra_info) matches = re.search( - r'Date de parution(?: :)?\d{2}/\d{2}/(?P\d{4})Editeur(?: :)?(?P.+?)(?:ISBN|Collection)', - extra_info) + r"Date de parution(?: :)?\d{2}/\d{2}/(?P\d{4})Editeur(?: :)?(?P.+?)(?:ISBN|Collection)", + extra_info, + ) if matches: groups = matches.groupdict() - year = groups.get('year') - editor = groups.get('editor').strip() + year = groups.get("year") + editor = groups.get("editor").strip() return { - 'title': title, - 'authors': authors, - 'isbn': isbn, - 'price': float(price) if price else None, - 'year': year, - 'editor': editor, + "title": title, + "authors": authors, + "isbn": isbn, + "price": float(price) if price else None, + "year": year, + "editor": editor, } class SuppliesRequirement(BaseModel): class Meta: - verbose_name = 'demande de fournitures' - verbose_name_plural = 'demandes de fournitures' + verbose_name = "demande de fournitures" + verbose_name_plural = "demandes de fournitures" - teacher = models.ForeignKey(verbose_name='coordonnateur', to=Teacher, on_delete=models.PROTECT, null=True) - level = models.ForeignKey(verbose_name='classe', to=Level, on_delete=models.PROTECT, null=True) - field = models.CharField('discipline', max_length=50) - supplies = models.TextField('fournitures') - done = models.BooleanField( - 'Traité', - blank=True, - default=False + teacher = models.ForeignKey( + verbose_name="coordonnateur", to=Teacher, on_delete=models.PROTECT, null=True ) + level = models.ForeignKey( + verbose_name="classe", to=Level, on_delete=models.PROTECT, null=True + ) + field = models.CharField("discipline", max_length=50) + supplies = models.TextField("fournitures") + done = models.BooleanField("Traité", blank=True, default=False) def __str__(self): - return f'{self.supplies} pour {self.level} ({self.teacher})' + return f"{self.supplies} pour {self.level} ({self.teacher})" class CommonSupply(BaseModel): class Meta: - verbose_name = 'fourniture commune' - verbose_name_plural = 'fournitures communes' - ordering = ('order', 'name',) + verbose_name = "fourniture commune" + verbose_name_plural = "fournitures communes" + ordering = ( + "order", + "name", + ) - name = models.CharField('nom', max_length=200) - order = models.IntegerField('ordre') + name = models.CharField("nom", max_length=200) + order = models.IntegerField("ordre") def __str__(self): return self.name diff --git a/manuels/static/icons/.gitkeep b/manuels/static/icons/.gitkeep index 8b13789..e69de29 100644 --- a/manuels/static/icons/.gitkeep +++ b/manuels/static/icons/.gitkeep @@ -1 +0,0 @@ - diff --git a/manuels/templates/manuels/add_book.html b/manuels/templates/manuels/add_book.html index e6f20e3..c324c50 100644 --- a/manuels/templates/manuels/add_book.html +++ b/manuels/templates/manuels/add_book.html @@ -112,4 +112,4 @@ {% block end_js %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/manuels/templates/manuels/confirm_delete.html b/manuels/templates/manuels/confirm_delete.html index cc07478..7124460 100644 --- a/manuels/templates/manuels/confirm_delete.html +++ b/manuels/templates/manuels/confirm_delete.html @@ -7,4 +7,4 @@

{{ object }}

- \ No newline at end of file + diff --git a/manuels/templates/manuels/home_page.html b/manuels/templates/manuels/home_page.html index a072506..e3f8c5c 100644 --- a/manuels/templates/manuels/home_page.html +++ b/manuels/templates/manuels/home_page.html @@ -28,4 +28,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/manuels/templates/manuels/list_books_supplies.html b/manuels/templates/manuels/list_books_supplies.html index 77a6f91..c9abe75 100644 --- a/manuels/templates/manuels/list_books_supplies.html +++ b/manuels/templates/manuels/list_books_supplies.html @@ -144,4 +144,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/manuels/templates/manuels/supplies_message.html b/manuels/templates/manuels/supplies_message.html index b2cc35a..64a0ec0 100644 --- a/manuels/templates/manuels/supplies_message.html +++ b/manuels/templates/manuels/supplies_message.html @@ -8,4 +8,4 @@
  • {{ supply.name }}
  • {% endfor %} - \ No newline at end of file + diff --git a/manuels/tests/test_inscription.py b/manuels/tests/test_inscription.py index 31359c2..69d1efe 100644 --- a/manuels/tests/test_inscription.py +++ b/manuels/tests/test_inscription.py @@ -4,4 +4,3 @@ from django.test import TestCase class MyTestCase(TestCase): def test_something(self): self.assertEqual(True, False) - diff --git a/manuels/urls.py b/manuels/urls.py index b78ddec..903ac8c 100644 --- a/manuels/urls.py +++ b/manuels/urls.py @@ -1,24 +1,57 @@ from django.conf import settings -from django.urls import path, include +from django.urls import include, path -from manuels.views import AddBookView, ListBooksView, clear_teacher_view, AddSuppliesView, EditBookView, \ - EditSuppliesView, DeleteBookView, DeleteSuppliesView, ConfirmTeacherView, isbn_api +from manuels.views import ( + AddBookView, + AddSuppliesView, + ConfirmTeacherView, + DeleteBookView, + DeleteSuppliesView, + EditBookView, + EditSuppliesView, + ListBooksView, + clear_teacher_view, + isbn_api, +) urlpatterns = [ - path('teacher//add_book', AddBookView.as_view(), name='add_book'), - path('teacher//add_supplies', AddSuppliesView.as_view(), name='add_supplies'), - path('teacher/', ListBooksView.as_view(), name='list_books'), - path('teacher//book/', EditBookView.as_view(), name='edit_book'), - path('teacher//book//delete', DeleteBookView.as_view(), name='delete_book'), - path('teacher//supplies/', EditSuppliesView.as_view(), name='edit_supplies'), - path('teacher//supplies//delete', DeleteSuppliesView.as_view(), name='delete_supplies'), - path('teacher//confirm', ConfirmTeacherView.as_view(), name='confirm_teacher'), - path('clear', clear_teacher_view, name='clear_teacher'), - path('isbn_api/', isbn_api, name='isbn_api'), + path("teacher//add_book", AddBookView.as_view(), name="add_book"), + path( + "teacher//add_supplies", AddSuppliesView.as_view(), name="add_supplies" + ), + path("teacher/", ListBooksView.as_view(), name="list_books"), + path( + "teacher//book/", + EditBookView.as_view(), + name="edit_book", + ), + path( + "teacher//book//delete", + DeleteBookView.as_view(), + name="delete_book", + ), + path( + "teacher//supplies/", + EditSuppliesView.as_view(), + name="edit_supplies", + ), + path( + "teacher//supplies//delete", + DeleteSuppliesView.as_view(), + name="delete_supplies", + ), + path( + "teacher//confirm", + ConfirmTeacherView.as_view(), + name="confirm_teacher", + ), + path("clear", clear_teacher_view, name="clear_teacher"), + path("isbn_api/", isbn_api, name="isbn_api"), ] if settings.DEBUG: import debug_toolbar + urlpatterns = [ - path('__debug__/', include(debug_toolbar.urls)), + path("__debug__/", include(debug_toolbar.urls)), ] + urlpatterns diff --git a/manuels/utils.py b/manuels/utils.py index d527490..61292f9 100644 --- a/manuels/utils.py +++ b/manuels/utils.py @@ -2,7 +2,7 @@ def validate_isbn(isbn): _sum = 0 if len(isbn) == 10: for i, digit in enumerate(isbn): - if digit == 'X': + if digit == "X": digit = 10 else: digit = int(digit) diff --git a/manuels/views.py b/manuels/views.py index 88df650..88aac49 100644 --- a/manuels/views.py +++ b/manuels/views.py @@ -8,10 +8,10 @@ from django.http import HttpResponseRedirect, JsonResponse from django.shortcuts import redirect from django.urls import reverse from django.views.decorators.cache import cache_page -from django.views.generic import CreateView, UpdateView, DeleteView, TemplateView +from django.views.generic import CreateView, DeleteView, TemplateView, UpdateView from manuels.forms import AddBookForm, AddSuppliesForm, EditBookForm, EditSuppliesForm -from manuels.models import Teacher, Book, SuppliesRequirement, CommonSupply, ISBNError +from manuels.models import Book, CommonSupply, ISBNError, SuppliesRequirement, Teacher from manuels.utils import validate_isbn logger = logging.getLogger(__name__) @@ -19,13 +19,13 @@ logger = logging.getLogger(__name__) class HomePageView(CreateView): model = Teacher - fields = ['first_name', 'last_name', 'phone_number', 'email'] - template_name = 'manuels/home_page.html' + fields = ["first_name", "last_name", "phone_number", "email"] + template_name = "manuels/home_page.html" def get(self, request, *args, **kwargs): - teacher_pk = request.session.get('teacher_pk') + teacher_pk = request.session.get("teacher_pk") if teacher_pk: - return redirect('list_books', pk=teacher_pk) + return redirect("list_books", pk=teacher_pk) return super().get(request, *args, **kwargs) @@ -37,26 +37,31 @@ class HomePageView(CreateView): class BaseTeacherView: teacher = None - teacher_field = 'pk' + teacher_field = "pk" def dispatch(self, request, *args, **kwargs): - self.teacher = Teacher.objects.filter(pk=self.kwargs[self.teacher_field]).first() + self.teacher = Teacher.objects.filter( + pk=self.kwargs[self.teacher_field] + ).first() if not self.teacher: - messages.warning(request, "Impossible de trouver le coordonnateur demandé. Si vous pensez que ceci est " - "une erreur, merci de vous adresser à votre documentaliste.") - return redirect('clear_teacher') - request.session['teacher_pk'] = str(self.teacher.pk) + messages.warning( + request, + "Impossible de trouver le coordonnateur demandé. Si vous pensez que ceci est " + "une erreur, merci de vous adresser à votre documentaliste.", + ) + return redirect("clear_teacher") + request.session["teacher_pk"] = str(self.teacher.pk) return super().dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data() - context['teacher'] = self.teacher + context["teacher"] = self.teacher return context class ListBooksView(BaseTeacherView, TemplateView): - template_name = 'manuels/list_books_supplies.html' + template_name = "manuels/list_books_supplies.html" class ItemView(BaseTeacherView): @@ -66,79 +71,80 @@ class ItemView(BaseTeacherView): success_target = None message_template = None verb = None - button_class = 'primary' - button_icon = 'fas fa-check-circle' + button_class = "primary" + button_icon = "fas fa-check-circle" def dispatch(self, request, *args, **kwargs): response = super().dispatch(request, *args, **kwargs) if self.teacher and self.teacher.has_confirmed_list: - messages.error(request, "Vous avez déjà confirmé vos listes. Il n'est plus possible de les modifier.") - return redirect('list_books', pk=self.teacher.pk) + messages.error( + request, + "Vous avez déjà confirmé vos listes. Il n'est plus possible de les modifier.", + ) + return redirect("list_books", pk=self.teacher.pk) return response def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['item'] = self.item_text - context['item_plural'] = self.item_text_plural - context['message_template'] = self.message_template - context['verb'] = self.verb - context['button_class'] = self.button_class - context['button_icon'] = self.button_icon + context["item"] = self.item_text + context["item_plural"] = self.item_text_plural + context["message_template"] = self.message_template + context["verb"] = self.verb + context["button_class"] = self.button_class + context["button_icon"] = self.button_icon return context def get_initial(self): - return { - 'teacher': self.teacher - } + return {"teacher": self.teacher} def get_form(self, form_class=None): form = super().get_form(form_class) - form.fields['teacher'].queryset = Teacher.objects.filter(pk=self.teacher.pk) + form.fields["teacher"].queryset = Teacher.objects.filter(pk=self.teacher.pk) return form class AddItemView(ItemView, CreateView): - verb = 'Ajouter' - button_icon = 'fas fa-plus-circle' + verb = "Ajouter" + button_icon = "fas fa-plus-circle" def get_success_url(self): if self.add_another: return reverse(self.success_target, args=[str(self.teacher.pk)]) else: - return reverse('list_books', args=[str(self.teacher.pk)]) + return reverse("list_books", args=[str(self.teacher.pk)]) def form_valid(self, form): - self.add_another = form.cleaned_data['add_another'] + self.add_another = form.cleaned_data["add_another"] return HttpResponseRedirect(self.get_success_url()) class BookView: model = Book - success_target = 'add_book' - item_text = 'un livre' - item_text_plural = 'livres' + success_target = "add_book" + item_text = "un livre" + item_text_plural = "livres" class AddBookView(BookView, AddItemView): form_class = AddBookForm - template_name = 'manuels/add_book.html' + template_name = "manuels/add_book.html" def form_valid(self, form: AddBookForm): - for level in form.cleaned_data['levels']: + for level in form.cleaned_data["levels"]: book = Book.objects.create( - teacher=form.cleaned_data['teacher'], + teacher=form.cleaned_data["teacher"], level=level, - field=form.cleaned_data['field'], - title=form.cleaned_data['title'], - authors=form.cleaned_data['authors'], - editor=form.cleaned_data['editor'], - other_editor=form.cleaned_data['other_editor'], - publication_year=form.cleaned_data['publication_year'], - isbn=form.cleaned_data['isbn'], - price=form.cleaned_data['price'], - previously_acquired=form.cleaned_data['previously_acquired'], - comments=form.cleaned_data['comments'], - consumable=form.cleaned_data['consumable'], + field=form.cleaned_data["field"], + title=form.cleaned_data["title"], + authors=form.cleaned_data["authors"], + editor=form.cleaned_data["editor"], + other_editor=form.cleaned_data["other_editor"], + publication_year=form.cleaned_data["publication_year"], + isbn=form.cleaned_data["isbn"], + price=form.cleaned_data["price"], + previously_acquired=form.cleaned_data["previously_acquired"], + comments=form.cleaned_data["comments"], + consumable=form.cleaned_data["consumable"], ) messages.success(self.request, f'"{book}" a été ajouté.') @@ -147,28 +153,28 @@ class AddBookView(BookView, AddItemView): class SuppliesView: model = SuppliesRequirement - success_target = 'add_supplies' - item_text = 'des fournitures' - item_text_plural = 'fournitures' + success_target = "add_supplies" + item_text = "des fournitures" + item_text_plural = "fournitures" class AddSuppliesView(SuppliesView, AddItemView): form_class = AddSuppliesForm - message_template = 'manuels/supplies_message.html' - template_name = 'manuels/add_supplies.html' + message_template = "manuels/supplies_message.html" + template_name = "manuels/add_supplies.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['common_supplies'] = CommonSupply.objects.all() + context["common_supplies"] = CommonSupply.objects.all() return context def form_valid(self, form: AddBookForm): - for level in form.cleaned_data['levels']: + for level in form.cleaned_data["levels"]: supplies = SuppliesRequirement.objects.create( - teacher=form.cleaned_data['teacher'], + teacher=form.cleaned_data["teacher"], level=level, - field=form.cleaned_data['field'], - supplies=form.cleaned_data['supplies'], + field=form.cleaned_data["field"], + supplies=form.cleaned_data["supplies"], ) messages.success(self.request, f'"{supplies}" a été ajouté.') @@ -176,46 +182,46 @@ class AddSuppliesView(SuppliesView, AddItemView): class EditItemView(ItemView, UpdateView): - teacher_field = 'teacher_pk' + teacher_field = "teacher_pk" item_text = None item_text_plural = None message_template = None - verb = 'Modifier' + verb = "Modifier" def get_queryset(self): return self.model.objects.filter(teacher=self.teacher) def get_success_url(self): messages.success(self.request, f'"{self.object}" a été modifié.') - return reverse('list_books', args=[str(self.teacher.pk)]) + return reverse("list_books", args=[str(self.teacher.pk)]) class EditBookView(BookView, EditItemView): form_class = EditBookForm - template_name = 'manuels/add_book.html' + template_name = "manuels/add_book.html" class EditSuppliesView(SuppliesView, EditItemView): form_class = EditSuppliesForm - template_name = 'manuels/add_supplies.html' + template_name = "manuels/add_supplies.html" class DeleteItemView(ItemView, DeleteView): - teacher_field = 'teacher_pk' + teacher_field = "teacher_pk" item_text = None item_text_plural = None - message_template = 'manuels/confirm_delete.html' - verb = 'Supprimer' - button_class = 'danger' - button_icon = 'fas fa-trash' - template_name = 'manuels/add_supplies.html' + message_template = "manuels/confirm_delete.html" + verb = "Supprimer" + button_class = "danger" + button_icon = "fas fa-trash" + template_name = "manuels/add_supplies.html" def get_queryset(self): return self.model.objects.filter(teacher=self.teacher) def get_success_url(self): messages.success(self.request, f'"{self.object}" a été supprimé.') - return reverse('list_books', args=[str(self.teacher.pk)]) + return reverse("list_books", args=[str(self.teacher.pk)]) class DeleteBookView(BookView, DeleteItemView): @@ -227,22 +233,25 @@ class DeleteSuppliesView(SuppliesView, DeleteItemView): def clear_teacher_view(request): - if 'teacher_pk' in request.session: - del request.session['teacher_pk'] - return redirect('home_page') + if "teacher_pk" in request.session: + del request.session["teacher_pk"] + return redirect("home_page") class ConfirmTeacherView(BaseTeacherView, UpdateView): model = Teacher fields = [] - template_name = 'manuels/confirm_teacher.html' + template_name = "manuels/confirm_teacher.html" def form_valid(self, form): response = super().form_valid(form) self.object.has_confirmed_list = True self.object.save() self.object.send_confirmation(request=self.request) - messages.success(self.request, "Vos listes ont été validées. Votre documentaliste a été notifiée par email.") + messages.success( + self.request, + "Vos listes ont été validées. Votre documentaliste a été notifiée par email.", + ) return response diff --git a/manuels_collection/settings.py b/manuels_collection/settings.py index 46c805e..424a318 100644 --- a/manuels_collection/settings.py +++ b/manuels_collection/settings.py @@ -13,9 +13,9 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ import os from pathlib import Path +import environ from django.contrib.messages import constants as messages -import environ BASE_DIR = Path(__file__).resolve(strict=True).parent.parent env = environ.Env( @@ -27,8 +27,8 @@ env = environ.Env( SERVER_EMAIL=str, AUTHORIZED_EMAILS=(list, []), LIBRARIAN_EMAILS=(list, []), - MAILGUN_ACCESS_KEY=(str, ''), - MAILGUN_SERVER_NAME=(str, ''), + MAILGUN_ACCESS_KEY=(str, ""), + MAILGUN_SERVER_NAME=(str, ""), ) env_file = os.getenv("ENV_FILE", None) if env_file: @@ -39,36 +39,35 @@ if env_file: SECRET_KEY = env("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = env('DJANGO_ENV') == 'dev' +DEBUG = env("DJANGO_ENV") == "dev" -ALLOWED_HOSTS = ['web', '127.0.0.1'] +ALLOWED_HOSTS = ["web", "127.0.0.1"] if DEBUG: - ALLOWED_HOSTS.extend([ - 'localhost', - env('CURRENT_IP') - ]) + ALLOWED_HOSTS.extend(["localhost", env("CURRENT_IP")]) ALLOWED_HOSTS.extend(env("HOST")) -ADMINS = [('Gabriel', env('ADMIN_EMAIL')), ] -SERVER_EMAIL = env('SERVER_EMAIL') -EMAIL_SUBJECT_PREFIX = '[Manuels] ' +ADMINS = [ + ("Gabriel", env("ADMIN_EMAIL")), +] +SERVER_EMAIL = env("SERVER_EMAIL") +EMAIL_SUBJECT_PREFIX = "[Manuels] " -AUTHORIZED_EMAILS = env('AUTHORIZED_EMAILS') -LIBRARIAN_EMAILS = env('LIBRARIAN_EMAILS') +AUTHORIZED_EMAILS = env("AUTHORIZED_EMAILS") +LIBRARIAN_EMAILS = env("LIBRARIAN_EMAILS") # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'anymail', - 'bootstrap4', - 'manuels', - 'import_export', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "anymail", + "bootstrap4", + "manuels", + "import_export", ] if DEBUG: @@ -77,47 +76,47 @@ if DEBUG: ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'whitenoise.middleware.WhiteNoiseMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] if DEBUG: MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware") -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" -ROOT_URLCONF = 'manuels_collection.urls' +ROOT_URLCONF = "manuels_collection.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'manuels.context_processors.authorized_mails' + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "manuels.context_processors.authorized_mails", ], }, }, ] -WSGI_APPLICATION = 'manuels_collection.wsgi.application' +WSGI_APPLICATION = "manuels_collection.wsgi.application" # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases -default_db_path = BASE_DIR / 'db.sqlite3' +default_db_path = BASE_DIR / "db.sqlite3" DATABASES = { - 'default': env.db(default=f'sqlite:///{default_db_path}'), + "default": env.db(default=f"sqlite:///{default_db_path}"), } # Password validation @@ -125,16 +124,16 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -145,9 +144,9 @@ INTERNAL_IPS = [ # Internationalization # https://docs.djangoproject.com/en/2.0/topics/i18n/ -LANGUAGE_CODE = 'fr-fr' +LANGUAGE_CODE = "fr-fr" -TIME_ZONE = 'Europe/Paris' +TIME_ZONE = "Europe/Paris" USE_I18N = True @@ -156,53 +155,47 @@ USE_L10N = True USE_TZ = True # Logging -LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO' +LOG_LEVEL = "DEBUG" if DEBUG else "INFO" LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'verbose': { - 'format': '[%(asctime)s] [%(process)d] [%(levelname)s] %(module)s - %(message)s' + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "format": "[%(asctime)s] [%(process)d] [%(levelname)s] %(module)s - %(message)s" }, }, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - 'formatter': 'verbose' - }, + "handlers": { + "console": {"class": "logging.StreamHandler", "formatter": "verbose"}, }, - 'loggers': { - 'manuels': { - 'handlers': ['console'], - 'level': LOG_LEVEL - }, + "loggers": { + "manuels": {"handlers": ["console"], "level": LOG_LEVEL}, }, } # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = BASE_DIR / 'staticfiles' +STATIC_URL = "/static/" +STATIC_ROOT = BASE_DIR / "staticfiles" -LOGIN_REDIRECT_URL = 'rooms-list' +LOGIN_REDIRECT_URL = "rooms-list" ANYMAIL = { - "MAILGUN_API_KEY": env('MAILGUN_ACCESS_KEY'), - "MAILGUN_SENDER_DOMAIN": env('MAILGUN_SERVER_NAME'), + "MAILGUN_API_KEY": env("MAILGUN_ACCESS_KEY"), + "MAILGUN_SENDER_DOMAIN": env("MAILGUN_SERVER_NAME"), } -EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' +EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" MESSAGE_TAGS = { - messages.ERROR: 'danger', + messages.ERROR: "danger", } CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', - 'LOCATION': 'manuels_cache', + "default": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": "manuels_cache", } } -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/manuels_collection/urls.py b/manuels_collection/urls.py index 0dda5b9..18b2d1a 100644 --- a/manuels_collection/urls.py +++ b/manuels_collection/urls.py @@ -14,14 +14,14 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path, include +from django.urls import include, path from manuels.views import HomePageView -admin.site.site_header = 'Manuels scolaires - Administration' +admin.site.site_header = "Manuels scolaires - Administration" urlpatterns = [ - path('admin/', admin.site.urls), - path('', HomePageView.as_view(), name='home_page'), - path('', include('manuels.urls')), + path("admin/", admin.site.urls), + path("", HomePageView.as_view(), name="home_page"), + path("", include("manuels.urls")), ]