diff --git a/media/admin.py b/media/admin.py index 6ea0bd4..6e53ebb 100644 --- a/media/admin.py +++ b/media/admin.py @@ -5,9 +5,8 @@ from django.urls import reverse from django.utils.html import format_html from django.utils.translation import ugettext_lazy as _ -from reversion.admin import VersionAdmin - from med.admin import admin_site +from reversion.admin import VersionAdmin from .forms import MediaAdminForm from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga,\ diff --git a/media/forms.py b/media/forms.py index 5520db1..fa9d14f 100644 --- a/media/forms.py +++ b/media/forms.py @@ -45,7 +45,8 @@ def generate_side_identifier(title, authors, subtitle=None): authors = authors.copy() def sort(author): - return "{:042d}".format(-author.note) + author.name.split(" ")[-1] + ".{:042d}".format(author.pk) + return "{:042d}".format(-author.note) + author.name.split(" ")[-1]\ + + ".{:042d}".format(author.pk) authors.sort(key=sort) primary_author = authors[0] @@ -54,7 +55,8 @@ def generate_side_identifier(title, authors, subtitle=None): author_name = author_name.split(' ')[-1] author_name = ''.join( char for char in unicodedata.normalize('NFKD', author_name.casefold()) - if all(not unicodedata.category(char).startswith(cat) for cat in {'M', 'P', 'Z', 'C'}) or char == ' ' + if all(not unicodedata.category(char).startswith(cat) + for cat in {'M', 'P', 'Z', 'C'}) or char == ' ' ).casefold().upper() author_name = re.sub("[^A-Z]", "", author_name) side_identifier = "{:.3} {:.3}".format(author_name, title_normalized, ) @@ -68,9 +70,12 @@ def generate_side_identifier(title, authors, subtitle=None): side_identifier += " {:0>2}".format(start, ) # Normalize side identifier, in order to remove accents - side_identifier = ''.join(char for char in unicodedata.normalize('NFKD', side_identifier.casefold()) - if all(not unicodedata.category(char).startswith(cat) for cat in {'M', 'P', 'Z', 'C'}) - or char == ' ').casefold().upper() + side_identifier = ''.join( + char for char in unicodedata.normalize('NFKD', + side_identifier.casefold()) + if all(not unicodedata.category(char).startswith(cat) + for cat in {'M', 'P', 'Z', 'C'}) + or char == ' ').casefold().upper() return side_identifier @@ -85,15 +90,19 @@ class MediaAdminForm(ModelForm): side_identifier_field = self.fields.get('side_identifier') if side_identifier_field and self.instance and self.instance.pk: instance = self.instance - title, authors, subtitle = instance.title, instance.authors.all(), None + title, authors, subtitle = instance.title,\ + instance.authors.all(), None if hasattr(instance, "subtitle"): subtitle = instance.subtitle side_identifier_field.widget.attrs.update( - {'data-generated-side-identifier': generate_side_identifier(title, authors, subtitle)}) - side_identifier_field.widget.template_name = "media/generate_side_identifier.html" + {'data-generated-side-identifier': + generate_side_identifier(title, authors, subtitle)}) + side_identifier_field.widget.template_name =\ + "media/generate_side_identifier.html" def download_data_isbndb(self, isbn): - api_url = "https://api2.isbndb.com/book/" + str(isbn) + "?Authorization=" + os.getenv("ISBNDB_KEY", "") + api_url = "https://api2.isbndb.com/book/" + str(isbn)\ + + "?Authorization=" + os.getenv("ISBNDB_KEY", "") req = urllib.request.Request(api_url) req.add_header("Authorization", os.getenv("ISBNDB_KEY", "")) try: @@ -109,11 +118,13 @@ class MediaAdminForm(ModelForm): data.setdefault("image", "") self.cleaned_data["title"] = data["title"] self.cleaned_data["publish_date"] = data["date_published"][:10] - while len(self.cleaned_data["publish_date"]) == 4 or len(self.cleaned_data["publish_date"]) == 7: + while len(self.cleaned_data["publish_date"]) == 4 \ + or len(self.cleaned_data["publish_date"]) == 7: self.cleaned_data["publish_date"] += "-01" self.cleaned_data["number_of_pages"] = data["pages"] self.cleaned_data["authors"] = \ - list(Auteur.objects.get_or_create(name=author_name)[0] for author_name in data["authors"]) + list(Auteur.objects.get_or_create(name=author_name)[0] + for author_name in data["authors"]) self.cleaned_data["external_url"] = data["image"] return True @@ -333,4 +344,6 @@ class MediaAdminForm(ModelForm): class Meta: model = BD - fields = '__all__' + fields = ('isbn', 'title', 'subtitle', 'external_url', + 'side_identifier', 'authors', 'number_of_pages', + 'publish_date', 'present', ) diff --git a/media/management/commands/export_markdown_site.py b/media/management/commands/export_markdown_site.py index 40fae2c..0b3962a 100644 --- a/media/management/commands/export_markdown_site.py +++ b/media/management/commands/export_markdown_site.py @@ -1,6 +1,3 @@ -from argparse import FileType -from sys import stdin - from django.core.management import BaseCommand from media.models import BD, CD, Manga, Revue, Roman, Vinyle, Jeu @@ -18,47 +15,27 @@ class Command(BaseCommand): with open(directory + "/docs/index.md", "w") as f: f.write("# Media de la Mediatek\n\n\n") - f.write("Ce site répertorie l'intégralité des media présents à la Mediatek de l'ENS Paris-Saclay.\n") + f.write("Ce site répertorie l'intégralité des media présents " + "à la Mediatek de l'ENS Paris-Saclay.\n") - for model_class, file_name in [(BD, "bd.md"), (Manga, "mangas.md"), (Roman, "romans.md"), + for model_class, file_name in [(BD, "bd.md"), (Manga, "mangas.md"), + (Roman, "romans.md"), (CD, "cd.md"), (Vinyle, "vinyles.md")]: - with open(directory + "/docs/" + file_name, "w") as f: - f.write("# " + str(model_class._meta.verbose_name_plural).capitalize() + "\n\n\n") - - titles = list(set(obj["title"] for obj in model_class.objects.values("title").distinct().all())) - titles.sort() - - for title in titles: - f.write(f"## {title}\n\n\n") - - for medium in model_class.objects.filter(title=title).order_by("side_identifier").all(): - if hasattr(medium, "subtitle"): - f.write(f"### {medium.subtitle}\n\n\n") - if hasattr(medium, "isbn"): - f.write(f"ISBN : {medium.isbn}\n\n") - f.write(f"Cote : {medium.side_identifier}\n\n") - f.write("Auteurs : " + ", ".join(author.name for author in medium.authors.all()) + "\n\n") - if hasattr(medium, "number_of_pages"): - f.write(f"Nombre de pages : {medium.number_of_pages}\n\n") - if hasattr(medium, "rpm"): - f.write(f"Tours par minute : {medium.rpm}\n\n") - if hasattr(medium, "publish_date"): - f.write(f"Publié le : {medium.publish_date}\n\n") - if hasattr(medium, "external_url"): - f.write(f"Lien : [{medium.external_url}]({medium.external_url})\n\n") - f.write("\n\n\n") + self.process_model_class(model_class, file_name, f, directory) # Traitement différent pour les revues with open(directory + "/docs/revues.md", "w") as f: f.write("# Revues\n\n\n") - titles = list(set(obj["title"] for obj in Revue.objects.values("title").distinct().all())) + titles = list(set(obj["title"] for obj in + Revue.objects.values("title").distinct().all())) titles.sort() for title in titles: f.write(f"## {title}\n\n\n") - for medium in Revue.objects.filter(title=title).order_by("number").all(): + for medium in Revue.objects.filter(title=title)\ + .order_by("number").all(): f.write(f"### Numéro {medium.number}\n\n\n") if medium.double: f.write("Double revue\n\n") @@ -77,9 +54,46 @@ class Command(BaseCommand): for game in Jeu.objects.order_by("name").all(): f.write(f"## {game.name}\n\n\n") f.write(f"Durée : {game.duree}\n\n") - f.write(f"Nombre de joueurs : {game.nombre_joueurs_min} - {game.nombre_joueurs_max}\n\n") + f.write(f"Nombre de joueurs : {game.nombre_joueurs_min} " + f"- {game.nombre_joueurs_max}\n\n") if game.proprietaire.username != "Med": f.write(f"Propriétaire : {game.proprietaire.username}\n\n") if game.comment: f.write(f"Commentaire : {game.comment}\n\n") f.write("\n\n\n") + + def process_model_class(self, model_class, file_name, f, directory): + with open(directory + "/docs/" + file_name, "w") as f: + f.write("# " + str(model_class._meta.verbose_name_plural) + .capitalize() + "\n\n\n") + + titles = list(set(obj["title"] for obj in model_class.objects + .values("title").distinct().all())) + titles.sort() + + for title in titles: + f.write(f"## {title}\n\n\n") + + for medium in model_class.objects.filter(title=title) \ + .order_by("side_identifier").all(): + if hasattr(medium, "subtitle"): + f.write(f"### {medium.subtitle}\n\n\n") + if hasattr(medium, "isbn"): + f.write(f"ISBN : {medium.isbn}\n\n") + f.write(f"Cote : {medium.side_identifier}\n\n") + f.write("Auteurs : " + ", ".join( + author.name for author in medium.authors.all()) + + "\n\n") + if hasattr(medium, "number_of_pages"): + f.write(f"Nombre de pages : " + f"{medium.number_of_pages}\n\n") + if hasattr(medium, "rpm"): + f.write(f"Tours par minute : " + f"{medium.rpm}\n\n") + if hasattr(medium, "publish_date"): + f.write(f"Publié le : " + f"{medium.publish_date}\n\n") + if hasattr(medium, "external_url"): + f.write(f"Lien : [{medium.external_url}]" + f"({medium.external_url})\n\n") + f.write("\n\n\n") diff --git a/media/management/commands/import_future_media.py b/media/management/commands/import_future_media.py index 9ec6a49..c0b4c4b 100644 --- a/media/management/commands/import_future_media.py +++ b/media/management/commands/import_future_media.py @@ -1,7 +1,6 @@ from random import random from time import sleep -from django.core.exceptions import ValidationError from django.core.management import BaseCommand from media.forms import MediaAdminForm from media.models import BD, FutureMedia, Manga, Roman @@ -25,7 +24,9 @@ class Command(BaseCommand): continue if cl.objects.filter(isbn=isbn).exists(): - self.stderr.write(self.style.WARNING(f"ISBN {isbn} for type {type_str} already exists, remove it")) + self.stderr.write(self.style.WARNING( + f"ISBN {isbn} for type {type_str} already exists, " + f"remove it")) future_medium.delete() continue @@ -36,7 +37,8 @@ class Command(BaseCommand): try: form.full_clean() - if hasattr(form.instance, "subtitle") and not form.instance.subtitle: + if hasattr(form.instance, "subtitle") and \ + not form.instance.subtitle: form.instance.subtitle = "" form.save() future_medium.delete() @@ -46,4 +48,5 @@ class Command(BaseCommand): except Exception as e: self.stderr.write(self.style.WARNING( "An error occured while importing ISBN {isbn}: {error}" - .format(isbn=isbn, error=str(e.__class__) + "(" + str(e) + ")"))) + .format(isbn=isbn, + error=str(e.__class__) + "(" + str(e) + ")"))) diff --git a/media/management/commands/import_no_isbn_roman.py b/media/management/commands/import_no_isbn_roman.py index 0bbb739..e7adb0a 100644 --- a/media/management/commands/import_no_isbn_roman.py +++ b/media/management/commands/import_no_isbn_roman.py @@ -2,7 +2,6 @@ from argparse import FileType from sys import stdin from django.core.management import BaseCommand - from media.forms import generate_side_identifier from media.models import Roman, Auteur diff --git a/media/management/commands/regenerate_side_identifiers.py b/media/management/commands/regenerate_side_identifiers.py index c604b7f..35311ac 100644 --- a/media/management/commands/regenerate_side_identifiers.py +++ b/media/management/commands/regenerate_side_identifiers.py @@ -1,6 +1,5 @@ from django.core.management import BaseCommand from django.db import transaction - from media.forms import generate_side_identifier from media.models import BD, Manga, Roman @@ -11,11 +10,14 @@ class Command(BaseCommand): type=str, default='bd', choices=['bd', 'manga', 'roman'], - help="Type of medium where the sides need to be regenerated.") + help="Type of medium where the " + "sides need to be regenerated.") parser.add_argument('--noninteractivemode', '-ni', action="store_true", - help="Disable the interaction mode and replace existing side identifiers.") + help="Disable the interaction mode and replace " + "existing side identifiers.") parser.add_argument('--no-commit', '-nc', action="store_true", - help="Only show modifications, don't commit them to database.") + help="Only show modifications, don't commit " + "them to database.") @transaction.atomic def handle(self, *args, **options): @@ -37,23 +39,30 @@ class Command(BaseCommand): if not obj.authors.all(): self.stdout.write(str(obj)) subtitle = obj.subtitle if hasattr(obj, "subtitle") else None - generated_side_identifier = generate_side_identifier(obj.title, obj.authors.all(), subtitle) + generated_side_identifier = generate_side_identifier( + obj.title, obj.authors.all(), subtitle) if current_side_identifier != generated_side_identifier: answer = 'y' if interactive_mode: answer = '' while answer != 'y' and answer != 'n': - answer = input(f"For medium {obj}, current side: {current_side_identifier}, generated side: " - f"{generated_side_identifier}, would you like to replace ? [y/n]").lower()[0] + answer = input(f"For medium {obj}, current side: " + f"{current_side_identifier}, " + f"generated side: " + f"{generated_side_identifier}, " + f"would you like to replace ? [y/n]")\ + .lower()[0] if answer == 'y': - self.stdout.write(self.style.WARNING(f"Replace side of {obj} from {current_side_identifier} " - f"to {generated_side_identifier}...")) + self.stdout.write(self.style.WARNING( + f"Replace side of {obj} from {current_side_identifier}" + f" to {generated_side_identifier}...")) obj.side_identifier = generated_side_identifier if not options["no_commit"]: obj.save() replaced += 1 if replaced: - self.stdout.write(self.style.SUCCESS(f"{replaced} side identifiers were replaced.")) + self.stdout.write(self.style.SUCCESS( + f"{replaced} side identifiers were replaced.")) else: self.stdout.write(self.style.WARNING("Nothing changed.")) diff --git a/media/serializers.py b/media/serializers.py index 53cb0ea..a02b055 100644 --- a/media/serializers.py +++ b/media/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers -from .models import Auteur, BD, CD, FutureMedia, Manga, Emprunt, Jeu, Revue, Roman, Vinyle +from .models import Auteur, BD, CD, FutureMedia, Manga, Emprunt, Jeu, Revue,\ + Roman, Vinyle class AuteurSerializer(serializers.ModelSerializer): diff --git a/media/urls.py b/media/urls.py index 53eeb5a..ff61900 100644 --- a/media/urls.py +++ b/media/urls.py @@ -12,11 +12,25 @@ urlpatterns = [ url(r'^retour_emprunt/(?P[0-9]+)$', views.retour_emprunt, name='retour-emprunt'), path('find/', views.FindMediumView.as_view(), name="find"), - path('mark-as-present/bd//', views.MarkBDAsPresent.as_view(), name="mark_bd_as_present"), - path('mark-as-present/manga//', views.MarkMangaAsPresent.as_view(), name="mark_manga_as_present"), - path('mark-as-present/cd//', views.MarkCDAsPresent.as_view(), name="mark_cd_as_present"), - path('mark-as-present/vinyle//', views.MarkVinyleAsPresent.as_view(), name="mark_vinyle_as_present"), - path('mark-as-present/roman//', views.MarkRomanAsPresent.as_view(), name="mark_roman_as_present"), - path('mark-as-present/revue//', views.MarkRevueAsPresent.as_view(), name="mark_revue_as_present"), - path('mark-as-present/future//', views.MarkFutureAsPresent.as_view(), name="mark_future_as_present"), + path('mark-as-present/bd//', + views.MarkBDAsPresent.as_view(), + name="mark_bd_as_present"), + path('mark-as-present/manga//', + views.MarkMangaAsPresent.as_view(), + name="mark_manga_as_present"), + path('mark-as-present/cd//', + views.MarkCDAsPresent.as_view(), + name="mark_cd_as_present"), + path('mark-as-present/vinyle//', + views.MarkVinyleAsPresent.as_view(), + name="mark_vinyle_as_present"), + path('mark-as-present/roman//', + views.MarkRomanAsPresent.as_view(), + name="mark_roman_as_present"), + path('mark-as-present/revue//', + views.MarkRevueAsPresent.as_view(), + name="mark_revue_as_present"), + path('mark-as-present/future//', + views.MarkFutureAsPresent.as_view(), + name="mark_future_as_present"), ] diff --git a/media/views.py b/media/views.py index 1571a61..eb45dc4 100644 --- a/media/views.py +++ b/media/views.py @@ -1,7 +1,6 @@ # -*- mode: python; coding: utf-8 -*- # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from http.client import NO_CONTENT from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required @@ -17,9 +16,11 @@ from rest_framework import viewsets from rest_framework.filters import SearchFilter from reversion import revisions as reversion -from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga, Revue, Roman, Vinyle -from .serializers import AuteurSerializer, BDSerializer, CDSerializer, EmpruntSerializer, FutureMediaSerializer, \ - JeuSerializer, MangaSerializer, RevueSerializer, RomanSerializer, VinyleSerializer +from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga, Revue,\ + Roman, Vinyle +from .serializers import AuteurSerializer, BDSerializer, CDSerializer,\ + EmpruntSerializer, FutureMediaSerializer, JeuSerializer, MangaSerializer,\ + RevueSerializer, RomanSerializer, VinyleSerializer @login_required @@ -107,7 +108,8 @@ class BDViewSet(viewsets.ModelViewSet): serializer_class = BDSerializer filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ["isbn", "side_identifier"] - search_fields = ["=isbn", "title", "subtitle", "side_identifier", "authors__name"] + search_fields = ["=isbn", "title", "subtitle", "side_identifier", + "authors__name"] class MangaViewSet(viewsets.ModelViewSet): @@ -118,7 +120,8 @@ class MangaViewSet(viewsets.ModelViewSet): serializer_class = MangaSerializer filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ["isbn", "side_identifier"] - search_fields = ["=isbn", "title", "subtitle", "side_identifier", "authors__name"] + search_fields = ["=isbn", "title", "subtitle", "side_identifier", + "authors__name"] class CDViewSet(viewsets.ModelViewSet): @@ -151,7 +154,8 @@ class RomanViewSet(viewsets.ModelViewSet): serializer_class = RomanSerializer filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ["isbn", "side_identifier", "number_of_pages"] - search_fields = ["=isbn", "title", "subtitle", "side_identifier", "authors__name"] + search_fields = ["=isbn", "title", "subtitle", "side_identifier", + "authors__name"] class RevueViewSet(viewsets.ModelViewSet):