mirror of
https://gitlab.crans.org/mediatek/med.git
synced 2025-02-25 06:26:32 +00:00
Compare commits
No commits in common. "e75f04b53014ebe6bd299bc58e42622e48340e6b" and "aceb0d893c2d97c4f98cab62a49fd01bd129f537" have entirely different histories.
e75f04b530
...
aceb0d893c
@ -7,7 +7,7 @@ from django.contrib.auth.admin import Group, GroupAdmin
|
|||||||
from django.contrib.sites.admin import Site, SiteAdmin
|
from django.contrib.sites.admin import Site, SiteAdmin
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from media.models import Borrow
|
from media.models import Emprunt
|
||||||
|
|
||||||
|
|
||||||
class DatabaseAdmin(AdminSite):
|
class DatabaseAdmin(AdminSite):
|
||||||
@ -22,8 +22,8 @@ class DatabaseAdmin(AdminSite):
|
|||||||
|
|
||||||
# User is always authenticated
|
# User is always authenticated
|
||||||
# Get currently borrowed items
|
# Get currently borrowed items
|
||||||
user_borrowed = Borrow.objects.filter(user=request.user,
|
user_borrowed = Emprunt.objects.filter(user=request.user,
|
||||||
given_back=None)
|
date_rendu=None)
|
||||||
response.context_data["borrowed_items"] = user_borrowed
|
response.context_data["borrowed_items"] = user_borrowed
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -167,6 +167,8 @@ PAGINATION_NUMBER = 25
|
|||||||
|
|
||||||
AUTH_USER_MODEL = 'users.User'
|
AUTH_USER_MODEL = 'users.User'
|
||||||
|
|
||||||
|
MAX_EMPRUNT = 5 # Max emprunts
|
||||||
|
|
||||||
# AUTHLIB CLIENTS
|
# AUTHLIB CLIENTS
|
||||||
AUTHLIB_OAUTH_CLIENTS = {
|
AUTHLIB_OAUTH_CLIENTS = {
|
||||||
'notekfet': {
|
'notekfet': {
|
||||||
|
@ -21,7 +21,7 @@ router.register(r'media/vinyl', media.views.VinylViewSet)
|
|||||||
router.register(r'media/novel', media.views.NovelViewSet)
|
router.register(r'media/novel', media.views.NovelViewSet)
|
||||||
router.register(r'media/review', media.views.ReviewViewSet)
|
router.register(r'media/review', media.views.ReviewViewSet)
|
||||||
router.register(r'media/future', media.views.FutureMediumViewSet)
|
router.register(r'media/future', media.views.FutureMediumViewSet)
|
||||||
router.register(r'borrowed_items', media.views.BorrowViewSet)
|
router.register(r'borrowed_items', media.views.EmpruntViewSet)
|
||||||
router.register(r'games', media.views.GameViewSet)
|
router.register(r'games', media.views.GameViewSet)
|
||||||
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)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# 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 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 polymorphic.admin import PolymorphicChildModelAdmin, \
|
from polymorphic.admin import PolymorphicChildModelAdmin, \
|
||||||
@ -10,7 +11,7 @@ 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, Borrow, Borrowable, CD, Comic, FutureMedium, \
|
from .models import Author, Borrowable, CD, Comic, Emprunt, FutureMedium, \
|
||||||
Game, Manga, Novel, Review, Vinyl
|
Game, Manga, Novel, Review, Vinyl
|
||||||
|
|
||||||
|
|
||||||
@ -119,15 +120,30 @@ class ReviewAdmin(VersionAdmin, PolymorphicChildModelAdmin):
|
|||||||
show_in_index = True
|
show_in_index = True
|
||||||
|
|
||||||
|
|
||||||
class BorrowAdmin(VersionAdmin):
|
class EmpruntAdmin(VersionAdmin):
|
||||||
list_display = ('borrowable', 'user', 'borrow_date', 'borrowed_with',
|
list_display = ('media', 'user', 'date_emprunt', 'date_rendu',
|
||||||
'given_back_to')
|
'permanencier_emprunt', 'permanencier_rendu_custom')
|
||||||
search_fields = ('borrowable__isbn', 'borrowable__title',
|
search_fields = ('media__title', 'media__side_identifier',
|
||||||
'borrowable__medium__side_identifier',
|
'user__username', 'date_emprunt', 'date_rendu')
|
||||||
'user__username', 'borrow_date', 'given_back')
|
date_hierarchy = 'date_emprunt'
|
||||||
date_hierarchy = 'borrow_date'
|
autocomplete_fields = ('media', 'user', 'permanencier_emprunt',
|
||||||
autocomplete_fields = ('borrowable', 'user', 'borrowed_with',
|
'permanencier_rendu')
|
||||||
'given_back_to')
|
|
||||||
|
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
|
||||||
|
|
||||||
def add_view(self, request, form_url='', extra_context=None):
|
def add_view(self, request, form_url='', extra_context=None):
|
||||||
"""
|
"""
|
||||||
@ -135,7 +151,7 @@ class BorrowAdmin(VersionAdmin):
|
|||||||
"""
|
"""
|
||||||
# Make GET data mutable
|
# Make GET data mutable
|
||||||
data = request.GET.copy()
|
data = request.GET.copy()
|
||||||
data['borrowed_with'] = request.user
|
data['permanencier_emprunt'] = request.user
|
||||||
request.GET = data
|
request.GET = data
|
||||||
return super().add_view(request, form_url, extra_context)
|
return super().add_view(request, form_url, extra_context)
|
||||||
|
|
||||||
@ -157,5 +173,5 @@ admin_site.register(CD, CDAdmin)
|
|||||||
admin_site.register(Vinyl, VinylAdmin)
|
admin_site.register(Vinyl, VinylAdmin)
|
||||||
admin_site.register(Review, ReviewAdmin)
|
admin_site.register(Review, ReviewAdmin)
|
||||||
admin_site.register(FutureMedium, FutureMediumAdmin)
|
admin_site.register(FutureMedium, FutureMediumAdmin)
|
||||||
admin_site.register(Borrow, BorrowAdmin)
|
admin_site.register(Emprunt, EmpruntAdmin)
|
||||||
admin_site.register(Game, GameAdmin)
|
admin_site.register(Game, GameAdmin)
|
||||||
|
@ -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-11-14 14:25+0100\n"
|
"POT-Creation-Date: 2021-10-26 15:14+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,7 +13,8 @@ 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:46 admin.py:102 admin.py:114 models.py:30 models.py:85
|
#: 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
|
||||||
msgid "authors"
|
msgid "authors"
|
||||||
msgstr "auteurs"
|
msgstr "auteurs"
|
||||||
|
|
||||||
@ -21,47 +22,55 @@ msgstr "auteurs"
|
|||||||
msgid "external url"
|
msgid "external url"
|
||||||
msgstr "URL externe"
|
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
|
#: fields.py:17
|
||||||
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:302
|
#: forms.py:301
|
||||||
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é."
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:57 models.py:156
|
#: management/commands/migrate_to_new_format.py:52 models.py:408 models.py:415
|
||||||
msgid "CDs"
|
msgid "CDs"
|
||||||
msgstr "CDs"
|
msgstr "CDs"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:57 models.py:155
|
#: management/commands/migrate_to_new_format.py:52 models.py:407 models.py:414
|
||||||
msgid "CD"
|
msgid "CD"
|
||||||
msgstr "CD"
|
msgstr "CD"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:73 models.py:149
|
#: management/commands/migrate_to_new_format.py:68 models.py:362 models.py:377
|
||||||
msgid "vinyls"
|
msgid "vinyls"
|
||||||
msgstr "vinyles"
|
msgstr "vinyles"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:73 models.py:148
|
#: management/commands/migrate_to_new_format.py:68 models.py:361 models.py:376
|
||||||
msgid "vinyl"
|
msgid "vinyl"
|
||||||
msgstr "vinyle"
|
msgstr "vinyle"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:91 models.py:196
|
#: management/commands/migrate_to_new_format.py:86 models.py:466 models.py:506
|
||||||
msgid "reviews"
|
msgid "reviews"
|
||||||
msgstr "revues"
|
msgstr "revues"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:91 models.py:195
|
#: management/commands/migrate_to_new_format.py:86 models.py:465 models.py:505
|
||||||
msgid "review"
|
msgid "review"
|
||||||
msgstr "revue"
|
msgstr "revue"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:111 models.py:315
|
#: management/commands/migrate_to_new_format.py:106 models.py:629 models.py:670
|
||||||
msgid "games"
|
msgid "games"
|
||||||
msgstr "jeux"
|
msgstr "jeux"
|
||||||
|
|
||||||
#: management/commands/migrate_to_new_format.py:111 models.py:314
|
#: management/commands/migrate_to_new_format.py:106 models.py:628 models.py:669
|
||||||
msgid "game"
|
msgid "game"
|
||||||
msgstr "jeu"
|
msgstr "jeu"
|
||||||
|
|
||||||
#: models.py:17
|
#: models.py:17 models.py:598
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr "nom"
|
msgstr "nom"
|
||||||
|
|
||||||
@ -73,59 +82,63 @@ msgstr "note"
|
|||||||
msgid "author"
|
msgid "author"
|
||||||
msgstr "auteur"
|
msgstr "auteur"
|
||||||
|
|
||||||
#: models.py:36 models.py:202
|
#: models.py:37 models.py:127 models.py:199 models.py:268 models.py:329
|
||||||
msgid "ISBN"
|
#: models.py:383 models.py:421
|
||||||
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"
|
msgid "title"
|
||||||
msgstr "titre"
|
msgstr "titre"
|
||||||
|
|
||||||
#: models.py:49 models.py:220
|
#: models.py:41 models.py:165 models.py:237 models.py:306 models.py:352
|
||||||
|
#: models.py:398 models.py:456 models.py:530
|
||||||
msgid "present"
|
msgid "present"
|
||||||
msgstr "présent"
|
msgstr "présent"
|
||||||
|
|
||||||
#: models.py:50 models.py:221
|
#: models.py:42 models.py:166 models.py:238 models.py:307 models.py:353
|
||||||
|
#: models.py:399 models.py:457 models.py:531
|
||||||
msgid "Tell that the medium is present in the Mediatek."
|
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:68
|
#: models.py:60
|
||||||
msgid "borrowable"
|
msgid "borrowable"
|
||||||
msgstr "empruntable"
|
msgstr "empruntable"
|
||||||
|
|
||||||
#: models.py:69
|
#: models.py:61
|
||||||
msgid "borrowables"
|
msgid "borrowables"
|
||||||
msgstr "empruntables"
|
msgstr "empruntables"
|
||||||
|
|
||||||
#: models.py:74
|
#: models.py:66 models.py:138 models.py:210 models.py:279
|
||||||
msgid "external URL"
|
msgid "external URL"
|
||||||
msgstr "URL externe"
|
msgstr "URL externe"
|
||||||
|
|
||||||
#: models.py:79
|
#: models.py:71 models.py:143 models.py:215 models.py:284 models.py:334
|
||||||
|
#: models.py:388
|
||||||
msgid "side identifier"
|
msgid "side identifier"
|
||||||
msgstr "côte"
|
msgstr "côte"
|
||||||
|
|
||||||
#: models.py:89
|
#: models.py:81
|
||||||
msgid "medium"
|
msgid "medium"
|
||||||
msgstr "medium"
|
msgstr "medium"
|
||||||
|
|
||||||
#: models.py:90
|
#: models.py:82
|
||||||
msgid "media"
|
msgid "media"
|
||||||
msgstr "media"
|
msgstr "media"
|
||||||
|
|
||||||
#: models.py:95
|
#: 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
|
||||||
msgid "subtitle"
|
msgid "subtitle"
|
||||||
msgstr "sous-titre"
|
msgstr "sous-titre"
|
||||||
|
|
||||||
#: models.py:101
|
#: models.py:101 models.py:153 models.py:225 models.py:294
|
||||||
msgid "number of pages"
|
msgid "number of pages"
|
||||||
msgstr "nombre de pages"
|
msgstr "nombre de pages"
|
||||||
|
|
||||||
#: models.py:107
|
#: models.py:107 models.py:159 models.py:231 models.py:300
|
||||||
msgid "publish date"
|
msgid "publish date"
|
||||||
msgstr "date de publication"
|
msgstr "date de publication"
|
||||||
|
|
||||||
@ -137,143 +150,135 @@ msgstr "livre"
|
|||||||
msgid "books"
|
msgid "books"
|
||||||
msgstr "livres"
|
msgstr "livres"
|
||||||
|
|
||||||
#: models.py:119
|
#: models.py:177 models.py:184
|
||||||
msgid "comic"
|
msgid "comic"
|
||||||
msgstr "BD"
|
msgstr "BD"
|
||||||
|
|
||||||
#: models.py:120
|
#: models.py:178 models.py:185
|
||||||
msgid "comics"
|
msgid "comics"
|
||||||
msgstr "BDs"
|
msgstr "BDs"
|
||||||
|
|
||||||
#: models.py:126
|
#: models.py:246 models.py:253
|
||||||
msgid "manga"
|
msgid "manga"
|
||||||
msgstr "manga"
|
msgstr "manga"
|
||||||
|
|
||||||
#: models.py:127
|
#: models.py:247 models.py:254
|
||||||
msgid "mangas"
|
msgid "mangas"
|
||||||
msgstr "mangas"
|
msgstr "mangas"
|
||||||
|
|
||||||
#: models.py:133
|
#: models.py:315 models.py:322
|
||||||
msgid "novel"
|
msgid "novel"
|
||||||
msgstr "roman"
|
msgstr "roman"
|
||||||
|
|
||||||
#: models.py:134
|
#: models.py:316 models.py:323
|
||||||
msgid "novels"
|
msgid "novels"
|
||||||
msgstr "romans"
|
msgstr "romans"
|
||||||
|
|
||||||
#: models.py:140
|
#: models.py:339 models.py:368
|
||||||
msgid "rounds per minute"
|
msgid "rounds per minute"
|
||||||
msgstr "tours par minute"
|
msgstr "tours par minute"
|
||||||
|
|
||||||
#: models.py:142
|
#: models.py:341 models.py:370
|
||||||
msgid "33 RPM"
|
msgid "33 RPM"
|
||||||
msgstr "33 TPM"
|
msgstr "33 TPM"
|
||||||
|
|
||||||
#: models.py:143
|
#: models.py:342 models.py:371
|
||||||
msgid "45 RPM"
|
msgid "45 RPM"
|
||||||
msgstr "45 TPM"
|
msgstr "45 TPM"
|
||||||
|
|
||||||
#: models.py:162
|
#: models.py:426 models.py:472
|
||||||
msgid "number"
|
msgid "number"
|
||||||
msgstr "nombre"
|
msgstr "nombre"
|
||||||
|
|
||||||
#: models.py:166
|
#: models.py:430 models.py:476
|
||||||
msgid "year"
|
msgid "year"
|
||||||
msgstr "année"
|
msgstr "année"
|
||||||
|
|
||||||
#: models.py:173
|
#: models.py:437 models.py:483
|
||||||
msgid "month"
|
msgid "month"
|
||||||
msgstr "mois"
|
msgstr "mois"
|
||||||
|
|
||||||
#: models.py:180
|
#: models.py:444 models.py:490
|
||||||
msgid "day"
|
msgid "day"
|
||||||
msgstr "jour"
|
msgstr "jour"
|
||||||
|
|
||||||
#: models.py:187
|
#: models.py:451 models.py:497
|
||||||
msgid "double"
|
msgid "double"
|
||||||
msgstr "double"
|
msgstr "double"
|
||||||
|
|
||||||
#: models.py:210
|
#: models.py:520
|
||||||
msgid "type"
|
msgid "type"
|
||||||
msgstr "type"
|
msgstr "type"
|
||||||
|
|
||||||
#: models.py:212
|
#: models.py:522
|
||||||
msgid "Comic"
|
msgid "Comic"
|
||||||
msgstr "BD"
|
msgstr "BD"
|
||||||
|
|
||||||
#: models.py:213
|
#: models.py:523
|
||||||
msgid "Manga"
|
msgid "Manga"
|
||||||
msgstr "Manga"
|
msgstr "Manga"
|
||||||
|
|
||||||
#: models.py:214
|
#: models.py:524
|
||||||
msgid "Roman"
|
msgid "Roman"
|
||||||
msgstr "Roman"
|
msgstr "Roman"
|
||||||
|
|
||||||
#: models.py:226
|
#: models.py:536
|
||||||
msgid "future medium"
|
msgid "future medium"
|
||||||
msgstr "medium à importer"
|
msgstr "medium à importer"
|
||||||
|
|
||||||
#: models.py:227
|
#: models.py:537
|
||||||
msgid "future media"
|
msgid "future media"
|
||||||
msgstr "medias à importer"
|
msgstr "medias à importer"
|
||||||
|
|
||||||
#: models.py:237
|
#: models.py:551
|
||||||
msgid "object"
|
|
||||||
msgstr "objet"
|
|
||||||
|
|
||||||
#: models.py:242
|
|
||||||
msgid "borrower"
|
msgid "borrower"
|
||||||
msgstr "emprunteur"
|
msgstr "emprunteur"
|
||||||
|
|
||||||
#: models.py:245
|
#: models.py:554
|
||||||
msgid "borrowed on"
|
msgid "borrowed on"
|
||||||
msgstr "emprunté le"
|
msgstr "emprunté le"
|
||||||
|
|
||||||
#: models.py:250
|
#: models.py:559
|
||||||
msgid "given back on"
|
msgid "given back on"
|
||||||
msgstr "rendu le"
|
msgstr "rendu le"
|
||||||
|
|
||||||
#: models.py:256
|
#: models.py:565
|
||||||
msgid "borrowed with"
|
msgid "borrowed with"
|
||||||
msgstr "emprunté avec"
|
msgstr "emprunté avec"
|
||||||
|
|
||||||
#: models.py:257
|
#: models.py:566
|
||||||
msgid "The keyholder that registered this borrowed item."
|
msgid "The keyholder that registered this borrowed item."
|
||||||
msgstr "Le permanencier qui enregistre cet emprunt."
|
msgstr "Le permanencier qui enregistre cet emprunt."
|
||||||
|
|
||||||
#: models.py:265
|
#: models.py:575
|
||||||
msgid "given back to"
|
|
||||||
msgstr "rendu à"
|
|
||||||
|
|
||||||
#: models.py:266
|
|
||||||
msgid "The keyholder to whom this item was given back."
|
msgid "The keyholder to whom this item was given back."
|
||||||
msgstr "Le permanencier à qui l'emprunt a été rendu."
|
msgstr "Le permanencier à qui l'emprunt a été rendu."
|
||||||
|
|
||||||
#: models.py:273
|
#: models.py:582
|
||||||
msgid "borrowed item"
|
msgid "borrowed item"
|
||||||
msgstr "emprunt"
|
msgstr "emprunt"
|
||||||
|
|
||||||
#: models.py:274
|
#: models.py:583
|
||||||
msgid "borrowed items"
|
msgid "borrowed items"
|
||||||
msgstr "emprunts"
|
msgstr "emprunts"
|
||||||
|
|
||||||
#: models.py:289
|
#: models.py:603 models.py:644
|
||||||
msgid "owner"
|
msgid "owner"
|
||||||
msgstr "propriétaire"
|
msgstr "propriétaire"
|
||||||
|
|
||||||
#: models.py:294
|
#: models.py:608 models.py:649
|
||||||
msgid "duration"
|
msgid "duration"
|
||||||
msgstr "durée"
|
msgstr "durée"
|
||||||
|
|
||||||
#: models.py:298
|
#: models.py:612 models.py:653
|
||||||
msgid "minimum number of players"
|
msgid "minimum number of players"
|
||||||
msgstr "nombre minimum de joueurs"
|
msgstr "nombre minimum de joueurs"
|
||||||
|
|
||||||
#: models.py:302
|
#: models.py:616 models.py:657
|
||||||
msgid "maximum number of players"
|
msgid "maximum number of players"
|
||||||
msgstr "nombre maximum de joueurs"
|
msgstr "nombre maximum de joueurs"
|
||||||
|
|
||||||
#: models.py:307
|
#: models.py:621 models.py:662
|
||||||
msgid "comment"
|
msgid "comment"
|
||||||
msgstr "commentaire"
|
msgstr "commentaire"
|
||||||
|
|
||||||
@ -301,6 +306,6 @@ 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:25
|
#: views.py:47
|
||||||
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"
|
||||||
|
@ -20,7 +20,7 @@ class Command(BaseCommand):
|
|||||||
"Old data structure has been deleted. This script won't work "
|
"Old data structure has been deleted. This script won't work "
|
||||||
"anymore (and is now useless)"))
|
"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
|
OldReview, OldVinyl
|
||||||
|
|
||||||
# Migrate books
|
# Migrate books
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
# 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',
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python; coding: utf-8 -*-
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
# Copyright (C) 2017-2021 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 django.conf import settings
|
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -230,36 +230,35 @@ class FutureMedium(models.Model):
|
|||||||
return "Future medium (ISBN: {isbn})".format(isbn=self.isbn, )
|
return "Future medium (ISBN: {isbn})".format(isbn=self.isbn, )
|
||||||
|
|
||||||
|
|
||||||
class Borrow(models.Model):
|
class Emprunt(models.Model):
|
||||||
borrowable = models.ForeignKey(
|
media = models.ForeignKey(
|
||||||
'media.Borrowable',
|
'media.Borrowable',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
verbose_name=_('object'),
|
|
||||||
)
|
)
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
'users.User',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
verbose_name=_("borrower"),
|
verbose_name=_("borrower"),
|
||||||
)
|
)
|
||||||
borrow_date = models.DateTimeField(
|
date_emprunt = models.DateTimeField(
|
||||||
verbose_name=_('borrowed on'),
|
verbose_name=_('borrowed on'),
|
||||||
)
|
)
|
||||||
given_back = models.DateTimeField(
|
date_rendu = models.DateTimeField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name=_('given back on'),
|
verbose_name=_('given back on'),
|
||||||
)
|
)
|
||||||
borrowed_with = models.ForeignKey(
|
permanencier_emprunt = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
'users.User',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='user_permanencier_emprunt',
|
||||||
verbose_name=_('borrowed with'),
|
verbose_name=_('borrowed with'),
|
||||||
help_text=_('The keyholder that registered this borrowed item.')
|
help_text=_('The keyholder that registered this borrowed item.')
|
||||||
)
|
)
|
||||||
given_back_to = models.ForeignKey(
|
permanencier_rendu = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
'users.User',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='+',
|
related_name='user_permanencier_rendu',
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name=_('given back to'),
|
verbose_name=_('given back to'),
|
||||||
@ -267,12 +266,12 @@ class Borrow(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.borrowable) + str(self.user)
|
return str(self.media) + str(self.user)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("borrowed item")
|
verbose_name = _("borrowed item")
|
||||||
verbose_name_plural = _("borrowed items")
|
verbose_name_plural = _("borrowed items")
|
||||||
ordering = ['-borrow_date']
|
ordering = ['-date_emprunt']
|
||||||
|
|
||||||
|
|
||||||
class Game(Borrowable):
|
class Game(Borrowable):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import Author, Borrow, CD, Comic, FutureMedium, Manga, Game, \
|
from .models import Author, CD, Comic, FutureMedium, Manga, Emprunt, Game, \
|
||||||
Novel, Review, Vinyl
|
Novel, Review, Vinyl
|
||||||
|
|
||||||
|
|
||||||
@ -52,13 +52,15 @@ class FutureMediumSerializer(serializers.ModelSerializer):
|
|||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class BorrowSerializer(serializers.HyperlinkedModelSerializer):
|
class EmpruntSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Borrow
|
model = Emprunt
|
||||||
fields = '__all__'
|
fields = ['url', 'media', 'user', 'date_emprunt', 'date_rendu',
|
||||||
|
'permanencier_emprunt', 'permanencier_rendu']
|
||||||
|
|
||||||
|
|
||||||
class GameSerializer(serializers.HyperlinkedModelSerializer):
|
class GameSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Game
|
model = Game
|
||||||
fields = '__all__'
|
fields = ['url', 'name', 'proprietaire', 'duree', 'nombre_joueurs_min',
|
||||||
|
'nombre_joueurs_max', 'comment']
|
||||||
|
@ -55,10 +55,10 @@ class TemplateTests(TestCase):
|
|||||||
), data=data)
|
), data=data)
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
def test_comic_borrow_changelist(self):
|
def test_comic_emprunt_changelist(self):
|
||||||
response = self.client.get(reverse('admin:media_borrow_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_borrow_add(self):
|
def test_comic_emprunt_add(self):
|
||||||
response = self.client.get(reverse('admin:media_borrow_add'))
|
response = self.client.get(reverse('admin:media_emprunt_add'))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -2,12 +2,15 @@
|
|||||||
# 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 django.conf.urls import url
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
app_name = 'media'
|
app_name = 'media'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
url(r'^retour_emprunt/(?P<empruntid>[0-9]+)$', views.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/comic/<int:pk>/',
|
path('mark-as-present/comic/<int:pk>/',
|
||||||
views.MarkComicAsPresent.as_view(),
|
views.MarkComicAsPresent.as_view(),
|
||||||
|
@ -2,20 +2,42 @@
|
|||||||
# 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 django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
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.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
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
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.filters import SearchFilter
|
from rest_framework.filters import SearchFilter
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
from .models import Author, Borrow, CD, Comic, FutureMedium, Game, Manga,\
|
from .models import Author, CD, Comic, Emprunt, FutureMedium, Game, Manga,\
|
||||||
Novel, Review, Vinyl
|
Novel, Review, Vinyl
|
||||||
from .serializers import AuthorSerializer, BorrowSerializer, ComicSerializer, \
|
from .serializers import AuthorSerializer, ComicSerializer, CDSerializer,\
|
||||||
CDSerializer, FutureMediumSerializer, GameSerializer, MangaSerializer, \
|
EmpruntSerializer, FutureMediumSerializer, GameSerializer, \
|
||||||
NovelSerializer, ReviewSerializer, VinylSerializer
|
MangaSerializer, NovelSerializer, ReviewSerializer, VinylSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@permission_required('media.change_emprunt')
|
||||||
|
def retour_emprunt(request, empruntid):
|
||||||
|
try:
|
||||||
|
emprunt_instance = Emprunt.objects.get(pk=empruntid)
|
||||||
|
except Emprunt.DoesNotExist:
|
||||||
|
messages.error(request, u"Entrée inexistante")
|
||||||
|
return redirect("admin:media_emprunt_changelist")
|
||||||
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
emprunt_instance.permanencier_rendu = request.user
|
||||||
|
emprunt_instance.date_rendu = timezone.now()
|
||||||
|
emprunt_instance.save()
|
||||||
|
reversion.set_user(request.user)
|
||||||
|
messages.success(request, "Retour enregistré")
|
||||||
|
return redirect("admin:media_emprunt_changelist")
|
||||||
|
|
||||||
|
|
||||||
class IndexView(TemplateView):
|
class IndexView(TemplateView):
|
||||||
@ -159,12 +181,12 @@ class FutureMediumViewSet(viewsets.ModelViewSet):
|
|||||||
search_fields = ["=isbn"]
|
search_fields = ["=isbn"]
|
||||||
|
|
||||||
|
|
||||||
class BorrowViewSet(viewsets.ModelViewSet):
|
class EmpruntViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
API endpoint that allows borrowed items to be viewed or edited.
|
API endpoint that allows borrowed items to be viewed or edited.
|
||||||
"""
|
"""
|
||||||
queryset = Borrow.objects.all()
|
queryset = Emprunt.objects.all()
|
||||||
serializer_class = BorrowSerializer
|
serializer_class = EmpruntSerializer
|
||||||
|
|
||||||
|
|
||||||
class GameViewSet(viewsets.ModelViewSet):
|
class GameViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -64,9 +64,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<li><strong>{% trans 'date joined' %}</strong> : {{ user.date_joined }}</li>
|
<li><strong>{% trans 'date joined' %}</strong> : {{ user.date_joined }}</li>
|
||||||
<li><strong>{% trans 'last login' %}</strong> : {{ user.last_login }}</li>
|
<li><strong>{% trans 'last login' %}</strong> : {{ user.last_login }}</li>
|
||||||
<li><strong>{% trans 'address' %}</strong> : {{ user.address }}</li>
|
<li><strong>{% trans 'address' %}</strong> : {{ user.address }}</li>
|
||||||
<li><strong>{% trans 'phone number' %}</strong> : {{ user.phone_number }}</li>
|
<li><strong>{% trans 'phone number' %}</strong> : {{ user.telephone }}</li>
|
||||||
<li><strong>{% trans 'groups' %}</strong> : {% for g in user.groups.all %}{{ g.name }} {% endfor %}
|
<li><strong>{% trans 'groups' %}</strong> : {% for g in user.groups.all %}{{ g.name }} {% endfor %}
|
||||||
</li>
|
</li>
|
||||||
|
<li><strong>{% trans 'maximum borrowed' %}</strong> : {{ user.maxemprunt }}</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>{% trans 'membership for current year' %}</strong> :
|
<strong>{% trans 'membership for current year' %}</strong> :
|
||||||
{% if user.is_member %}
|
{% if user.is_member %}
|
||||||
@ -80,8 +81,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<h3>{% trans 'Current borrowed items' %}</h3>
|
<h3>{% trans 'Current borrowed items' %}</h3>
|
||||||
{% if borrowed_items %}
|
{% if borrowed_items %}
|
||||||
<ul>
|
<ul>
|
||||||
{% for borrow in borrowed_items %}
|
{% for emprunt in borrowed_items %}
|
||||||
<li>{{ borrow.object }} ({% trans 'since' %} {{ borrow.borrow_date }})</li>
|
<li>{{ emprunt.media }} ({% trans 'since' %} {{ emprunt.date_emprunt }})</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -12,6 +12,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from reversion.admin import VersionAdmin
|
from reversion.admin import VersionAdmin
|
||||||
from med.admin import admin_site
|
from med.admin import admin_site
|
||||||
|
|
||||||
|
from .forms import UserCreationAdminForm
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
@ -34,17 +35,28 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
|
|||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('username', 'password')}),
|
(None, {'fields': ('username', 'password')}),
|
||||||
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email',
|
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email',
|
||||||
'phone_number', 'address',
|
'telephone', 'address', 'comment')}),
|
||||||
'comment')}),
|
|
||||||
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
|
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
|
||||||
'groups', 'user_permissions')}),
|
'groups', 'user_permissions',
|
||||||
|
'maxemprunt')}),
|
||||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||||
)
|
)
|
||||||
list_display = ('username', 'email', 'first_name', 'last_name',
|
list_display = ('username', 'email', 'first_name', 'last_name',
|
||||||
'is_member', 'is_staff')
|
'maxemprunt', 'is_member', 'is_staff')
|
||||||
list_filter = (IsMemberFilter, 'is_staff', 'is_superuser', 'is_active',
|
list_filter = (IsMemberFilter, 'is_staff', 'is_superuser', 'is_active',
|
||||||
'groups')
|
'groups')
|
||||||
|
|
||||||
|
# Customize required initial fields
|
||||||
|
add_form_template = 'admin/change_form.html'
|
||||||
|
add_form = UserCreationAdminForm
|
||||||
|
add_fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': ("username", "email", "first_name", "last_name",
|
||||||
|
"address", "telephone"),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
"""
|
"""
|
||||||
On creation, send a password init mail
|
On creation, send a password init mail
|
||||||
|
57
users/forms.py
Normal file
57
users/forms.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.forms import UsernameField
|
||||||
|
from django.core.validators import MinLengthValidator
|
||||||
|
from django.forms import ModelForm
|
||||||
|
|
||||||
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
|
class PassForm(forms.Form):
|
||||||
|
passwd1 = forms.CharField(
|
||||||
|
label=u'Nouveau mot de passe',
|
||||||
|
max_length=255,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
)
|
||||||
|
passwd2 = forms.CharField(
|
||||||
|
label=u'Saisir à nouveau le mot de passe',
|
||||||
|
max_length=255,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
widget=forms.PasswordInput
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseInfoForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = [
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'address',
|
||||||
|
'telephone',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class UserCreationAdminForm(ModelForm):
|
||||||
|
"""
|
||||||
|
A form that creates a user, with no privileges,
|
||||||
|
from the given information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['email'].required = True
|
||||||
|
self.fields['first_name'].required = True
|
||||||
|
self.fields['last_name'].required = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ("username", "email", "first_name", "last_name", "address",
|
||||||
|
"telephone")
|
||||||
|
field_classes = {'username': UsernameField}
|
@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 2.2.24 on 2021-11-14 13:23
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('users', '0044_membership'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name='user',
|
|
||||||
old_name='telephone',
|
|
||||||
new_name='phone_number',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='user',
|
|
||||||
name='maxemprunt',
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,5 +1,5 @@
|
|||||||
# -*- mode: python; coding: utf-8 -*-
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
# Copyright (C) 2017-2021 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 datetime import datetime
|
from datetime import datetime
|
||||||
@ -12,10 +12,11 @@ from django.db import models
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
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 med.settings import MAX_EMPRUNT
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
phone_number = models.CharField(
|
telephone = models.CharField(
|
||||||
verbose_name=_('phone number'),
|
verbose_name=_('phone number'),
|
||||||
max_length=15,
|
max_length=15,
|
||||||
blank=True,
|
blank=True,
|
||||||
@ -25,6 +26,12 @@ class User(AbstractUser):
|
|||||||
max_length=255,
|
max_length=255,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
maxemprunt = models.IntegerField(
|
||||||
|
verbose_name=_('maximum borrowed'),
|
||||||
|
help_text=_('Maximal amount of simultaneous borrowed item '
|
||||||
|
'authorized.'),
|
||||||
|
default=MAX_EMPRUNT,
|
||||||
|
)
|
||||||
comment = models.CharField(
|
comment = models.CharField(
|
||||||
verbose_name=_('comment'),
|
verbose_name=_('comment'),
|
||||||
help_text=_('Promotion...'),
|
help_text=_('Promotion...'),
|
||||||
@ -32,7 +39,7 @@ class User(AbstractUser):
|
|||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
date_joined = models.DateTimeField(
|
date_joined = models.DateTimeField(
|
||||||
verbose_name=_('date joined'),
|
_('date joined'),
|
||||||
default=timezone.now,
|
default=timezone.now,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
@ -62,7 +69,7 @@ class User(AbstractUser):
|
|||||||
self.email = data['email']
|
self.email = data['email']
|
||||||
self.first_name = data['first_name']
|
self.first_name = data['first_name']
|
||||||
self.last_name = data['last_name']
|
self.last_name = data['last_name']
|
||||||
self.phone_number = data['profile']['phone_number']
|
self.telephone = data['profile']['phone_number']
|
||||||
self.address = data['profile']['address']
|
self.address = data['profile']['address']
|
||||||
self.comment = data['profile']['section']
|
self.comment = data['profile']['section']
|
||||||
|
|
||||||
@ -97,9 +104,6 @@ class Membership(models.Model):
|
|||||||
verbose_name=_('start date'),
|
verbose_name=_('start date'),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'{self.user}: {self.date_start} to {self.date_end}'
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('membership')
|
verbose_name = _('membership')
|
||||||
verbose_name_plural = _('memberships')
|
verbose_name_plural = _('memberships')
|
||||||
@ -205,9 +209,6 @@ class AccessToken(models.Model):
|
|||||||
def get_token(cls, request):
|
def get_token(cls, request):
|
||||||
return AccessToken.objects.get(pk=request.session['access_token_id'])
|
return AccessToken.objects.get(pk=request.session['access_token_id'])
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.access_token
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('access token')
|
verbose_name = _('access token')
|
||||||
verbose_name_plural = _('access tokens')
|
verbose_name_plural = _('access tokens')
|
||||||
|
@ -8,7 +8,7 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['url', 'username', 'first_name', 'last_name', 'email',
|
fields = ['url', 'username', 'first_name', 'last_name', 'email',
|
||||||
'groups', 'phone_number', 'address', 'comment',
|
'groups', 'telephone', 'address', 'maxemprunt', 'comment',
|
||||||
'date_joined']
|
'date_joined']
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# -*- mode: python; coding: utf-8 -*-
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from django.core import mail
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from users.models import User
|
from users.models import User
|
||||||
@ -22,3 +23,19 @@ class TemplateTests(TestCase):
|
|||||||
def test_users_user_changelist(self):
|
def test_users_user_changelist(self):
|
||||||
response = self.client.get(reverse('admin:users_user_changelist'))
|
response = self.client.get(reverse('admin:users_user_changelist'))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_users_user_add_init_mail(self):
|
||||||
|
"""
|
||||||
|
Test that an initialization mail is send when a new user is added
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'username': "test_user",
|
||||||
|
'email': "test@example.com",
|
||||||
|
'first_name': "Test",
|
||||||
|
'last_name': "User",
|
||||||
|
}
|
||||||
|
response = self.client.post(reverse(
|
||||||
|
'admin:users_user_add',
|
||||||
|
), data=data)
|
||||||
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
@ -20,8 +20,7 @@ class LoginView(RedirectView):
|
|||||||
oauth = OAuth()
|
oauth = OAuth()
|
||||||
oauth.register('notekfet')
|
oauth.register('notekfet')
|
||||||
redirect_url = self.request.build_absolute_uri(reverse('users:auth'))
|
redirect_url = self.request.build_absolute_uri(reverse('users:auth'))
|
||||||
return oauth.notekfet.authorize_redirect(self.request,
|
return oauth.notekfet.authorize_redirect(self.request, redirect_url).url
|
||||||
redirect_url).url
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizeView(RedirectView):
|
class AuthorizeView(RedirectView):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user