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.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,\

View File

@ -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,8 +70,11 @@ 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'})
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', )

View File

@ -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")

View File

@ -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) + ")")))

View File

@ -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

View File

@ -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."))

View File

@ -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):

View File

@ -12,11 +12,25 @@ urlpatterns = [
url(r'^retour_emprunt/(?P<empruntid>[0-9]+)$', views.retour_emprunt,
name='retour-emprunt'),
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/manga/<int:pk>/', views.MarkMangaAsPresent.as_view(), name="mark_manga_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"),
path('mark-as-present/bd/<int:pk>/',
views.MarkBDAsPresent.as_view(),
name="mark_bd_as_present"),
path('mark-as-present/manga/<int:pk>/',
views.MarkMangaAsPresent.as_view(),
name="mark_manga_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 -*-
# 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):