1
0
mirror of https://gitlab.crans.org/mediatek/med.git synced 2025-02-25 07:06:31 +00:00

Compare commits

..

No commits in common. "0b3701f01fed4bb87a23613d7c35b1cd6e5b47ba" and "94c6c736152a1966f6e35975559a0c9a2c1c1a3c" have entirely different histories.

31 changed files with 307 additions and 330 deletions

View File

@ -2,6 +2,30 @@ stages:
- test - test
- quality-assurance - quality-assurance
py37-django22:
stage: test
image: debian:buster-backports
before_script:
- >
apt-get update &&
apt-get install --no-install-recommends -t buster-backports -y
python3-django python3-django-casclient python3-django-reversion python3-djangorestframework
python3-docutils python3-pil python3-tz python3-six python3-sqlparse python3-stdnum python3-yaml python3-coreapi tox
script: tox -e py37
py38-django22:
stage: test
image: ubuntu:20.04
before_script:
# Fix tzdata prompt
- ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone
- >
apt-get update &&
apt-get install --no-install-recommends -y
python3-django python3-django-casclient python3-django-reversion python3-djangorestframework
python3-docutils python3-pil python3-tz python3-six python3-sqlparse python3-stdnum python3-yaml python3-coreapi tox
script: tox -e py38
py39-django22: py39-django22:
stage: test stage: test
image: debian:bullseye image: debian:bullseye
@ -9,13 +33,13 @@ py39-django22:
- > - >
apt-get update && apt-get update &&
apt-get install --no-install-recommends -y apt-get install --no-install-recommends -y
python3-django python3-django-reversion python3-djangorestframework python3-django python3-django-casclient python3-django-reversion python3-djangorestframework
python3-docutils python3-requests tox python3-docutils python3-pil python3-tz python3-six python3-sqlparse python3-stdnum python3-yaml python3-coreapi tox
script: tox -e py39 script: tox -e py39
linters: linters:
stage: quality-assurance stage: quality-assurance
image: debian:bullseye image: debian:buster-backports
before_script: before_script:
- apt-get update && apt-get install -y tox - apt-get update && apt-get install -y tox
script: tox -e linters script: tox -e linters

View File

@ -90,6 +90,10 @@ bureau
media | Can add borrowed item media | Can add borrowed item
media | Can change borrowed item media | Can change borrowed item
media | Can delete borrowed item media | Can delete borrowed item
users | Can view adhesion
users | Can add adhesion
users | Can change adhesion
users | Can delete adhesion
users | Can view user users | Can view user
users | Can add user users | Can add user
users | Can change user users | Can change user

View File

