Commit 145806b5 authored by ynerant's avatar ynerant
Browse files

Merge branch 'note' into 'main'

Note Kfet integration

See merge request !7
parents faf697d3 49898143
Pipeline #9547 passed with stages
in 2 minutes and 45 seconds
......@@ -7,7 +7,7 @@ from django.contrib.auth.admin import Group, GroupAdmin
from django.contrib.sites.admin import Site, SiteAdmin
from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache
from media.models import Emprunt
from media.models import Borrow
class DatabaseAdmin(AdminSite):
......@@ -22,8 +22,8 @@ class DatabaseAdmin(AdminSite):
# User is always authenticated
# Get currently borrowed items
user_borrowed = Emprunt.objects.filter(user=request.user,
date_rendu=None)
user_borrowed = Borrow.objects.filter(user=request.user,
given_back=None)
response.context_data["borrowed_items"] = user_borrowed
return response
......
......@@ -167,9 +167,26 @@ PAGINATION_NUMBER = 25
AUTH_USER_MODEL = 'users.User'
MAX_EMPRUNT = 5 # Max emprunts
NOTE_KFET_URL = 'https://note.crans.org'
NOTE_KFET_CLIENT_ID = 'CHANGE_ME'
NOTE_KFET_CLIENT_SECRET = 'CHANGE_ME'
NOTE_KFET_SCOPES = '1_1 2_1 48_1'
try:
from .settings_local import *
except ImportError:
pass
AUTHLIB_OAUTH_CLIENTS = {
'notekfet': {
'client_id': f'{NOTE_KFET_CLIENT_ID}',
'client_secret': f'{NOTE_KFET_CLIENT_SECRET}',
'access_token_url': f'{NOTE_KFET_URL}/o/token/',
'refresh_token_url': f'{NOTE_KFET_URL}/o/token/',
'authorize_url': f'{NOTE_KFET_URL}/o/authorize/',
'userinfo_endpoint': f'{NOTE_KFET_URL}/api/me/',
'client_kwargs': {
'scope': NOTE_KFET_SCOPES,
}
}
}
......@@ -40,3 +40,8 @@ DATABASES = {
'PORT': '',
}
}
NOTE_KFET_URL = 'https://note.crans.org'
NOTE_KFET_CLIENT_ID = 'CHANGE_ME'
NOTE_KFET_CLIENT_SECRET = 'CHANGE_ME'
NOTE_KFET_SCOPES = '1_1 2_1 48_1'
......@@ -21,7 +21,7 @@ router.register(r'media/vinyl', media.views.VinylViewSet)
router.register(r'media/novel', media.views.NovelViewSet)
router.register(r'media/review', media.views.ReviewViewSet)
router.register(r'media/future', media.views.FutureMediumViewSet)
router.register(r'borrowed_items', media.views.EmpruntViewSet)
router.register(r'borrowed_items', media.views.BorrowViewSet)
router.register(r'games', media.views.GameViewSet)
router.register(r'users', users.views.UserViewSet)
router.register(r'groups', users.views.GroupViewSet)
......
......@@ -2,7 +2,6 @@
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.urls import reverse
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _
from polymorphic.admin import PolymorphicChildModelAdmin, \
......@@ -11,7 +10,7 @@ from med.admin import admin_site
from reversion.admin import VersionAdmin
from .forms import MediaAdminForm
from .models import Author, Borrowable, CD, Comic, Emprunt, FutureMedium, \
from .models import Author, Borrow, Borrowable, CD, Comic, FutureMedium, \
Game, Manga, Novel, Review, Vinyl
......@@ -120,30 +119,15 @@ class ReviewAdmin(VersionAdmin, PolymorphicChildModelAdmin):
show_in_index = True
class EmpruntAdmin(VersionAdmin):
list_display = ('media', 'user', 'date_emprunt', 'date_rendu',
'permanencier_emprunt', 'permanencier_rendu_custom')
search_fields = ('media__title', 'media__side_identifier',
'user__username', 'date_emprunt', 'date_rendu')
date_hierarchy = 'date_emprunt'
autocomplete_fields = ('media', 'user', 'permanencier_emprunt',
'permanencier_rendu')
def permanencier_rendu_custom(self, obj):
"""
Show a button if item has not been returned yet
"""
if obj.permanencier_rendu:
return obj.permanencier_rendu
else:
return format_html(
'<a class="button" href="{}">{}</a>',
reverse('media:retour-emprunt', args=[obj.pk]),
_('Turn back')
)
permanencier_rendu_custom.short_description = _('given back to')
permanencier_rendu_custom.allow_tags = True
class BorrowAdmin(VersionAdmin):
list_display = ('borrowable', 'user', 'borrow_date', 'borrowed_with',
'given_back_to')
search_fields = ('borrowable__isbn', 'borrowable__title',
'borrowable__medium__side_identifier',
'user__username', 'borrow_date', 'given_back')
date_hierarchy = 'borrow_date'
autocomplete_fields = ('borrowable', 'user', 'borrowed_with',
'given_back_to')
def add_view(self, request, form_url='', extra_context=None):
"""
......@@ -151,7 +135,7 @@ class EmpruntAdmin(VersionAdmin):
"""
# Make GET data mutable
data = request.GET.copy()
data['permanencier_emprunt'] = request.user
data['borrowed_with'] = request.user
request.GET = data
return super().add_view(request, form_url, extra_context)
......@@ -173,5 +157,5 @@ admin_site.register(CD, CDAdmin)
admin_site.register(Vinyl, VinylAdmin)
admin_site.register(Review, ReviewAdmin)
admin_site.register(FutureMedium, FutureMediumAdmin)
admin_site.register(Emprunt, EmpruntAdmin)
admin_site.register(Borrow, BorrowAdmin)
admin_site.register(Game, GameAdmin)
......@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-26 15:14+0200\n"
"POT-Creation-Date: 2021-11-14 14:25+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -13,8 +13,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin.py:46 admin.py:102 admin.py:114 models.py:30 models.py:77
#: models.py:149 models.py:221 models.py:290 models.py:348 models.py:394
#: admin.py:46 admin.py:102 admin.py:114 models.py:30 models.py:85
msgid "authors"
msgstr "auteurs"
......@@ -22,55 +21,47 @@ msgstr "auteurs"
msgid "external url"
msgstr "URL externe"
#: admin.py:142
msgid "Turn back"
msgstr "Rendre"
#: admin.py:145 models.py:574
msgid "given back to"
msgstr "rendu à"
#: fields.py:17
msgid "ISBN-10 or ISBN-13"
msgstr "ISBN-10 ou ISBN-13"
#: forms.py:301
#: forms.py:302
msgid "This ISBN is not found."
msgstr "L'ISBN n'a pas été trouvé."
#: management/commands/migrate_to_new_format.py:52 models.py:408 models.py:415
#: management/commands/migrate_to_new_format.py:57 models.py:156
msgid "CDs"
msgstr "CDs"
#: management/commands/migrate_to_new_format.py:52 models.py:407 models.py:414
#: management/commands/migrate_to_new_format.py:57 models.py:155
msgid "CD"
msgstr "CD"
#: management/commands/migrate_to_new_format.py:68 models.py:362 models.py:377
#: management/commands/migrate_to_new_format.py:73 models.py:149
msgid "vinyls"
msgstr "vinyles"
#: management/commands/migrate_to_new_format.py:68 models.py:361 models.py:376
#: management/commands/migrate_to_new_format.py:73 models.py:148
msgid "vinyl"
msgstr "vinyle"
#: management/commands/migrate_to_new_format.py:86 models.py:466 models.py:506
#: management/commands/migrate_to_new_format.py:91 models.py:196
msgid "reviews"
msgstr "revues"
#: management/commands/migrate_to_new_format.py:86 models.py:465 models.py:505
#: management/commands/migrate_to_new_format.py:91 models.py:195
msgid "review"
msgstr "revue"
#: management/commands/migrate_to_new_format.py:106 models.py:629 models.py:670
#: management/commands/migrate_to_new_format.py:111 models.py:315
msgid "games"
msgstr "jeux"
#: management/commands/migrate_to_new_format.py:106 models.py:628 models.py:669
#: management/commands/migrate_to_new_format.py:111 models.py:314
msgid "game"
msgstr "jeu"
#: models.py:17 models.py:598
#: models.py:17
msgid "name"
msgstr "nom"
......@@ -82,63 +73,59 @@ msgstr "note"
msgid "author"
msgstr "auteur"
#: models.py:37 models.py:127 models.py:199 models.py:268 models.py:329
#: models.py:383 models.py:421
#: models.py:36 models.py:202
msgid "ISBN"
msgstr "ISBN"
#: models.py:37 models.py:203
msgid "You may be able to scan it from a bar code."
msgstr "Peut souvent être scanné à partir du code barre."
#: models.py:45
msgid "title"
msgstr "titre"
#: models.py:41 models.py:165 models.py:237 models.py:306 models.py:352
#: models.py:398 models.py:456 models.py:530
#: models.py:49 models.py:220
msgid "present"
msgstr "présent"
#: models.py:42 models.py:166 models.py:238 models.py:307 models.py:353
#: models.py:399 models.py:457 models.py:531
#: models.py:50 models.py:221
msgid "Tell that the medium is present in the Mediatek."
msgstr "Indique que le medium est présent à la Mediatek."
#: models.py:60
#: models.py:68
msgid "borrowable"
msgstr "empruntable"
#: models.py:61
#: models.py:69
msgid "borrowables"
msgstr "empruntables"
#: models.py:66 models.py:138 models.py:210 models.py:279
#: models.py:74
msgid "external URL"
msgstr "URL externe"
#: models.py:71 models.py:143 models.py:215 models.py:284 models.py:334
#: models.py:388
#: models.py:79
msgid "side identifier"
msgstr "côte"
#: models.py:81
#: models.py:89
msgid "medium"
msgstr "medium"
#: models.py:82
#: models.py:90
msgid "media"
msgstr "media"
#: models.py:87 models.py:119 models.py:191 models.py:260 models.py:512
msgid "ISBN"
msgstr "ISBN"
#: models.py:88 models.py:120 models.py:192 models.py:261 models.py:513
msgid "You may be able to scan it from a bar code."
msgstr "Peut souvent être scanné à partir du code barre."
#: models.py:95 models.py:132 models.py:204 models.py:273
#: models.py:95
msgid "subtitle"
msgstr "sous-titre"
#: models.py:101 models.py:153 models.py:225 models.py:294
#: models.py:101
msgid "number of pages"
msgstr "nombre de pages"
#: models.py:107 models.py:159 models.py:231 models.py:300
#: models.py:107
msgid "publish date"
msgstr "date de publication"
......@@ -150,135 +137,143 @@ msgstr "livre"
msgid "books"
msgstr "livres"
#: models.py:177 models.py:184
#: models.py:119
msgid "comic"
msgstr "BD"
#: models.py:178 models.py:185
#: models.py:120
msgid "comics"
msgstr "BDs"
#: models.py:246 models.py:253
#: models.py:126
msgid "manga"
msgstr "manga"
#: models.py:247 models.py:254
#: models.py:127
msgid "mangas"
msgstr "mangas"
#: models.py:315 models.py:322
#: models.py:133
msgid "novel"
msgstr "roman"
#: models.py:316 models.py:323
#: models.py:134
msgid "novels"
msgstr "romans"
#: models.py:339 models.py:368
#: models.py:140
msgid "rounds per minute"
msgstr "tours par minute"
#: models.py:341 models.py:370
#: models.py:142
msgid "33 RPM"
msgstr "33 TPM"
#: models.py:342 models.py:371
#: models.py:143
msgid "45 RPM"
msgstr "45 TPM"
#: models.py:426 models.py:472
#: models.py:162
msgid "number"
msgstr "nombre"
#: models.py:430 models.py:476
#: models.py:166
msgid "year"
msgstr "année"
#: models.py:437 models.py:483
#: models.py:173
msgid "month"
msgstr "mois"
#: models.py:444 models.py:490
#: models.py:180
msgid "day"
msgstr "jour"
#: models.py:451 models.py:497
#: models.py:187
msgid "double"
msgstr "double"
#: models.py:520
#: models.py:210
msgid "type"
msgstr "type"
#: models.py:522
#: models.py:212
msgid "Comic"
msgstr "BD"
#: models.py:523
#: models.py:213
msgid "Manga"
msgstr "Manga"
#: models.py:524
#: models.py:214
msgid "Roman"
msgstr "Roman"
#: models.py:536
#: models.py:226
msgid "future medium"
msgstr "medium à importer"
#: models.py:537
#: models.py:227
msgid "future media"
msgstr "medias à importer"
#: models.py:551
#: models.py:237
msgid "object"
msgstr "objet"
#: models.py:242
msgid "borrower"
msgstr "emprunteur"
#: models.py:554
#: models.py:245
msgid "borrowed on"
msgstr "emprunté le"
#: models.py:559
#: models.py:250
msgid "given back on"
msgstr "rendu le"
#: models.py:565
#: models.py:256
msgid "borrowed with"
msgstr "emprunté avec"
#: models.py:566
#: models.py:257
msgid "The keyholder that registered this borrowed item."
msgstr "Le permanencier qui enregistre cet emprunt."
#: models.py:575
#: models.py:265
msgid "given back to"
msgstr "rendu à"
#: models.py:266
msgid "The keyholder to whom this item was given back."
msgstr "Le permanencier à qui l'emprunt a été rendu."
#: models.py:582
#: models.py:273
msgid "borrowed item"
msgstr "emprunt"
#: models.py:583
#: models.py:274
msgid "borrowed items"
msgstr "emprunts"
#: models.py:603 models.py:644
#: models.py:289
msgid "owner"
msgstr "propriétaire"
#: models.py:608 models.py:649
#: models.py:294
msgid "duration"
msgstr "durée"
#: models.py:612 models.py:653
#: models.py:298
msgid "minimum number of players"
msgstr "nombre minimum de joueurs"
#: models.py:616 models.py:657
#: models.py:302
msgid "maximum number of players"
msgstr "nombre maximum de joueurs"
#: models.py:621 models.py:662
#: models.py:307
msgid "comment"
msgstr "commentaire"
......@@ -306,6 +301,6 @@ msgstr "ISBN invalide : mauvaise longueur"
msgid "Invalid ISBN: Only upper case allowed"
msgstr "ISBN invalide : seulement les majuscules sont autorisées"
#: views.py:47
#: views.py:25
msgid "Welcome to the Mediatek database"
msgstr "Bienvenue sur la base de données de la Mediatek"
......@@ -20,7 +20,7 @@ class Command(BaseCommand):
"Old data structure has been deleted. This script won't work "
"anymore (and is now useless)"))
from media.models import OldCD, OldComic, OldGame, OldManga, OldNovel, \
from media.models import OldCD, OldComic, OldGame, OldManga, OldNovel,\
OldReview, OldVinyl
# Migrate books
......
# Generated by Django 2.2.24 on 2021-11-14 13:23
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('media', '0044_auto_20211102_1254'),
]
operations = [
migrations.CreateModel(
name='Borrow',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('borrow_date', models.DateTimeField(verbose_name='borrowed on')),
('given_back', models.DateTimeField(blank=True, null=True, verbose_name='given back on')),
('borrowable', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='media.Borrowable', verbose_name='object')),
('borrowed_with', models.ForeignKey(help_text='The keyholder that registered this borrowed item.', on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='borrowed with')),
('given_back_to', models.ForeignKey(blank=True, help_text='The keyholder to whom this item was given back.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='given back to')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='borrower')),
],
options={
'verbose_name': 'borrowed item',
'verbose_name_plural': 'borrowed items',
'ordering': ['-borrow_date'],
},
),
migrations.DeleteModel(
name='Emprunt',
),
]
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# Copyright (C) 2017-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.conf import settings
from django.core.validators import MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
......@@ -230,35 +230,36 @@ class FutureMedium(models.Model):
return "Future medium (ISBN: {isbn})".format(isbn=self.isbn, )
class Emprunt(models.Model):
media = models.ForeignKey(
class Borrow(models.Model):
borrowable = models.ForeignKey(
'media.Borrowable',
on_delete=models.PROTECT,
verbose_name=_('object'),
)
user = models.ForeignKey(
'users.User',
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
verbose_name=_("borrower"),
)
date_emprunt = models.DateTimeField(
borrow_date = models.DateTimeField(
verbose_name=_('borrowed on'),
)
date_rendu = models.DateTimeField(
given_back = models.DateTimeField(
blank=True,
null=True,
verbose_name=_('given back on'),
)
permanencier_emprunt = models.ForeignKey(
'users.User',
borrowed_with = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
related_name='user_permanencier_emprunt',
related_name='+',
verbose_name=_('borrowed with'),
help_text=_('The keyholder that registered this borrowed item.')
)
permanencier_rendu = models.ForeignKey(
'users.User',
given_back_to = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
related_name='user_permanencier_rendu',
related_name='+',
blank=True,
null=True,
verbose_name=_('given back to'),
......@@ -266,12 +267,12 @@ class Emprunt(models.Model):
)
def __str__(self):
return str(self.media) + str(self.user)
return str(self.borrowable) + str(self.user)
class Meta:
verbose_name = _("borrowed item")
verbose_name_plural = _("borrowed items")
ordering = ['-date_emprunt']
ordering = ['-borrow_date']
class Game(Borrowable):
......
from rest_framework import serializers
from .models import Author, CD, Comic, FutureMedium, Manga, Emprunt, Game, \
from .models import Author, Borrow, CD, Comic, FutureMedium, Manga, Game, \
Novel, Review, Vinyl
......@@ -52,15 +52,13 @@ class FutureMediumSerializer(serializers.ModelSerializer):
fields = '__all__'
class EmpruntSerializer(serializers.HyperlinkedModelSerializer):
class BorrowSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Emprunt
fields = ['url', 'media', 'user', 'date_emprunt', 'date_rendu',
'permanencier_emprunt', 'permanencier_rendu']