This commit is contained in:
Yohann D'ANELLO 2020-12-28 23:12:27 +01:00
parent b8ccb40ded
commit 74f453637a
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
9 changed files with 133 additions and 77 deletions

View File

@ -5,9 +5,8 @@
from django.urls import reverse from django.urls import reverse
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from reversion.admin import VersionAdmin
from med.admin import admin_site from med.admin import admin_site
from reversion.admin import VersionAdmin
from .forms import MediaAdminForm from .forms import MediaAdminForm
from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga,\ from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga,\

View File

@ -45,7 +45,8 @@ def generate_side_identifier(title, authors, subtitle=None):
authors = authors.copy() authors = authors.copy()
def sort(author): 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) authors.sort(key=sort)
primary_author = authors[0] primary_author = authors[0]
@ -54,7 +55,8 @@ def generate_side_identifier(title, authors, subtitle=None):
author_name = author_name.split(' ')[-1] author_name = author_name.split(' ')[-1]
author_name = ''.join( author_name = ''.join(
char for char in unicodedata.normalize('NFKD', author_name.casefold()) 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() ).casefold().upper()
author_name = re.sub("[^A-Z]", "", author_name) author_name = re.sub("[^A-Z]", "", author_name)
side_identifier = "{:.3} {:.3}".format(author_name, title_normalized, ) side_identifier = "{:.3} {:.3}".format(author_name, title_normalized, )
@ -68,8 +70,11 @@ def generate_side_identifier(title, authors, subtitle=None):
side_identifier += " {:0>2}".format(start, ) side_identifier += " {:0>2}".format(start, )
# Normalize side identifier, in order to remove accents # Normalize side identifier, in order to remove accents
side_identifier = ''.join(char for char in unicodedata.normalize('NFKD', side_identifier.casefold()) side_identifier = ''.join(
if all(not unicodedata.category(char).startswith(cat) for cat in {'M', 'P', 'Z', 'C'}) 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() or char == ' ').casefold().upper()
return side_identifier return side_identifier
@ -85,15 +90,19 @@ class MediaAdminForm(ModelForm):
side_identifier_field = self.fields.get('side_identifier') side_identifier_field = self.fields.get('side_identifier')
if side_identifier_field and self.instance and self.instance.pk: if side_identifier_field and self.instance and self.instance.pk:
instance = self.instance 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"): if hasattr(instance, "subtitle"):
subtitle = instance.subtitle subtitle = instance.subtitle
side_identifier_field.widget.attrs.update( side_identifier_field.widget.attrs.update(
{'data-generated-side-identifier': generate_side_identifier(title, authors, subtitle)}) {'data-generated-side-identifier':
side_identifier_field.widget.template_name = "media/generate_side_identifier.html" generate_side_identifier(title, authors, subtitle)})
side_identifier_field.widget.template_name =\
"media/generate_side_identifier.html"
def download_data_isbndb(self, isbn): 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 = urllib.request.Request(api_url)
req.add_header("Authorization", os.getenv("ISBNDB_KEY", "")) req.add_header("Authorization", os.getenv("ISBNDB_KEY", ""))
try: try:
@ -109,11 +118,13 @@ class MediaAdminForm(ModelForm):
data.setdefault("image", "") data.setdefault("image", "")
self.cleaned_data["title"] = data["title"] self.cleaned_data["title"] = data["title"]
self.cleaned_data["publish_date"] = data["date_published"][:10] 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["publish_date"] += "-01"
self.cleaned_data["number_of_pages"] = data["pages"] self.cleaned_data["number_of_pages"] = data["pages"]
self.cleaned_data["authors"] = \ 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"] self.cleaned_data["external_url"] = data["image"]
return True return True
@ -333,4 +344,6 @@ class MediaAdminForm(ModelForm):
class Meta: class Meta:
model = BD model = BD
fields = '__all__' fields = ('isbn', 'title', 'subtitle', 'external_url',
'side_identifier', 'authors', 'number_of_pages',
'publish_date', 'present', )

View File

@ -1,6 +1,3 @@
from argparse import FileType
from sys import stdin
from django.core.management import BaseCommand from django.core.management import BaseCommand
from media.models import BD, CD, Manga, Revue, Roman, Vinyle, Jeu 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: with open(directory + "/docs/index.md", "w") as f:
f.write("# Media de la Mediatek\n\n\n") 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")]: (CD, "cd.md"), (Vinyle, "vinyles.md")]:
with open(directory + "/docs/" + file_name, "w") as f: self.process_model_class(model_class, file_name, f, directory)
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")
# Traitement différent pour les revues # Traitement différent pour les revues
with open(directory + "/docs/revues.md", "w") as f: with open(directory + "/docs/revues.md", "w") as f:
f.write("# Revues\n\n\n") 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() titles.sort()
for title in titles: for title in titles:
f.write(f"## {title}\n\n\n") 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") f.write(f"### Numéro {medium.number}\n\n\n")
if medium.double: if medium.double:
f.write("Double revue\n\n") f.write("Double revue\n\n")
@ -77,9 +54,46 @@ class Command(BaseCommand):
for game in Jeu.objects.order_by("name").all(): for game in Jeu.objects.order_by("name").all():
f.write(f"## {game.name}\n\n\n") f.write(f"## {game.name}\n\n\n")
f.write(f"Durée : {game.duree}\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": if game.proprietaire.username != "Med":
f.write(f"Propriétaire : {game.proprietaire.username}\n\n") f.write(f"Propriétaire : {game.proprietaire.username}\n\n")
if game.comment: if game.comment:
f.write(f"Commentaire : {game.comment}\n\n") f.write(f"Commentaire : {game.comment}\n\n")
f.write("\n\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")

View File

@ -1,7 +1,6 @@
from random import random from random import random
from time import sleep from time import sleep
from django.core.exceptions import ValidationError
from django.core.management import BaseCommand from django.core.management import BaseCommand
from media.forms import MediaAdminForm from media.forms import MediaAdminForm
from media.models import BD, FutureMedia, Manga, Roman from media.models import BD, FutureMedia, Manga, Roman
@ -25,7 +24,9 @@ class Command(BaseCommand):
continue continue
if cl.objects.filter(isbn=isbn).exists(): 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() future_medium.delete()
continue continue
@ -36,7 +37,8 @@ class Command(BaseCommand):
try: try:
form.full_clean() 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.instance.subtitle = ""
form.save() form.save()
future_medium.delete() future_medium.delete()
@ -46,4 +48,5 @@ class Command(BaseCommand):
except Exception as e: except Exception as e:
self.stderr.write(self.style.WARNING( self.stderr.write(self.style.WARNING(
"An error occured while importing ISBN {isbn}: {error}" "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) + ")")))

View File

@ -2,7 +2,6 @@ from argparse import FileType
from sys import stdin from sys import stdin
from django.core.management import BaseCommand from django.core.management import BaseCommand
from media.forms import generate_side_identifier from media.forms import generate_side_identifier
from media.models import Roman, Auteur from media.models import Roman, Auteur

View File

@ -1,6 +1,5 @@
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.db import transaction from django.db import transaction
from media.forms import generate_side_identifier from media.forms import generate_side_identifier
from media.models import BD, Manga, Roman from media.models import BD, Manga, Roman
@ -11,11 +10,14 @@ class Command(BaseCommand):
type=str, type=str,
default='bd', default='bd',
choices=['bd', 'manga', 'roman'], 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", 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", 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 @transaction.atomic
def handle(self, *args, **options): def handle(self, *args, **options):
@ -37,23 +39,30 @@ class Command(BaseCommand):
if not obj.authors.all(): if not obj.authors.all():
self.stdout.write(str(obj)) self.stdout.write(str(obj))
subtitle = obj.subtitle if hasattr(obj, "subtitle") else None 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: if current_side_identifier != generated_side_identifier:
answer = 'y' answer = 'y'
if interactive_mode: if interactive_mode:
answer = '' answer = ''
while answer != 'y' and answer != 'n': while answer != 'y' and answer != 'n':
answer = input(f"For medium {obj}, current side: {current_side_identifier}, generated side: " answer = input(f"For medium {obj}, current side: "
f"{generated_side_identifier}, would you like to replace ? [y/n]").lower()[0] f"{current_side_identifier}, "
f"generated side: "
f"{generated_side_identifier}, "
f"would you like to replace ? [y/n]")\
.lower()[0]
if answer == 'y': if answer == 'y':
self.stdout.write(self.style.WARNING(f"Replace side of {obj} from {current_side_identifier} " self.stdout.write(self.style.WARNING(
f"to {generated_side_identifier}...")) f"Replace side of {obj} from {current_side_identifier}"
f" to {generated_side_identifier}..."))
obj.side_identifier = generated_side_identifier obj.side_identifier = generated_side_identifier
if not options["no_commit"]: if not options["no_commit"]:
obj.save() obj.save()
replaced += 1 replaced += 1
if replaced: 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: else:
self.stdout.write(self.style.WARNING("Nothing changed.")) self.stdout.write(self.style.WARNING("Nothing changed."))

View File

@ -1,6 +1,7 @@
from rest_framework import serializers 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): class AuteurSerializer(serializers.ModelSerializer):

View File

@ -12,11 +12,25 @@ urlpatterns = [
url(r'^retour_emprunt/(?P<empruntid>[0-9]+)$', views.retour_emprunt, url(r'^retour_emprunt/(?P<empruntid>[0-9]+)$', views.retour_emprunt,
name='retour-emprunt'), name='retour-emprunt'),
path('find/', views.FindMediumView.as_view(), name="find"), path('find/', views.FindMediumView.as_view(), name="find"),
path('mark-as-present/bd/<int:pk>/', views.MarkBDAsPresent.as_view(), name="mark_bd_as_present"), path('mark-as-present/bd/<int:pk>/',
path('mark-as-present/manga/<int:pk>/', views.MarkMangaAsPresent.as_view(), name="mark_manga_as_present"), views.MarkBDAsPresent.as_view(),
path('mark-as-present/cd/<int:pk>/', views.MarkCDAsPresent.as_view(), name="mark_cd_as_present"), name="mark_bd_as_present"),
path('mark-as-present/vinyle/<int:pk>/', views.MarkVinyleAsPresent.as_view(), name="mark_vinyle_as_present"), path('mark-as-present/manga/<int:pk>/',
path('mark-as-present/roman/<int:pk>/', views.MarkRomanAsPresent.as_view(), name="mark_roman_as_present"), views.MarkMangaAsPresent.as_view(),
path('mark-as-present/revue/<int:pk>/', views.MarkRevueAsPresent.as_view(), name="mark_revue_as_present"), name="mark_manga_as_present"),
path('mark-as-present/future/<int:pk>/', views.MarkFutureAsPresent.as_view(), name="mark_future_as_present"), path('mark-as-present/cd/<int:pk>/',
views.MarkCDAsPresent.as_view(),
name="mark_cd_as_present"),
path('mark-as-present/vinyle/<int:pk>/',
views.MarkVinyleAsPresent.as_view(),
name="mark_vinyle_as_present"),
path('mark-as-present/roman/<int:pk>/',
views.MarkRomanAsPresent.as_view(),
name="mark_roman_as_present"),
path('mark-as-present/revue/<int:pk>/',
views.MarkRevueAsPresent.as_view(),
name="mark_revue_as_present"),
path('mark-as-present/future/<int:pk>/',
views.MarkFutureAsPresent.as_view(),
name="mark_future_as_present"),
] ]

View File

@ -1,7 +1,6 @@
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from http.client import NO_CONTENT
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required 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 rest_framework.filters import SearchFilter
from reversion import revisions as reversion from reversion import revisions as reversion
from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga, Revue, Roman, Vinyle from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga, Revue,\
from .serializers import AuteurSerializer, BDSerializer, CDSerializer, EmpruntSerializer, FutureMediaSerializer, \ Roman, Vinyle
JeuSerializer, MangaSerializer, RevueSerializer, RomanSerializer, VinyleSerializer from .serializers import AuteurSerializer, BDSerializer, CDSerializer,\
EmpruntSerializer, FutureMediaSerializer, JeuSerializer, MangaSerializer,\
RevueSerializer, RomanSerializer, VinyleSerializer
@login_required @login_required
@ -107,7 +108,8 @@ class BDViewSet(viewsets.ModelViewSet):
serializer_class = BDSerializer serializer_class = BDSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["isbn", "side_identifier"] 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): class MangaViewSet(viewsets.ModelViewSet):
@ -118,7 +120,8 @@ class MangaViewSet(viewsets.ModelViewSet):
serializer_class = MangaSerializer serializer_class = MangaSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["isbn", "side_identifier"] 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): class CDViewSet(viewsets.ModelViewSet):
@ -151,7 +154,8 @@ class RomanViewSet(viewsets.ModelViewSet):
serializer_class = RomanSerializer serializer_class = RomanSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["isbn", "side_identifier", "number_of_pages"] 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): class RevueViewSet(viewsets.ModelViewSet):