@ -35,7 +35,6 @@ INSTALLED_APPS = [
# External apps # External apps
'reversion', 'reversion',
'rest_framework', 'rest_framework',
'django_extensions',
# Django contrib # Django contrib
'django.contrib.admin', 'django.contrib.admin',

View File

@ -13,21 +13,21 @@ from .admin import admin_site
# API router # API router
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register(r'authors', media.views.AuthorViewSet) router.register(r'authors', media.views.AuteurViewSet)
router.register(r'media/comic', media.views.ComicViewSet) router.register(r'media/bd', media.views.BDViewSet)
router.register(r'media/manga', media.views.MangaViewSet) router.register(r'media/manga', media.views.MangaViewSet)
router.register(r'media/cd', media.views.CDViewSet) router.register(r'media/cd', media.views.CDViewSet)
router.register(r'media/vinyl', media.views.VinylViewSet) router.register(r'media/vinyle', media.views.VinyleViewSet)
router.register(r'media/novel', media.views.NovelViewSet) router.register(r'media/roman', media.views.RomanViewSet)
router.register(r'media/review', media.views.ReviewViewSet) router.register(r'media/revue', media.views.RevueViewSet)
router.register(r'media/future', media.views.FutureMediumViewSet) router.register(r'media/future', media.views.FutureMediaViewSet)
router.register(r'borrowed_items', media.views.EmpruntViewSet) router.register(r'borrowed_items', media.views.EmpruntViewSet)
router.register(r'games', media.views.GameViewSet) router.register(r'games', media.views.JeuViewSet)
router.register(r'users', users.views.UserViewSet) router.register(r'users', users.views.UserViewSet)
router.register(r'groups', users.views.GroupViewSet) router.register(r'groups', users.views.GroupViewSet)
urlpatterns = [ urlpatterns = [
path('', media.views.IndexView.as_view(), name='index'), path('', media.views.index, name='index'),
# Include project routers # Include project routers
path('users/', include('users.urls')), path('users/', include('users.urls')),

View File

@ -9,16 +9,16 @@ from med.admin import admin_site
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from .forms import MediaAdminForm from .forms import MediaAdminForm
from .models import Author, CD, Comic, Emprunt, FutureMedium, Game, Manga,\ from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga,\
Novel, Review, Vinyl Revue, Roman, Vinyle
class AuthorAdmin(VersionAdmin): class AuteurAdmin(VersionAdmin):
list_display = ('name',) list_display = ('name',)
search_fields = ('name',) search_fields = ('name',)
class MediumAdmin(VersionAdmin): class MediaAdmin(VersionAdmin):
list_display = ('__str__', 'authors_list', 'side_identifier', 'isbn', list_display = ('__str__', 'authors_list', 'side_identifier', 'isbn',
'external_link') 'external_link')
search_fields = ('title', 'authors__name', 'side_identifier', 'subtitle', search_fields = ('title', 'authors__name', 'side_identifier', 'subtitle',
@ -61,7 +61,7 @@ class MediumAdmin(VersionAdmin):
extra_context=extra_context) extra_context=extra_context)
class FutureMediumAdmin(VersionAdmin): class FutureMediaAdmin(VersionAdmin):
list_display = ('isbn',) list_display = ('isbn',)
search_fields = ('isbn',) search_fields = ('isbn',)
@ -88,7 +88,7 @@ class CDAdmin(VersionAdmin):
authors_list.short_description = _('authors') authors_list.short_description = _('authors')
class VinylAdmin(VersionAdmin): class VinyleAdmin(VersionAdmin):
list_display = ('title', 'authors_list', 'side_identifier', 'rpm',) list_display = ('title', 'authors_list', 'side_identifier', 'rpm',)
search_fields = ('title', 'authors__name', 'side_identifier', 'rpm',) search_fields = ('title', 'authors__name', 'side_identifier', 'rpm',)
autocomplete_fields = ('authors',) autocomplete_fields = ('authors',)
@ -99,7 +99,7 @@ class VinylAdmin(VersionAdmin):
authors_list.short_description = _('authors') authors_list.short_description = _('authors')
class ReviewAdmin(VersionAdmin): class RevueAdmin(VersionAdmin):
list_display = ('__str__', 'number', 'year', 'month', 'day', 'double',) list_display = ('__str__', 'number', 'year', 'month', 'day', 'double',)
search_fields = ('title', 'number', 'year',) search_fields = ('title', 'number', 'year',)
@ -140,20 +140,20 @@ class EmpruntAdmin(VersionAdmin):
return super().add_view(request, form_url, extra_context) return super().add_view(request, form_url, extra_context)
class GameAdmin(VersionAdmin): class JeuAdmin(VersionAdmin):
list_display = ('name', 'owner', 'duration', 'players_min', list_display = ('name', 'proprietaire', 'duree', 'nombre_joueurs_min',
'players_max', 'comment') 'nombre_joueurs_max', 'comment')
search_fields = ('name', 'owner__username', 'duration', 'comment') search_fields = ('name', 'proprietaire__username', 'duree', 'comment')
autocomplete_fields = ('owner',) autocomplete_fields = ('proprietaire',)
admin_site.register(Author, AuthorAdmin) admin_site.register(Auteur, AuteurAdmin)
admin_site.register(Comic, MediumAdmin) admin_site.register(BD, MediaAdmin)
admin_site.register(Manga, MediumAdmin) admin_site.register(Manga, MediaAdmin)
admin_site.register(Novel, MediumAdmin) admin_site.register(Roman, MediaAdmin)
admin_site.register(CD, CDAdmin) admin_site.register(CD, CDAdmin)
admin_site.register(Vinyl, VinylAdmin) admin_site.register(Vinyle, VinyleAdmin)
admin_site.register(Review, ReviewAdmin) admin_site.register(Revue, RevueAdmin)
admin_site.register(FutureMedium, FutureMediumAdmin) admin_site.register(FutureMedia, FutureMediaAdmin)
admin_site.register(Emprunt, EmpruntAdmin) admin_site.register(Emprunt, EmpruntAdmin)
admin_site.register(Game, GameAdmin) admin_site.register(Jeu, JeuAdmin)

View File

@ -13,7 +13,7 @@ from django.db.models import QuerySet
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from .models import Author, Comic from .models import Auteur, BD
from .scraper import BedetequeScraper from .scraper import BedetequeScraper
@ -123,7 +123,7 @@ class MediaAdminForm(ModelForm):
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(Author.objects.get_or_create(name=author_name)[0] list(Auteur.objects.get_or_create(name=author_name)[0]
for author_name in data["authors"]) for author_name in data["authors"])
self.cleaned_data["external_url"] = data["image"] self.cleaned_data["external_url"] = data["image"]
return True return True
@ -138,7 +138,7 @@ class MediaAdminForm(ModelForm):
if not r: if not r:
return False return False
# If results, then take the most accurate # If results, then take the most accurate
data = scraper.scrap_comic_info(r[0]) data = scraper.scrap_bd_info(r[0])
self.cleaned_data.update(data) self.cleaned_data.update(data)
return True return True
@ -195,7 +195,7 @@ class MediaAdminForm(ModelForm):
if 'authors' in info: if 'authors' in info:
for author in info['authors']: for author in info['authors']:
author_obj = Author.objects.get_or_create( author_obj = Auteur.objects.get_or_create(
name=author)[0] name=author)[0]
self.cleaned_data['authors'].append(author_obj) self.cleaned_data['authors'].append(author_obj)
@ -269,7 +269,7 @@ class MediaAdminForm(ModelForm):
if 'authors' in data: if 'authors' in data:
for author in data['authors']: for author in data['authors']:
author_obj = Author.objects.get_or_create( author_obj = Auteur.objects.get_or_create(
name=author['name'])[0] name=author['name'])[0]
self.cleaned_data['authors'].append(author_obj) self.cleaned_data['authors'].append(author_obj)
@ -343,7 +343,7 @@ class MediaAdminForm(ModelForm):
self.add_error(name, e) self.add_error(name, e)
class Meta: class Meta:
model = Comic model = BD
fields = ('isbn', 'title', 'subtitle', 'external_url', fields = ('isbn', 'title', 'subtitle', 'external_url',
'side_identifier', 'authors', 'number_of_pages', 'side_identifier', 'authors', 'number_of_pages',
'publish_date', 'present', ) 'publish_date', 'present', )

View File

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-23 18:27+0200\n" "POT-Creation-Date: 2020-10-02 13:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -13,20 +13,20 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:33 admin.py:88 admin.py:99 models.py:29 models.py:65 models.py:130 #: admin.py:34 admin.py:89 admin.py:100 models.py:29 models.py:65 models.py:130
#: models.py:192 models.py:243 models.py:274 #: models.py:192 models.py:243 models.py:274
msgid "authors" msgid "authors"
msgstr "auteurs" msgstr "auteurs"
#: admin.py:43 #: admin.py:44
msgid "external url" msgid "external url"
msgstr "URL externe" msgstr "URL externe"
#: admin.py:126 #: admin.py:127
msgid "Turn back" msgid "Turn back"
msgstr "Rendre" msgstr "Rendre"
#: admin.py:129 models.py:407 #: admin.py:130 models.py:407
msgid "given back to" msgid "given back to"
msgstr "rendu à" msgstr "rendu à"
@ -34,7 +34,7 @@ msgstr "rendu à"
msgid "ISBN-10 or ISBN-13" msgid "ISBN-10 or ISBN-13"
msgstr "ISBN-10 ou ISBN-13" msgstr "ISBN-10 ou ISBN-13"
#: forms.py:301 #: forms.py:244
msgid "This ISBN is not found." msgid "This ISBN is not found."
msgstr "L'ISBN n'a pas été trouvé." msgstr "L'ISBN n'a pas été trouvé."
@ -94,11 +94,11 @@ msgid "Tell that the medium is present in the Mediatek."
msgstr "Indique que le medium est présent à la Mediatek." msgstr "Indique que le medium est présent à la Mediatek."
#: models.py:93 models.py:355 #: models.py:93 models.py:355
msgid "comic" msgid "BD"
msgstr "BD" msgstr "BD"
#: models.py:94 #: models.py:94
msgid "comics" msgid "BDs"
msgstr "BDs" msgstr "BDs"
#: models.py:155 #: models.py:155
@ -110,11 +110,11 @@ msgid "mangas"
msgstr "mangas" msgstr "mangas"
#: models.py:217 #: models.py:217
msgid "novel" msgid "roman"
msgstr "roman" msgstr "roman"
#: models.py:218 #: models.py:218
msgid "novels" msgid "romans"
msgstr "romans" msgstr "romans"
#: models.py:234 #: models.py:234
@ -130,12 +130,12 @@ msgid "45 RPM"
msgstr "45 TPM" msgstr "45 TPM"
#: models.py:256 #: models.py:256
msgid "vinyl" msgid "vinyle"
msgstr "vinyle" msgstr "vinyle"
#: models.py:257 #: models.py:257
msgid "vinyls" msgid "vinyles"
msgstr "vinyles" msgstr "vinyle"
#: models.py:287 #: models.py:287
msgid "CD" msgid "CD"
@ -166,11 +166,11 @@ msgid "double"
msgstr "double" msgstr "double"
#: models.py:338 #: models.py:338
msgid "review" msgid "revue"
msgstr "revue" msgstr "revue"
#: models.py:339 #: models.py:339
msgid "reviews" msgid "revues"
msgstr "revues" msgstr "revues"
#: models.py:353 #: models.py:353
@ -277,6 +277,12 @@ msgstr "ISBN invalide : mauvaise longueur"
msgid "Invalid ISBN: Only upper case allowed" msgid "Invalid ISBN: Only upper case allowed"
msgstr "ISBN invalide : seulement les majuscules sont autorisées" msgstr "ISBN invalide : seulement les majuscules sont autorisées"
#: views.py:51 #: views.py:50
msgid "Welcome to the Mediatek database" msgid "Welcome to the Mediatek database"
msgstr "Bienvenue sur la base de données de la Mediatek" msgstr "Bienvenue sur la base de données de la Mediatek"
#~ msgid "medium"
#~ msgstr "medium"
#~ msgid "media"
#~ msgstr "media"

View File

@ -1,5 +1,5 @@
from django.core.management import BaseCommand from django.core.management import BaseCommand
from media.models import Comic, CD, Manga, Review, Novel, Vinyl, Game from media.models import BD, CD, Manga, Revue, Roman, Vinyle, Jeu
class Command(BaseCommand): class Command(BaseCommand):
@ -18,9 +18,9 @@ class Command(BaseCommand):
f.write("Ce site répertorie l'intégralité des media présents " f.write("Ce site répertorie l'intégralité des media présents "
"à la Mediatek de l'ENS Paris-Saclay.\n") "à la Mediatek de l'ENS Paris-Saclay.\n")
for model_class, file_name in [(Comic, "bd.md"), (Manga, "mangas.md"), for model_class, file_name in [(BD, "bd.md"), (Manga, "mangas.md"),
(Novel, "romans.md"), (Roman, "romans.md"),
(CD, "cd.md"), (Vinyl, "vinyles.md")]: (CD, "cd.md"), (Vinyle, "vinyles.md")]:
self.process_model_class(model_class, file_name, f, directory) self.process_model_class(model_class, file_name, f, directory)
# Traitement différent pour les revues # Traitement différent pour les revues
@ -28,13 +28,13 @@ class Command(BaseCommand):
f.write("# Revues\n\n\n") f.write("# Revues\n\n\n")
titles = list(set(obj["title"] for obj in titles = list(set(obj["title"] for obj in
Review.objects.values("title").distinct().all())) 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 Review.objects.filter(title=title)\ for medium in Revue.objects.filter(title=title)\
.order_by("number").all(): .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:
@ -51,13 +51,13 @@ class Command(BaseCommand):
with open(directory + "/docs/jeux.md", "w") as f: with open(directory + "/docs/jeux.md", "w") as f:
f.write("# Jeux\n\n\n") f.write("# Jeux\n\n\n")
for game in Game.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.duration}\n\n") f.write(f"Durée : {game.duree}\n\n")
f.write(f"Nombre de joueurs : {game.players_min} " f.write(f"Nombre de joueurs : {game.nombre_joueurs_min} "
f"- {game.players_max}\n\n") f"- {game.nombre_joueurs_max}\n\n")
if game.owner.username != "Med": if game.proprietaire.username != "Med":
f.write(f"Propriétaire : {game.owner.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")

View File

@ -2,7 +2,7 @@ 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.models import Author, CD from media.models import Auteur, CD
class Command(BaseCommand): class Command(BaseCommand):
@ -29,7 +29,7 @@ class Command(BaseCommand):
title = cd[0] title = cd[0]
side = cd[1] side = cd[1]
authors_str = cd[2].split('|') authors_str = cd[2].split('|')
authors = [Author.objects.get_or_create(name=author)[0] authors = [Auteur.objects.get_or_create(name=author)[0]
for author in authors_str] for author in authors_str]
cd, created = CD.objects.get_or_create( cd, created = CD.objects.get_or_create(
title=title, title=title,

View File

@ -3,20 +3,20 @@ from time import sleep
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 Comic, FutureMedium, Manga, Novel from media.models import BD, FutureMedia, Manga, Roman
class Command(BaseCommand): class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
for future_medium in FutureMedium.objects.all(): for future_medium in FutureMedia.objects.all():
isbn = future_medium.isbn isbn = future_medium.isbn
type_str = future_medium.type type_str = future_medium.type
if type_str == 'bd': if type_str == 'bd':
cl = Comic cl = BD
elif type_str == 'manga': elif type_str == 'manga':
cl = Manga cl = Manga
elif type_str == 'roman': elif type_str == 'roman':
cl = Novel cl = Roman
else: else:
self.stderr.write(self.style.WARNING( self.stderr.write(self.style.WARNING(
"Unknown medium type: {type}. Ignoring..." "Unknown medium type: {type}. Ignoring..."

View File

@ -3,7 +3,7 @@ from sys import stdin
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.management import BaseCommand from django.core.management import BaseCommand
from media.models import Comic, FutureMedium, Manga, Novel from media.models import BD, FutureMedia, Manga, Roman
from media.validators import isbn_validator from media.validators import isbn_validator
@ -27,7 +27,7 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
type_str = options["media_type"] type_str = options["media_type"]
media_classes = [Comic, Manga, Novel, FutureMedium] media_classes = [BD, Manga, Roman, FutureMedia]
file = options["input"] file = options["input"]
isbns = [] isbns = []
@ -70,7 +70,7 @@ class Command(BaseCommand):
if isbn_exists: if isbn_exists:
continue continue
FutureMedium.objects.create(isbn=isbn, type=type_str) FutureMedia.objects.create(isbn=isbn, type=type_str)
self.stdout.write(self.style.SUCCESS("ISBN {isbn} imported" self.stdout.write(self.style.SUCCESS("ISBN {isbn} imported"
.format(isbn=isbn))) .format(isbn=isbn)))
imported += 1 imported += 1

View File

@ -2,7 +2,7 @@ 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.models import Author, Comic from media.models import Auteur, BD
class Command(BaseCommand): class Command(BaseCommand):
@ -28,9 +28,9 @@ class Command(BaseCommand):
title = revue[0] title = revue[0]
number = revue[1] number = revue[1]
authors = [Author.objects.get_or_create(name=n)[0] authors = [Auteur.objects.get_or_create(name=n)[0]
for n in revue[2].split('|')] for n in revue[2].split('|')]
bd = Comic.objects.create( bd = BD.objects.create(
title=title, title=title,
subtitle=number, subtitle=number,
side_identifier="{:.3} {:.3} {:0>2}" side_identifier="{:.3} {:.3} {:0>2}"

View File

@ -3,7 +3,7 @@ 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 Novel, Author from media.models import Roman, Auteur
class Command(BaseCommand): class Command(BaseCommand):
@ -28,10 +28,10 @@ class Command(BaseCommand):
continue continue
title = book[1] title = book[1]
authors = [Author.objects.get_or_create(name=n)[0] authors = [Auteur.objects.get_or_create(name=n)[0]
for n in book[0].split(';')] for n in book[0].split(';')]
side_identifier = generate_side_identifier(title, authors) side_identifier = generate_side_identifier(title, authors)
roman = Novel.objects.create( roman = Roman.objects.create(
title=title, title=title,
side_identifier=side_identifier, side_identifier=side_identifier,
) )

View File

@ -2,7 +2,7 @@ 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.models import Review from media.models import Revue
class Command(BaseCommand): class Command(BaseCommand):
@ -37,7 +37,7 @@ class Command(BaseCommand):
year = revue[4] year = revue[4]
if not year: if not year:
year = None year = None
revue, created = Review.objects.get_or_create( revue, created = Revue.objects.get_or_create(
title=title, title=title,
number=number.replace('*', ''), number=number.replace('*', ''),
year=year, year=year,

View File

@ -2,7 +2,7 @@ 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.models import Author, Vinyl from media.models import Auteur, Vinyle
class Command(BaseCommand): class Command(BaseCommand):
@ -36,9 +36,9 @@ class Command(BaseCommand):
title = vinyle[1 if rpm == 33 else 2] title = vinyle[1 if rpm == 33 else 2]
authors_str = vinyle[2 if rpm == 33 else 1]\ authors_str = vinyle[2 if rpm == 33 else 1]\
.split('|' if rpm == 33 else ';') .split('|' if rpm == 33 else ';')
authors = [Author.objects.get_or_create(name=author)[0] authors = [Auteur.objects.get_or_create(name=author)[0]
for author in authors_str] for author in authors_str]
vinyle, created = Vinyl.objects.get_or_create( vinyle, created = Vinyle.objects.get_or_create(
title=title, title=title,
side_identifier=side, side_identifier=side,
rpm=rpm, rpm=rpm,

View File

@ -1,7 +1,7 @@
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 Comic, Manga, Novel from media.models import BD, Manga, Roman
class Command(BaseCommand): class Command(BaseCommand):
@ -24,11 +24,11 @@ class Command(BaseCommand):
t = options["type"] t = options["type"]
medium_class = None medium_class = None
if t == "bd": if t == "bd":
medium_class = Comic medium_class = BD
elif t == "manga": elif t == "manga":
medium_class = Manga medium_class = Manga
elif t == "roman": elif t == "roman":
medium_class = Novel medium_class = Roman
interactive_mode = not options["noninteractivemode"] interactive_mode = not options["noninteractivemode"]

View File

@ -2,7 +2,7 @@ from time import sleep
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 Comic, Manga from media.models import BD, Manga
class Command(BaseCommand): class Command(BaseCommand):
@ -14,7 +14,7 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
converted = 0 converted = 0
for media in Comic.objects.all(): for media in BD.objects.all():
if media.pk < 3400: if media.pk < 3400:
continue continue
# We sleep 5 seconds to avoid a ban from Bedetheque # We sleep 5 seconds to avoid a ban from Bedetheque

View File

@ -1,61 +0,0 @@
# Generated by Django 2.2.17 on 2021-10-23 16:30
from django.conf import settings
from django.db import migrations, models
import media.fields
import media.validators
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('media', '0039_mark_media_present'),
]
operations = [
migrations.RenameModel(
old_name='Auteur',
new_name='Author',
),
migrations.RenameModel(
old_name='Roman',
new_name='Comic',
),
migrations.RenameModel(
old_name='Jeu',
new_name='Game',
),
migrations.RenameModel(
old_name='BD',
new_name='Novel',
),
migrations.RenameModel(
old_name='Revue',
new_name='Review',
),
migrations.RenameModel(
old_name='Vinyle',
new_name='Vinyl',
),
migrations.RenameModel(
old_name='FutureMedia',
new_name='FutureMedium',
),
migrations.AlterModelOptions(
name='comic',
options={'ordering': ['title', 'subtitle'], 'verbose_name': 'comic', 'verbose_name_plural': 'comics'},
),
migrations.AlterModelOptions(
name='novel',
options={'ordering': ['title', 'subtitle'], 'verbose_name': 'novel', 'verbose_name_plural': 'novels'},
),
migrations.AlterModelOptions(
name='review',
options={'ordering': ['title', 'number'], 'verbose_name': 'review', 'verbose_name_plural': 'reviews'},
),
migrations.AlterModelOptions(
name='vinyl',
options={'ordering': ['title'], 'verbose_name': 'vinyl', 'verbose_name_plural': 'vinyls'},
),
]

View File

@ -1,44 +0,0 @@
# Generated by Django 2.2.17 on 2021-10-23 16:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('media', '0040_auto_20211023_1830'),
]
operations = [
migrations.RenameField(
model_name='game',
old_name='duree',
new_name='duration',
),
migrations.RenameField(
model_name='game',
old_name='proprietaire',
new_name='owner',
),
migrations.RenameField(
model_name='game',
old_name='nombre_joueurs_max',
new_name='players_max',
),
migrations.RenameField(
model_name='game',
old_name='nombre_joueurs_min',
new_name='players_min',
),
migrations.AlterField(
model_name='emprunt',
name='media',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='media.Comic'),
),
migrations.AlterField(
model_name='futuremedium',
name='type',
field=models.CharField(choices=[('bd', 'Comic'), ('manga', 'Manga'), ('roman', 'Roman')], max_length=8, verbose_name='type'),
),
]

View File

@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
from .fields import ISBNField from .fields import ISBNField
class Author(models.Model): class Auteur(models.Model):
name = models.CharField( name = models.CharField(
max_length=255, max_length=255,
unique=True, unique=True,
@ -30,7 +30,7 @@ class Author(models.Model):
ordering = ['name'] ordering = ['name']
class Comic(models.Model): class BD(models.Model):
isbn = ISBNField( isbn = ISBNField(
_('ISBN'), _('ISBN'),
help_text=_('You may be able to scan it from a bar code.'), help_text=_('You may be able to scan it from a bar code.'),
@ -61,7 +61,7 @@ class Comic(models.Model):
) )
authors = models.ManyToManyField( authors = models.ManyToManyField(
'Author', 'Auteur',
verbose_name=_('authors'), verbose_name=_('authors'),
) )
@ -90,8 +90,8 @@ class Comic(models.Model):
return self.title return self.title
class Meta: class Meta:
verbose_name = _("comic") verbose_name = _("BD")
verbose_name_plural = _("comics") verbose_name_plural = _("BDs")
ordering = ['title', 'subtitle'] ordering = ['title', 'subtitle']
@ -126,7 +126,7 @@ class Manga(models.Model):
) )
authors = models.ManyToManyField( authors = models.ManyToManyField(
'Author', 'Auteur',
verbose_name=_('authors'), verbose_name=_('authors'),
) )
@ -157,7 +157,7 @@ class Manga(models.Model):
ordering = ['title'] ordering = ['title']
class Novel(models.Model): class Roman(models.Model):
isbn = ISBNField( isbn = ISBNField(
_('ISBN'), _('ISBN'),
help_text=_('You may be able to scan it from a bar code.'), help_text=_('You may be able to scan it from a bar code.'),
@ -188,7 +188,7 @@ class Novel(models.Model):
) )
authors = models.ManyToManyField( authors = models.ManyToManyField(
'Author', 'Auteur',
verbose_name=_('authors'), verbose_name=_('authors'),
) )
@ -214,12 +214,12 @@ class Novel(models.Model):
return self.title return self.title
class Meta: class Meta:
verbose_name = _("novel") verbose_name = _("roman")
verbose_name_plural = _("novels") verbose_name_plural = _("romans")
ordering = ['title', 'subtitle'] ordering = ['title', 'subtitle']
class Vinyl(models.Model): class Vinyle(models.Model):
title = models.CharField( title = models.CharField(
verbose_name=_('title'), verbose_name=_('title'),
max_length=255, max_length=255,
@ -239,7 +239,7 @@ class Vinyl(models.Model):
) )
authors = models.ManyToManyField( authors = models.ManyToManyField(
'Author', 'Auteur',
verbose_name=_('authors'), verbose_name=_('authors'),
) )
@ -253,8 +253,8 @@ class Vinyl(models.Model):
return self.title return self.title
class Meta: class Meta:
verbose_name = _("vinyl") verbose_name = _("vinyle")
verbose_name_plural = _("vinyls") verbose_name_plural = _("vinyles")
ordering = ['title'] ordering = ['title']
@ -270,7 +270,7 @@ class CD(models.Model):
) )
authors = models.ManyToManyField( authors = models.ManyToManyField(
'Author', 'Auteur',
verbose_name=_('authors'), verbose_name=_('authors'),
) )
@ -289,7 +289,7 @@ class CD(models.Model):
ordering = ['title'] ordering = ['title']
class Review(models.Model): class Revue(models.Model):
title = models.CharField( title = models.CharField(
verbose_name=_('title'), verbose_name=_('title'),
max_length=255, max_length=255,
@ -335,12 +335,12 @@ class Review(models.Model):
return self.title + "" + str(self.number) return self.title + "" + str(self.number)
class Meta: class Meta:
verbose_name = _("review") verbose_name = _("revue")
verbose_name_plural = _("reviews") verbose_name_plural = _("revues")
ordering = ['title', 'number'] ordering = ['title', 'number']
class FutureMedium(models.Model): class FutureMedia(models.Model):
isbn = ISBNField( isbn = ISBNField(
_('ISBN'), _('ISBN'),
help_text=_('You may be able to scan it from a bar code.'), help_text=_('You may be able to scan it from a bar code.'),
@ -352,7 +352,7 @@ class FutureMedium(models.Model):
type = models.CharField( type = models.CharField(
_('type'), _('type'),
choices=[ choices=[
('bd', _('Comic')), ('bd', _('BD')),
('manga', _('Manga')), ('manga', _('Manga')),
('roman', _('Roman')), ('roman', _('Roman')),
], ],
@ -375,7 +375,7 @@ class FutureMedium(models.Model):
class Emprunt(models.Model): class Emprunt(models.Model):
media = models.ForeignKey( media = models.ForeignKey(
'Comic', 'BD',
on_delete=models.PROTECT, on_delete=models.PROTECT,
) )
user = models.ForeignKey( user = models.ForeignKey(
@ -417,8 +417,8 @@ class Emprunt(models.Model):
ordering = ['-date_emprunt'] ordering = ['-date_emprunt']
class Game(models.Model): class Jeu(models.Model):
DURATIONS = ( DUREE = (
('-1h', '-1h'), ('-1h', '-1h'),
('1-2h', '1-2h'), ('1-2h', '1-2h'),
('2-3h', '2-3h'), ('2-3h', '2-3h'),
@ -430,21 +430,21 @@ class Game(models.Model):
max_length=255, max_length=255,
verbose_name=_("name"), verbose_name=_("name"),
) )
owner = models.ForeignKey( proprietaire = models.ForeignKey(
'users.User', 'users.User',
on_delete=models.PROTECT, on_delete=models.PROTECT,
verbose_name=_("owner"), verbose_name=_("owner"),
) )
duration = models.CharField( duree = models.CharField(
choices=DURATIONS, choices=DUREE,
max_length=255, max_length=255,
verbose_name=_("duration"), verbose_name=_("duration"),
) )
players_min = models.IntegerField( nombre_joueurs_min = models.IntegerField(
validators=[MinValueValidator(1)], validators=[MinValueValidator(1)],
verbose_name=_("minimum number of players"), verbose_name=_("minimum number of players"),
) )
players_max = models.IntegerField( nombre_joueurs_max = models.IntegerField(
validators=[MinValueValidator(1)], validators=[MinValueValidator(1)],
verbose_name=_('maximum number of players'), verbose_name=_('maximum number of players'),
) )

View File

@ -4,7 +4,7 @@
import re import re
import requests import requests
from media.models import Author from media.models import Auteur
class BedetequeScraper: class BedetequeScraper:
@ -44,7 +44,7 @@ class BedetequeScraper:
regex = r'href=\"(https://www\.bedetheque\.com/BD.*.html)\"' regex = r'href=\"(https://www\.bedetheque\.com/BD.*.html)\"'
return re.findall(regex, content) return re.findall(regex, content)
def scrap_comic_info(self, bd_url: str) -> dict: def scrap_bd_info(self, bd_url: str) -> dict:
""" """
Load BD web page and scrap data Load BD web page and scrap data
:param bd_url: URL where to find BD data :param bd_url: URL where to find BD data
@ -99,12 +99,12 @@ class BedetequeScraper:
if 'author' not in data: if 'author' not in data:
data['authors'] = list() data['authors'] = list()
if author: if author:
author_obj = Author.objects.get_or_create( author_obj = Auteur.objects.get_or_create(
name=author.group(1))[0] name=author.group(1))[0]
data['authors'].append(author_obj) data['authors'].append(author_obj)
illustrator = re.search(regex_illustrator, content) illustrator = re.search(regex_illustrator, content)
if illustrator: if illustrator:
author_obj = Author.objects.get_or_create( author_obj = Auteur.objects.get_or_create(
name=illustrator.group(1))[0] name=illustrator.group(1))[0]
data['authors'].append(author_obj) data['authors'].append(author_obj)

View File

@ -1,18 +1,18 @@
from rest_framework import serializers from rest_framework import serializers
from .models import Author, CD, Comic, FutureMedium, Manga, Emprunt, Game, \ from .models import Auteur, BD, CD, FutureMedia, Manga, Emprunt, Jeu, Revue,\
Novel, Review, Vinyl Roman, Vinyle
class AuthorSerializer(serializers.ModelSerializer): class AuteurSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Author model = Auteur
fields = ['url', 'name'] fields = ['url', 'name']
class ComicSerializer(serializers.ModelSerializer): class BDSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Comic model = BD
fields = '__all__' fields = '__all__'
@ -28,27 +28,27 @@ class CDSerializer(serializers.ModelSerializer):
fields = '__all__' fields = '__all__'
class VinylSerializer(serializers.ModelSerializer): class VinyleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Vinyl model = Vinyle
fields = '__all__' fields = '__all__'
class NovelSerializer(serializers.ModelSerializer): class RomanSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Novel model = Roman
fields = '__all__' fields = '__all__'
class ReviewSerializer(serializers.ModelSerializer): class RevueSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Review model = Revue
fields = '__all__' fields = '__all__'
class FutureMediumSerializer(serializers.ModelSerializer): class FutureMediaSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = FutureMedium model = FutureMedia
fields = '__all__' fields = '__all__'
@ -59,8 +59,8 @@ class EmpruntSerializer(serializers.HyperlinkedModelSerializer):
'permanencier_emprunt', 'permanencier_rendu'] 'permanencier_emprunt', 'permanencier_rendu']
class GameSerializer(serializers.HyperlinkedModelSerializer): class JeuSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = Game model = Jeu
fields = ['url', 'name', 'proprietaire', 'duree', 'nombre_joueurs_min', fields = ['url', 'name', 'proprietaire', 'duree', 'nombre_joueurs_min',
'nombre_joueurs_max', 'comment'] 'nombre_joueurs_max', 'comment']

View File

@ -3,7 +3,7 @@
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from media.models import Author, Comic from media.models import Auteur, BD
from users.models import User from users.models import User
""" """
@ -21,44 +21,44 @@ class TemplateTests(TestCase):
self.client.force_login(self.user) self.client.force_login(self.user)
# Create an author # Create an author
self.dummy_author = Author.objects.create(name="Test author") self.dummy_author = Auteur.objects.create(name="Test author")
# Create media # Create media
self.dummy_bd1 = Comic.objects.create( self.dummy_bd1 = BD.objects.create(
title="Test media", title="Test media",
side_identifier="T M", side_identifier="T M",
) )
self.dummy_bd1.authors.add(self.dummy_author) self.dummy_bd1.authors.add(self.dummy_author)
self.dummy_bd2 = Comic.objects.create( self.dummy_bd2 = BD.objects.create(
title="Test media bis", title="Test media bis",
side_identifier="T M 2", side_identifier="T M 2",
external_url="https://example.com/", external_url="https://example.com/",
) )
self.dummy_bd2.authors.add(self.dummy_author) self.dummy_bd2.authors.add(self.dummy_author)
def test_comic_bd_changelist(self): def test_bd_bd_changelist(self):
response = self.client.get(reverse('admin:media_comic_changelist')) response = self.client.get(reverse('admin:media_bd_changelist'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_comic_bd_add(self): def test_bd_bd_add(self):
response = self.client.get(reverse('admin:media_comic_add')) response = self.client.get(reverse('admin:media_bd_add'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_comic_isbn_download(self): def test_bd_isbn_download(self):
data = { data = {
'_isbn': True, '_isbn': True,
'isbn': "0316358525", 'isbn': "0316358525",
} }
response = self.client.post(reverse( response = self.client.post(reverse(
'admin:media_comic_change', 'admin:media_bd_change',
args=[self.dummy_bd1.id], args=[self.dummy_bd1.id],
), data=data) ), data=data)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
def test_comic_emprunt_changelist(self): def test_bd_emprunt_changelist(self):
response = self.client.get(reverse('admin:media_emprunt_changelist')) response = self.client.get(reverse('admin:media_emprunt_changelist'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_comic_emprunt_add(self): def test_bd_emprunt_add(self):
response = self.client.get(reverse('admin:media_emprunt_add')) response = self.client.get(reverse('admin:media_emprunt_add'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)

View File

@ -13,8 +13,8 @@ urlpatterns = [
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>/', path('mark-as-present/bd/<int:pk>/',
views.MarkComicAsPresent.as_view(), views.MarkBDAsPresent.as_view(),
name="mark_comic_as_present"), name="mark_bd_as_present"),
path('mark-as-present/manga/<int:pk>/', path('mark-as-present/manga/<int:pk>/',
views.MarkMangaAsPresent.as_view(), views.MarkMangaAsPresent.as_view(),
name="mark_manga_as_present"), name="mark_manga_as_present"),
@ -22,7 +22,7 @@ urlpatterns = [
views.MarkCDAsPresent.as_view(), views.MarkCDAsPresent.as_view(),
name="mark_cd_as_present"), name="mark_cd_as_present"),
path('mark-as-present/vinyle/<int:pk>/', path('mark-as-present/vinyle/<int:pk>/',
views.MarkVinylAsPresent.as_view(), views.MarkVinyleAsPresent.as_view(),
name="mark_vinyle_as_present"), name="mark_vinyle_as_present"),
path('mark-as-present/roman/<int:pk>/', path('mark-as-present/roman/<int:pk>/',
views.MarkRomanAsPresent.as_view(), views.MarkRomanAsPresent.as_view(),

View File

@ -8,7 +8,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse from django.http import HttpResponse
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from django.db import transaction from django.db import transaction
from django.shortcuts import redirect from django.shortcuts import redirect, render
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView, DetailView from django.views.generic import TemplateView, DetailView
@ -16,11 +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 Author, CD, Comic, Emprunt, FutureMedium, Game, Manga,\ from .models import Auteur, BD, CD, Emprunt, FutureMedia, Jeu, Manga, Revue,\
Novel, Review, Vinyl Roman, Vinyle
from .serializers import AuthorSerializer, ComicSerializer, CDSerializer,\ from .serializers import AuteurSerializer, BDSerializer, CDSerializer,\
EmpruntSerializer, FutureMediumSerializer, GameSerializer, \ EmpruntSerializer, FutureMediaSerializer, JeuSerializer, MangaSerializer,\
MangaSerializer, NovelSerializer, ReviewSerializer, VinylSerializer RevueSerializer, RomanSerializer, VinyleSerializer
@login_required @login_required
@ -40,17 +40,16 @@ def retour_emprunt(request, empruntid):
return redirect("admin:media_emprunt_changelist") return redirect("admin:media_emprunt_changelist")
class IndexView(TemplateView): def index(request):
""" """
Home page which redirect to admin when logged in Home page which redirect to admin when logged in
""" """
extra_context = {'title': _('Welcome to the Mediatek database')} if request.user.is_authenticated:
template_name = 'admin/index.html' return redirect('admin:index')
else:
def dispatch(self, request, *args, **kwargs): return render(request, 'admin/index.html', {
if request.user.is_authenticated: 'title': _('Welcome to the Mediatek database'),
return redirect('admin:index') })
return super().dispatch(request, *args, **kwargs)
class FindMediumView(LoginRequiredMixin, TemplateView): class FindMediumView(LoginRequiredMixin, TemplateView):
@ -65,8 +64,8 @@ class MarkMediumAsPresent(LoginRequiredMixin, DetailView):
return HttpResponse("", content_type=204) return HttpResponse("", content_type=204)
class MarkComicAsPresent(MarkMediumAsPresent): class MarkBDAsPresent(MarkMediumAsPresent):
model = Comic model = BD
class MarkMangaAsPresent(MarkMediumAsPresent): class MarkMangaAsPresent(MarkMediumAsPresent):
@ -77,36 +76,36 @@ class MarkCDAsPresent(MarkMediumAsPresent):
model = CD model = CD
class MarkVinylAsPresent(MarkMediumAsPresent): class MarkVinyleAsPresent(MarkMediumAsPresent):
model = Vinyl model = Vinyle
class MarkRomanAsPresent(MarkMediumAsPresent): class MarkRomanAsPresent(MarkMediumAsPresent):
model = Novel model = Roman
class MarkRevueAsPresent(MarkMediumAsPresent): class MarkRevueAsPresent(MarkMediumAsPresent):
model = Review model = Revue
class MarkFutureAsPresent(MarkMediumAsPresent): class MarkFutureAsPresent(MarkMediumAsPresent):
model = FutureMedium model = FutureMedia
class AuthorViewSet(viewsets.ModelViewSet): class AuteurViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows authors to be viewed or edited. API endpoint that allows authors to be viewed or edited.
""" """
queryset = Author.objects.all() queryset = Auteur.objects.all()
serializer_class = AuthorSerializer serializer_class = AuteurSerializer
class ComicViewSet(viewsets.ModelViewSet): class BDViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows media to be viewed or edited. API endpoint that allows media to be viewed or edited.
""" """
queryset = Comic.objects.all() queryset = BD.objects.all()
serializer_class = ComicSerializer 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", search_fields = ["=isbn", "title", "subtitle", "side_identifier",
@ -136,46 +135,46 @@ class CDViewSet(viewsets.ModelViewSet):
search_fields = ["title", "side_identifier", "authors__name"] search_fields = ["title", "side_identifier", "authors__name"]
class VinylViewSet(viewsets.ModelViewSet): class VinyleViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows media to be viewed or edited. API endpoint that allows media to be viewed or edited.
""" """
queryset = Vinyl.objects.all() queryset = Vinyle.objects.all()
serializer_class = VinylSerializer serializer_class = VinyleSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["side_identifier", "rpm"] filterset_fields = ["side_identifier", "rpm"]
search_fields = ["title", "side_identifier", "authors__name"] search_fields = ["title", "side_identifier", "authors__name"]
class NovelViewSet(viewsets.ModelViewSet): class RomanViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows media to be viewed or edited. API endpoint that allows media to be viewed or edited.
""" """
queryset = Novel.objects.all() queryset = Roman.objects.all()
serializer_class = NovelSerializer 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", search_fields = ["=isbn", "title", "subtitle", "side_identifier",
"authors__name"] "authors__name"]
class ReviewViewSet(viewsets.ModelViewSet): class RevueViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows media to be viewed or edited. API endpoint that allows media to be viewed or edited.
""" """
queryset = Review.objects.all() queryset = Revue.objects.all()
serializer_class = ReviewSerializer serializer_class = RevueSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["number", "year", "month", "day", "double"] filterset_fields = ["number", "year", "month", "day", "double"]
search_fields = ["title"] search_fields = ["title"]
class FutureMediumViewSet(viewsets.ModelViewSet): class FutureMediaViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows media to be viewed or edited. API endpoint that allows media to be viewed or edited.
""" """
queryset = FutureMedium.objects.all() queryset = FutureMedia.objects.all()
serializer_class = FutureMediumSerializer serializer_class = FutureMediaSerializer
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ["isbn"] filterset_fields = ["isbn"]
search_fields = ["=isbn"] search_fields = ["=isbn"]
@ -189,9 +188,9 @@ class EmpruntViewSet(viewsets.ModelViewSet):
serializer_class = EmpruntSerializer serializer_class = EmpruntSerializer
class GameViewSet(viewsets.ModelViewSet): class JeuViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows games to be viewed or edited. API endpoint that allows games to be viewed or edited.
""" """
queryset = Game.objects.all() queryset = Jeu.objects.all()
serializer_class = GameSerializer serializer_class = JeuSerializer

View File

@ -1,7 +1,13 @@
docutils~=0.16 # for Django-admin docs Django~=2.2.10
Django~=2.2 docutils~=0.14
Pillow>=8.0.1
pytz~=2020.4
six~=1.15
sqlparse~=0.3
django-filter~=2.4 django-filter~=2.4
django-reversion~=3.0 django-reversion~=3.0
djangorestframework~=3.12 python-stdnum~=1.14
django_extensions~=3.0 djangorestframework~=3.12.1
requests~=2.25 # for scrapping pyyaml~=5.3.1
coreapi~=2.3.3
django_extensions~=3.1

View File

@ -13,7 +13,12 @@ from reversion.admin import VersionAdmin
from med.admin import admin_site from med.admin import admin_site
from .forms import UserCreationAdminForm from .forms import UserCreationAdminForm
from .models import User from .models import Adhesion, User
class AdhesionAdmin(VersionAdmin):
list_display = ('starting_in', 'ending_in')
autocomplete_fields = ('members',)
class IsMemberFilter(admin.SimpleListFilter): class IsMemberFilter(admin.SimpleListFilter):
@ -26,7 +31,12 @@ class IsMemberFilter(admin.SimpleListFilter):
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
# FIXME Replace with imported Note Kfet memberships value = self.value()
if value == 'Yes':
# Get current membership year and list all members
last_adh_year = Adhesion.objects.all().order_by('starting_in') \
.reverse().first()
return last_adh_year.members
return queryset return queryset
@ -78,8 +88,9 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
""" """
Get current membership year and check if user is there Get current membership year and check if user is there
""" """
# FIXME Use NK20 last_adh_year = Adhesion.objects.all().order_by('starting_in') \
is_member = True .reverse().first()
is_member = last_adh_year and obj in last_adh_year.members.all()
if is_member: if is_member:
return format_html( return format_html(
'<img src="/static/admin/img/icon-yes.svg" alt="True">' '<img src="/static/admin/img/icon-yes.svg" alt="True">'
@ -97,3 +108,4 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
admin_site.register(User, UserAdmin) admin_site.register(User, UserAdmin)
admin_site.register(Adhesion, AdhesionAdmin)

View File

@ -1,16 +0,0 @@
# Generated by Django 2.2.17 on 2021-10-23 12:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('users', '0041_auto_20200923_2030'),
]
operations = [
migrations.DeleteModel(
name='Adhesion',
),
]

View File

@ -42,5 +42,31 @@ class User(AbstractUser):
@property @property
def is_member(self): def is_member(self):
# FIXME Use NK20 last_year = Adhesion.objects.all().order_by(
return True 'starting_in').reverse().first()
return last_year and self in last_year.members.all()
class Adhesion(models.Model):
starting_in = models.IntegerField(
verbose_name=_('starting in'),
help_text=_('Year in which the membership year starts.'),
unique=True,
)
ending_in = models.IntegerField(
verbose_name=_('ending in'),
help_text=_('Year in which the membership year ends.'),
unique=True,
)
members = models.ManyToManyField(
'User',
verbose_name=_('members'),
blank=True,
)
class Meta:
verbose_name = _('membership year')
verbose_name_plural = _('membership years')
def __str__(self):
return f"{self.starting_in} - {self.ending_in}"

View File

@ -9,4 +9,5 @@ from . import views
app_name = 'users' app_name = 'users'
urlpatterns = [ urlpatterns = [
url(r'^edit_info/$', views.edit_info, name='edit-info'), url(r'^edit_info/$', views.edit_info, name='edit-info'),
url(r'^adherer/(?P<userid>[0-9]+)$', views.adherer, name='adherer'),
] ]

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.db import transaction from django.db import transaction
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
@ -12,7 +12,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import viewsets from rest_framework import viewsets
from reversion import revisions as reversion from reversion import revisions as reversion
from users.forms import BaseInfoForm from users.forms import BaseInfoForm
from users.models import User from users.models import Adhesion, User
from .serializers import GroupSerializer, UserSerializer from .serializers import GroupSerializer, UserSerializer
@ -44,6 +44,27 @@ def edit_info(request):
}, 'users/user.html', request) }, 'users/user.html', request)
@login_required
@permission_required('users.add_adhesion')
def adherer(request, userid):
try:
users = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, "Utilisateur inexistant")
return redirect("admin:users_user_changelist")
adh_year = Adhesion.objects.all().order_by('starting_in').reverse().first()
if not adh_year:
messages.error(request, "Année d'adhésion non définie")
return redirect("admin:users_user_changelist")
with transaction.atomic(), reversion.create_revision():
reversion.set_user(request.user)
adh_year.members.add(users)
adh_year.save()
reversion.set_comment("Adhesion de %s" % users)
messages.success(request, "Adhesion effectuee")
return redirect("admin:users_user_changelist")
class UserViewSet(viewsets.ModelViewSet): class UserViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.