Add ISBN data downloader
This commit is contained in:
parent
2f872eccce
commit
861279d30d
|
@ -8,6 +8,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 MediaAdminForm
|
||||||
from .models import Auteur, Emprunt, Jeu, Media
|
from .models import Auteur, Emprunt, Jeu, Media
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,16 +18,43 @@ class AuteurAdmin(VersionAdmin):
|
||||||
|
|
||||||
|
|
||||||
class MediaAdmin(VersionAdmin):
|
class MediaAdmin(VersionAdmin):
|
||||||
list_display = ('title', 'authors_list', 'side_title', 'isbn')
|
list_display = ('title', 'authors_list', 'side_title', 'isbn',
|
||||||
|
'external_link')
|
||||||
search_fields = ('title', 'authors__nom', 'side_title', 'subtitle', 'isbn')
|
search_fields = ('title', 'authors__nom', 'side_title', 'subtitle', 'isbn')
|
||||||
autocomplete_fields = ('authors',)
|
autocomplete_fields = ('authors',)
|
||||||
date_hierarchy = 'publish_date'
|
date_hierarchy = 'publish_date'
|
||||||
|
form = MediaAdminForm
|
||||||
|
|
||||||
def authors_list(self, obj):
|
def authors_list(self, obj):
|
||||||
return ", ".join([a.nom for a in obj.authors.all()])
|
return ", ".join([a.nom for a in obj.authors.all()])
|
||||||
|
|
||||||
authors_list.short_description = _('authors')
|
authors_list.short_description = _('authors')
|
||||||
|
|
||||||
|
def external_link(self, obj):
|
||||||
|
return format_html('<a href="{}" target="about:blank">{}</a>',
|
||||||
|
obj.external_url, obj.external_url)
|
||||||
|
|
||||||
|
external_link.allow_tags = True
|
||||||
|
external_link.short_description = _('external url')
|
||||||
|
|
||||||
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Pass request to form (for ISBN magic)
|
||||||
|
"""
|
||||||
|
form = super().get_form(request, obj=obj, **kwargs)
|
||||||
|
form.request = request
|
||||||
|
return form
|
||||||
|
|
||||||
|
def changeform_view(self, request, object_id=None, form_url='',
|
||||||
|
extra_context=None):
|
||||||
|
"""
|
||||||
|
We use _continue for ISBN fetching, so remove continue button
|
||||||
|
"""
|
||||||
|
extra_context = extra_context or {}
|
||||||
|
extra_context['show_save_and_continue'] = False
|
||||||
|
return super().changeform_view(request, object_id, form_url,
|
||||||
|
extra_context=extra_context)
|
||||||
|
|
||||||
|
|
||||||
class EmpruntAdmin(VersionAdmin):
|
class EmpruntAdmin(VersionAdmin):
|
||||||
list_display = ('media', 'user', 'date_emprunt', 'date_rendu',
|
list_display = ('media', 'user', 'date_emprunt', 'date_rendu',
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
# 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
|
||||||
|
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
|
|
||||||
from .models import Emprunt
|
from .models import Emprunt
|
||||||
|
@ -11,3 +14,45 @@ class EmpruntForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Emprunt
|
model = Emprunt
|
||||||
fields = ['media']
|
fields = ['media']
|
||||||
|
|
||||||
|
|
||||||
|
class MediaAdminForm(ModelForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['isbn'].widget.template_name = "media/isbn_button.html"
|
||||||
|
|
||||||
|
def download_data(self, isbn):
|
||||||
|
"""
|
||||||
|
Download data from ISBN
|
||||||
|
"""
|
||||||
|
api_url = "https://openlibrary.org/api/books?bibkeys=ISBN:{}" \
|
||||||
|
"&format=json&jscmd=data".format(isbn)
|
||||||
|
with urllib.request.urlopen(api_url) as url:
|
||||||
|
data = json.loads(url.read().decode())
|
||||||
|
if data and data['ISBN:' + isbn]:
|
||||||
|
data = data['ISBN:' + isbn]
|
||||||
|
|
||||||
|
# Fill the data
|
||||||
|
# TODO implement authors
|
||||||
|
if data['title']:
|
||||||
|
self.cleaned_data['title'] = data['title']
|
||||||
|
self.cleaned_data['side_title'] = data['title']
|
||||||
|
if data['subtitle']:
|
||||||
|
self.cleaned_data['subtitle'] = data['subtitle']
|
||||||
|
if data['url']:
|
||||||
|
self.cleaned_data['external_url'] = data['url']
|
||||||
|
if data['number_of_pages']:
|
||||||
|
self.cleaned_data['number_of_pages'] = \
|
||||||
|
data['number_of_pages']
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
"""
|
||||||
|
If user fetch ISBN data, then download data before validating the form
|
||||||
|
"""
|
||||||
|
if "_continue" in self.request.POST:
|
||||||
|
isbn = self.cleaned_data.get('isbn')
|
||||||
|
if isbn:
|
||||||
|
# ISBN is present
|
||||||
|
self.download_data(isbn)
|
||||||
|
|
||||||
|
return super().clean()
|
||||||
|
|
|
@ -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: 2019-08-10 15:55+0200\n"
|
"POT-Creation-Date: 2019-08-11 10:39+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,46 +13,106 @@ 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:47
|
#: admin.py:31 models.py:20 models.py:51
|
||||||
msgid "Turn back"
|
|
||||||
msgstr "Rendre"
|
|
||||||
|
|
||||||
#: admin.py:50
|
|
||||||
msgid "permanencier rendu"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: models.py:17
|
|
||||||
msgid "author"
|
|
||||||
msgstr "auteur"
|
|
||||||
|
|
||||||
#: models.py:18
|
|
||||||
msgid "authors"
|
msgid "authors"
|
||||||
msgstr "auteurs"
|
msgstr "auteurs"
|
||||||
|
|
||||||
#: models.py:30
|
#: admin.py:38
|
||||||
|
msgid "external url"
|
||||||
|
msgstr "URL externe"
|
||||||
|
|
||||||
|
#: admin.py:78
|
||||||
|
msgid "Turn back"
|
||||||
|
msgstr "Rendre"
|
||||||
|
|
||||||
|
#: admin.py:81
|
||||||
|
msgid "permanencier rendu"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: fields.py:17
|
||||||
|
msgid "ISBN-10 or ISBN-13"
|
||||||
|
msgstr "ISBN-10 ou ISBN-13"
|
||||||
|
|
||||||
|
#: models.py:19
|
||||||
|
msgid "author"
|
||||||
|
msgstr "auteur"
|
||||||
|
|
||||||
|
#: models.py:25
|
||||||
|
msgid "ISBN"
|
||||||
|
msgstr "ISBN"
|
||||||
|
|
||||||
|
#: models.py:26
|
||||||
|
msgid "You may be able to scan it from a bar code."
|
||||||
|
msgstr "Peut souvent être scanné à partir du code barre."
|
||||||
|
|
||||||
|
#: models.py:31
|
||||||
|
msgid "title"
|
||||||
|
msgstr "titre"
|
||||||
|
|
||||||
|
#: models.py:35
|
||||||
|
msgid "subtitle"
|
||||||
|
msgstr "sous-titre"
|
||||||
|
|
||||||
|
#: models.py:41
|
||||||
|
msgid "external URL"
|
||||||
|
msgstr "URL externe"
|
||||||
|
|
||||||
|
#: models.py:46
|
||||||
|
msgid "side title"
|
||||||
|
msgstr "côte"
|
||||||
|
|
||||||
|
#: models.py:54
|
||||||
|
msgid "number of pages"
|
||||||
|
msgstr "nombre de pages"
|
||||||
|
|
||||||
|
#: models.py:59
|
||||||
|
msgid "publish date"
|
||||||
|
msgstr "date de publication"
|
||||||
|
|
||||||
|
#: models.py:68
|
||||||
msgid "medium"
|
msgid "medium"
|
||||||
msgstr "medium"
|
msgstr "medium"
|
||||||
|
|
||||||
#: models.py:31
|
#: models.py:69
|
||||||
msgid "media"
|
msgid "media"
|
||||||
msgstr "media"
|
msgstr "media"
|
||||||
|
|
||||||
#: models.py:60
|
#: models.py:98
|
||||||
msgid "borrowed item"
|
msgid "borrowed item"
|
||||||
msgstr "emprunt"
|
msgstr "emprunt"
|
||||||
|
|
||||||
#: models.py:61
|
#: models.py:99
|
||||||
msgid "borrowed items"
|
msgid "borrowed items"
|
||||||
msgstr "emprunts"
|
msgstr "emprunts"
|
||||||
|
|
||||||
#: models.py:85
|
#: models.py:123
|
||||||
msgid "game"
|
msgid "game"
|
||||||
msgstr "jeu"
|
msgstr "jeu"
|
||||||
|
|
||||||
#: models.py:86
|
#: models.py:124
|
||||||
msgid "games"
|
msgid "games"
|
||||||
msgstr "jeux"
|
msgstr "jeux"
|
||||||
|
|
||||||
|
#: templates/media/isbn_button.html:3
|
||||||
|
msgid "Fetch data"
|
||||||
|
msgstr "Télécharger les données"
|
||||||
|
|
||||||
|
#: validators.py:20
|
||||||
|
msgid "Invalid ISBN: Not a string"
|
||||||
|
msgstr "ISBN invalide : ce n'est pas une chaîne de caractères"
|
||||||
|
|
||||||
|
#: validators.py:23
|
||||||
|
msgid "Invalid ISBN: Wrong length"
|
||||||
|
msgstr "ISBN invalide : mauvaise longueur"
|
||||||
|
|
||||||
|
#: validators.py:26
|
||||||
|
msgid "Invalid ISBN: Failed checksum"
|
||||||
|
msgstr "ISBN invalide : mauvais checksum"
|
||||||
|
|
||||||
|
#: validators.py:29
|
||||||
|
msgid "Invalid ISBN: Only upper case allowed"
|
||||||
|
msgstr "ISBN invalide : seulement les majuscules sont autorisées"
|
||||||
|
|
||||||
#: views.py:41
|
#: views.py:41
|
||||||
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"
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
// curl 'https://openlibrary.org/api/books?bibkeys=ISBN:0201558025&format=json&jscmd=data'
|
|
||||||
a = {
|
|
||||||
"ISBN:0201558025": {
|
|
||||||
"publishers": [{"name": "Addison-Wesley"}],
|
|
||||||
"pagination": "xiii, 657 p. :",
|
|
||||||
"identifiers": {
|
|
||||||
"lccn": ["93040325"],
|
|
||||||
"openlibrary": ["OL1429049M"],
|
|
||||||
"isbn_10": ["0201558025"],
|
|
||||||
"wikidata": ["Q15303722"],
|
|
||||||
"goodreads": ["112243"],
|
|
||||||
"librarything": ["45844"]
|
|
||||||
},
|
|
||||||
//"subtitle": "a foundation for computer science",
|
|
||||||
//"title": "Concrete mathematics",
|
|
||||||
//"url": "https://openlibrary.org/books/OL1429049M/Concrete_mathematics",
|
|
||||||
"classifications": {"dewey_decimal_class": ["510"], "lc_classifications": ["QA39.2 .G733 1994"]},
|
|
||||||
"notes": "Includes bibliographical references (p. 604-631) and index.",
|
|
||||||
"number_of_pages": 657,
|
|
||||||
"cover": {
|
|
||||||
"small": "https://covers.openlibrary.org/b/id/135182-S.jpg",
|
|
||||||
"large": "https://covers.openlibrary.org/b/id/135182-L.jpg",
|
|
||||||
"medium": "https://covers.openlibrary.org/b/id/135182-M.jpg"
|
|
||||||
},
|
|
||||||
"subjects": [{
|
|
||||||
"url": "https://openlibrary.org/subjects/computer_science",
|
|
||||||
"name": "Computer science"
|
|
||||||
}, {"url": "https://openlibrary.org/subjects/mathematics", "name": "Mathematics"}],
|
|
||||||
"publish_date": "1994",
|
|
||||||
"key": "/books/OL1429049M",
|
|
||||||
"authors": [{
|
|
||||||
"url": "https://openlibrary.org/authors/OL720958A/Ronald_L._Graham",
|
|
||||||
"name": "Ronald L. Graham"
|
|
||||||
}, {
|
|
||||||
"url": "https://openlibrary.org/authors/OL229501A/Donald_Knuth",
|
|
||||||
"name": "Donald Knuth"
|
|
||||||
}, {"url": "https://openlibrary.org/authors/OL2669938A/Oren_Patashnik", "name": "Oren Patashnik"}],
|
|
||||||
"by_statement": "Ronald L. Graham, Donald E. Knuth, Oren Patashnik.",
|
|
||||||
"publish_places": [{"name": "Reading, Mass"}],
|
|
||||||
"ebooks": [{
|
|
||||||
"formats": {},
|
|
||||||
"preview_url": "https://archive.org/details/concretemathemat00grah_444",
|
|
||||||
"availability": "restricted"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% load i18n %}
|
||||||
|
{% include "django/forms/widgets/input.html" %}
|
||||||
|
<input type="submit" value="{% trans "Fetch data" %}" name="_continue">
|
|
@ -121,7 +121,7 @@ input[type=button]:focus, .button:hover, input[type=submit]:hover, input[type=bu
|
||||||
|
|
||||||
/* Pull footer to bottom */
|
/* Pull footer to bottom */
|
||||||
#content {
|
#content {
|
||||||
min-height: calc(100vh - 190px);
|
min-height: calc(100vh - 220px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login #content {
|
.login #content {
|
||||||
|
|
|
@ -103,7 +103,6 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
|
||||||
'<img src="/static/admin/img/icon-yes.svg" alt="True">'
|
'<img src="/static/admin/img/icon-yes.svg" alt="True">'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# TODO permit adhere only if perms.users.add_user
|
|
||||||
return format_html(
|
return format_html(
|
||||||
'<img src="/static/admin/img/icon-no.svg" alt="False"> '
|
'<img src="/static/admin/img/icon-no.svg" alt="False"> '
|
||||||
'<a class="button" href="{}">{}</a>',
|
'<a class="button" href="{}">{}</a>',
|
||||||
|
|
Loading…
Reference in New Issue