diff --git a/biscuit/apps/exlibris/__init__.py b/biscuit/apps/exlibris/__init__.py index caaacd4267c62fb008c4a399435a697ae212ef2a..d60bef7eb6ce08054d6d404700cad541b9c6fd94 100644 --- a/biscuit/apps/exlibris/__init__.py +++ b/biscuit/apps/exlibris/__init__.py @@ -1,11 +1,11 @@ import pkg_resources try: - __version__ = pkg_resources.get_distribution('BiscuIT-App-Exlibris').version + __version__ = pkg_resources.get_distribution("BiscuIT-App-Exlibris").version except Exception: - __version__ = 'unknown' + __version__ = "unknown" -default_app_config = 'biscuit.apps.exlibris.apps.ExlibrisConfig' +default_app_config = "biscuit.apps.exlibris.apps.ExlibrisConfig" # Additional apps to add to BiscuIT's INSTALLED_APPS on loading -INSTALLED_APPS = ['isbn_field'] +INSTALLED_APPS = ["isbn_field"] diff --git a/biscuit/apps/exlibris/apps.py b/biscuit/apps/exlibris/apps.py index 2c239bf646f0edc8a2dfe225c44bf7d1833b35a3..0f6da041e9932706cf739da36ea8843eea1c9669 100644 --- a/biscuit/apps/exlibris/apps.py +++ b/biscuit/apps/exlibris/apps.py @@ -2,5 +2,5 @@ from biscuit.core.util.apps import AppConfig class ExlibrisConfig(AppConfig): - name = 'biscuit.apps.exlibris' - verbose_name = 'BiscuIT - Exlibris (School book management)' + name = "biscuit.apps.exlibris" + verbose_name = "BiscuIT - Exlibris (School book management)" diff --git a/biscuit/apps/exlibris/forms.py b/biscuit/apps/exlibris/forms.py index 6665351f7e688ffeb4e1059b9a57ecf3f371e749..626624da0c48f794fe01e9e723b30cf9fb9ff83d 100644 --- a/biscuit/apps/exlibris/forms.py +++ b/biscuit/apps/exlibris/forms.py @@ -1,5 +1,6 @@ from django import forms from django.utils.translation import ugettext_lazy as _ + from django_select2.forms import Select2Widget from biscuit.core.models import Person @@ -10,47 +11,47 @@ from .models import Book, BookCopy class BookAddISBNForm(forms.ModelForm): class Meta: model = Book - fields = ['isbn'] + fields = ["isbn"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['isbn'].widget.attrs.update({'autofocus': 'autofocus'}) + self.fields["isbn"].widget.attrs.update({"autofocus": "autofocus"}) class BookGetCopyForm(forms.ModelForm): class Meta: model = BookCopy - fields = ['barcode'] + fields = ["barcode"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['barcode'].widget.attrs.update({'autofocus': 'autofocus'}) + self.fields["barcode"].widget.attrs.update({"autofocus": "autofocus"}) class BookEditForm(forms.ModelForm): class Meta: model = Book - fields = ['isbn', 'title', 'author', - 'publisher', 'year', 'edition', 'cover'] + fields = ["isbn", "title", "author", "publisher", "year", "edition", "cover"] class BookCopyEditForm(forms.ModelForm): class Meta: model = BookCopy - fields = ['borrower', 'borrow_count', - 'condition', 'remarks', 'barcode'] + fields = ["borrower", "borrow_count", "condition", "remarks", "barcode"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['borrower'].disabled = True + self.fields["borrower"].disabled = True class BookCopiesBulkAddForm(forms.Form): - count = forms.IntegerField(label=_('Number of copies')) + count = forms.IntegerField(label=_("Number of copies")) class PersonBorrowForm(forms.Form): - borrower = forms.ModelChoiceField(label=_('Person'), queryset=Person.objects.all(), widget=Select2Widget) - barcodes = forms.CharField(label=_('Barcodes'), widget=forms.Textarea) + borrower = forms.ModelChoiceField( + label=_("Person"), queryset=Person.objects.all(), widget=Select2Widget + ) + barcodes = forms.CharField(label=_("Barcodes"), widget=forms.Textarea) diff --git a/biscuit/apps/exlibris/menus.py b/biscuit/apps/exlibris/menus.py index 142e3d76a0b48002bbc780ef2efc86679863ca92..568e7aabc2f032ff03abf06cd102457ed530f636 100644 --- a/biscuit/apps/exlibris/menus.py +++ b/biscuit/apps/exlibris/menus.py @@ -1,34 +1,37 @@ from django.utils.translation import ugettext_lazy as _ MENUS = { - 'NAV_MENU_CORE': [ + "NAV_MENU_CORE": [ { - 'name': _('Books'), - 'url': '#', - 'root': True, - 'validators': ['menu_generator.validators.is_authenticated', 'biscuit.core.util.core_helpers.has_person'], - 'submenu': [ + "name": _("Books"), + "url": "#", + "root": True, + "validators": [ + "menu_generator.validators.is_authenticated", + "biscuit.core.util.core_helpers.has_person", + ], + "submenu": [ { - 'name': _('List of books'), - 'url': 'books', - 'validators': ['menu_generator.validators.is_authenticated'] + "name": _("List of books"), + "url": "books", + "validators": ["menu_generator.validators.is_authenticated"], }, { - 'name': _('Add book'), - 'url': 'add_book', - 'validators': ['menu_generator.validators.is_authenticated'] + "name": _("Add book"), + "url": "add_book", + "validators": ["menu_generator.validators.is_authenticated"], }, { - 'name': _('Open copy'), - 'url': 'get_copy', - 'validators': ['menu_generator.validators.is_authenticated'] + "name": _("Open copy"), + "url": "get_copy", + "validators": ["menu_generator.validators.is_authenticated"], }, { - 'name': _('Person borrowing'), - 'url': 'person_borrow', - 'validators': ['menu_generator.validators.is_authenticated'] - } - ] + "name": _("Person borrowing"), + "url": "person_borrow", + "validators": ["menu_generator.validators.is_authenticated"], + }, + ], } ] } diff --git a/biscuit/apps/exlibris/migrations/0001_initial.py b/biscuit/apps/exlibris/migrations/0001_initial.py index 0ac8362600c039a823841f33a2d9f31b8e08e184..54ee6920330b38edad15981194b462f1611982fa 100644 --- a/biscuit/apps/exlibris/migrations/0001_initial.py +++ b/biscuit/apps/exlibris/migrations/0001_initial.py @@ -1,53 +1,165 @@ # Generated by Django 2.2.5 on 2019-09-03 18:30 -import biscuit.core.util.core_helpers -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models + import isbn_field.fields import isbn_field.validators +import biscuit.core.util.core_helpers + class Migration(migrations.Migration): initial = True dependencies = [ - ('core', '0001_initial'), + ("core", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Book', + name="Book", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=50, verbose_name='Book title')), - ('author', models.CharField(blank=True, max_length=50, verbose_name='Author name')), - ('publisher', models.CharField(blank=True, max_length=50, verbose_name='Publishing company')), - ('edition', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Number of edition')), - ('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Publishing year')), - ('isbn', isbn_field.fields.ISBNField(max_length=28, unique=True, validators=[isbn_field.validators.ISBNValidator], verbose_name='ISBN number')), - ('cover', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Photo of cover')), - ('school', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.School')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=50, verbose_name="Book title")), + ( + "author", + models.CharField( + blank=True, max_length=50, verbose_name="Author name" + ), + ), + ( + "publisher", + models.CharField( + blank=True, max_length=50, verbose_name="Publishing company" + ), + ), + ( + "edition", + models.PositiveSmallIntegerField( + blank=True, null=True, verbose_name="Number of edition" + ), + ), + ( + "year", + models.PositiveSmallIntegerField( + blank=True, null=True, verbose_name="Publishing year" + ), + ), + ( + "isbn", + isbn_field.fields.ISBNField( + max_length=28, + unique=True, + validators=[isbn_field.validators.ISBNValidator], + verbose_name="ISBN number", + ), + ), + ( + "cover", + models.ImageField( + blank=True, + null=True, + upload_to="", + verbose_name="Photo of cover", + ), + ), + ( + "school", + models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.CASCADE, + to="core.School", + ), + ), ], options={ - 'ordering': ['title', 'year', 'edition'], - 'unique_together': {('school', 'title', 'author', 'edition', 'year')}, + "ordering": ["title", "year", "edition"], + "unique_together": {("school", "title", "author", "edition", "year")}, }, ), migrations.CreateModel( - name='BookCopy', + name="BookCopy", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('copy_num', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Current number of copy')), - ('borrow_count', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Number of borrowings')), - ('condition', models.CharField(blank=True, choices=[('U', 'New, unused'), ('N', 'New, used'), ('S', 'Slightly worn'), ('H', 'Heavily worn')], max_length=1, verbose_name='Condition')), - ('remarks', models.CharField(blank=True, max_length=100, verbose_name='Remarks')), - ('barcode', models.CharField(max_length=20, unique=True, verbose_name='Barcode')), - ('book', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='copies', to='exlibris.Book')), - ('borrower', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='books', to='core.Person')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "copy_num", + models.PositiveSmallIntegerField( + blank=True, null=True, verbose_name="Current number of copy" + ), + ), + ( + "borrow_count", + models.PositiveSmallIntegerField( + blank=True, null=True, verbose_name="Number of borrowings" + ), + ), + ( + "condition", + models.CharField( + blank=True, + choices=[ + ("U", "New, unused"), + ("N", "New, used"), + ("S", "Slightly worn"), + ("H", "Heavily worn"), + ], + max_length=1, + verbose_name="Condition", + ), + ), + ( + "remarks", + models.CharField( + blank=True, max_length=100, verbose_name="Remarks" + ), + ), + ( + "barcode", + models.CharField( + max_length=20, unique=True, verbose_name="Barcode" + ), + ), + ( + "book", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="copies", + to="exlibris.Book", + ), + ), + ( + "borrower", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="books", + to="core.Person", + ), + ), ], options={ - 'ordering': ['book__title', 'book__year', 'book__edition', 'copy_num'], + "ordering": ["book__title", "book__year", "book__edition", "copy_num"], }, ), ] diff --git a/biscuit/apps/exlibris/migrations/0002_db_indexes.py b/biscuit/apps/exlibris/migrations/0002_db_indexes.py index 81cac5b81d1092c5f30d76607b0a8b59be8943d1..c5d31ca3c5489ef7a3a4d8e58154172d5f9719fc 100644 --- a/biscuit/apps/exlibris/migrations/0002_db_indexes.py +++ b/biscuit/apps/exlibris/migrations/0002_db_indexes.py @@ -6,13 +6,15 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('core', '0001_initial'), - ('exlibris', '0001_initial'), + ("core", "0001_initial"), + ("exlibris", "0001_initial"), ] operations = [ migrations.AddIndex( - model_name='bookcopy', - index=models.Index(fields=['barcode'], name='exlibris_bo_co_barc_55ac33_idx'), + model_name="bookcopy", + index=models.Index( + fields=["barcode"], name="exlibris_bo_co_barc_55ac33_idx" + ), ), ] diff --git a/biscuit/apps/exlibris/models.py b/biscuit/apps/exlibris/models.py index 5ee717c707900da0da3c55a2ca3f5ca76b4f433a..713dd7f47ce93bcebd7c93a0f2153eff3e9631a5 100644 --- a/biscuit/apps/exlibris/models.py +++ b/biscuit/apps/exlibris/models.py @@ -7,24 +7,31 @@ from isbn_field import ISBNField class Book(models.Model): """A book that is available for borrowing by persons.""" - title = models.CharField(verbose_name=_('Book title'), max_length=50) - author = models.CharField(verbose_name=_( - 'Author name'), max_length=50, blank=True) - publisher = models.CharField(verbose_name=_( - 'Publishing company'), max_length=50, blank=True) + title = models.CharField(verbose_name=_("Book title"), max_length=50) + author = models.CharField(verbose_name=_("Author name"), max_length=50, blank=True) + publisher = models.CharField( + verbose_name=_("Publishing company"), max_length=50, blank=True + ) edition = models.PositiveSmallIntegerField( - verbose_name=_('Number of edition'), blank=True, null=True) + verbose_name=_("Number of edition"), blank=True, null=True + ) year = models.PositiveSmallIntegerField( - verbose_name=_('Publishing year'), blank=True, null=True) + verbose_name=_("Publishing year"), blank=True, null=True + ) - isbn = ISBNField(verbose_name=_('ISBN number'), unique=True) + isbn = ISBNField(verbose_name=_("ISBN number"), unique=True) - cover = models.ImageField(verbose_name=_( - 'Photo of cover'), blank=True, null=True) + cover = models.ImageField(verbose_name=_("Photo of cover"), blank=True, null=True) def __str__(self) -> str: - return '%s (%s, %d. %d %d)' % (self.title, self.author, self.edition, _('edition'), self.year) + return "%s (%s, %d. %d %d)" % ( + self.title, + self.author, + self.edition, + _("edition"), + self.year, + ) def is_deleteable(self) -> bool: for book_copy in self.copies.all(): @@ -34,8 +41,8 @@ class Book(models.Model): return True class Meta: - unique_together = [['title', 'author', 'edition', 'year']] - ordering = ['title', 'year', 'edition'] + unique_together = [["title", "author", "edition", "year"]] + ordering = ["title", "year", "edition"] class BookCopy(models.Model): @@ -44,40 +51,52 @@ class BookCopy(models.Model): """ CONDITION_CHOICES = [ - ('U', _('New, unused')), - ('N', _('New, used')), - ('S', _('Slightly worn')), - ('H', _('Heavily worn')) + ("U", _("New, unused")), + ("N", _("New, used")), + ("S", _("Slightly worn")), + ("H", _("Heavily worn")), ] book = models.ForeignKey( - 'Book', blank=True, null=True, on_delete=models.CASCADE, related_name='copies') + "Book", blank=True, null=True, on_delete=models.CASCADE, related_name="copies" + ) borrower = models.ForeignKey( - 'core.Person', blank=True, null=True, on_delete=models.CASCADE, related_name='books') + "core.Person", + blank=True, + null=True, + on_delete=models.CASCADE, + related_name="books", + ) copy_num = models.PositiveSmallIntegerField( - verbose_name=_('Current number of copy'), blank=True, null=True) + verbose_name=_("Current number of copy"), blank=True, null=True + ) borrow_count = models.PositiveSmallIntegerField( - verbose_name=_('Number of borrowings'), blank=True, null=True) + verbose_name=_("Number of borrowings"), blank=True, null=True + ) condition = models.CharField( - verbose_name=_('Condition'), choices=CONDITION_CHOICES, max_length=1, blank=True) - remarks = models.CharField( - verbose_name=_('Remarks'), max_length=100, blank=True) + verbose_name=_("Condition"), choices=CONDITION_CHOICES, max_length=1, blank=True + ) + remarks = models.CharField(verbose_name=_("Remarks"), max_length=100, blank=True) - barcode = models.CharField(verbose_name=_( - 'Barcode'), max_length=20, unique=True) + barcode = models.CharField(verbose_name=_("Barcode"), max_length=20, unique=True) def save(self, *args, **kwargs) -> None: if not self.copy_num: if self.book.copies.exclude(copy_num__isnull=True).exists(): - self.copy_num = self.book.copies.exclude( - copy_num__isnull=True).order_by('copy_num').last().copy_num + 1 + self.copy_num = ( + self.book.copies.exclude(copy_num__isnull=True) + .order_by("copy_num") + .last() + .copy_num + + 1 + ) else: self.copy_num = 1 if not self.barcode: - self.barcode = '%s-%s' % (self.book.isbn, self.copy_num) + self.barcode = "%s-%s" % (self.book.isbn, self.copy_num) super().save(*args, **kwargs) @@ -85,5 +104,5 @@ class BookCopy(models.Model): return not self.borrow_count and not self.borrower class Meta: - ordering = ['book__title', 'book__year', 'book__edition', 'copy_num'] - indexes = [models.Index(fields=['barcode'])] + ordering = ["book__title", "book__year", "book__edition", "copy_num"] + indexes = [models.Index(fields=["barcode"])] diff --git a/biscuit/apps/exlibris/tables.py b/biscuit/apps/exlibris/tables.py index 8baf6d26fd8175045769f9cabfc755bbb5a70981..1d6982e7589372942e3d073575ed20dcda944897 100644 --- a/biscuit/apps/exlibris/tables.py +++ b/biscuit/apps/exlibris/tables.py @@ -8,34 +8,48 @@ from django_tables2.utils import A class BooksTable(tables.Table): class Meta: attrs = { - 'class': 'table table-striped table-bordered table-hover table-responsive-xl'} - - isbn = tables.LinkColumn('book_by_id', args=[A('id')]) - - title = tables.LinkColumn('book_by_id', args=[A('id')], attrs={'td': { - 'data-poload': lambda record: reverse('book_card_by_id', kwargs={'id_': record.id})}}) + "class": "table table-striped table-bordered table-hover table-responsive-xl" + } + + isbn = tables.LinkColumn("book_by_id", args=[A("id")]) + + title = tables.LinkColumn( + "book_by_id", + args=[A("id")], + attrs={ + "td": { + "data-poload": lambda record: reverse( + "book_card_by_id", kwargs={"id_": record.id} + ) + } + }, + ) author = tables.Column() - num_copies = tables.Column(verbose_name=_( - 'Copies'), accessor='copies.count') + num_copies = tables.Column(verbose_name=_("Copies"), accessor="copies.count") - edit = tables.LinkColumn('edit_book_by_id', args=[ - A('id')], verbose_name='', text=_('Edit')) - delete = tables.LinkColumn('delete_book_by_id', args=[ - A('id')], verbose_name='', text=_('Delete')) + edit = tables.LinkColumn( + "edit_book_by_id", args=[A("id")], verbose_name="", text=_("Edit") + ) + delete = tables.LinkColumn( + "delete_book_by_id", args=[A("id")], verbose_name="", text=_("Delete") + ) class BookCopiesTable(tables.Table): class Meta: attrs = { - 'class': 'table table-striped table-bordered table-hover table-responsive-xl'} + "class": "table table-striped table-bordered table-hover table-responsive-xl" + } copy_num = tables.Column() borrower = tables.Column() condition = tables.Column() borrow_count = tables.Column() - edit = tables.LinkColumn('edit_book_copy_by_id', args=[ - A('id')], verbose_name='', text=_('Edit')) - delete = tables.LinkColumn('delete_book_copy_by_id', args=[ - A('id')], verbose_name='', text=_('Delete')) + edit = tables.LinkColumn( + "edit_book_copy_by_id", args=[A("id")], verbose_name="", text=_("Edit") + ) + delete = tables.LinkColumn( + "delete_book_copy_by_id", args=[A("id")], verbose_name="", text=_("Delete") + ) diff --git a/biscuit/apps/exlibris/urls.py b/biscuit/apps/exlibris/urls.py index ec7ebd00f587dc82096b771b116597a6e1064601..97cc05b7f3b73c3ab2bc94c07d594f1b038f9260 100644 --- a/biscuit/apps/exlibris/urls.py +++ b/biscuit/apps/exlibris/urls.py @@ -2,27 +2,36 @@ from django.urls import path from . import views - urlpatterns = [ - path('book/<int:id_>', views.book, - {'template': 'full'}, name='book_by_id'), - path('book/<int:id_>/card', views.book, - {'template': 'card'}, name='book_card_by_id'), - path('book/<int:id_>/edit', views.edit_book, name='edit_book_by_id'), - path('book/<int:id_>/delete', views.delete_book, name='delete_book_by_id'), - path('book/get_copy', views.get_copy, name='get_copy'), - path('book/copy/<barcode>', views.book_copy, - {'template': 'full'}, name='book_copy_by_barcode'), - path('book/<int:id_>/copies/labels', views.book_copies_labels, - name='copies_labels_by_book_id'), - path('book/copy/<int:id_>/edit', views.edit_book_copy, - name='edit_book_copy_by_id'), - path('book/copy/<int:id_>/delete', views.delete_book_copy, - name='delete_book_copy_by_id'), - path('book/<int:id_>/copies/add', views.add_book_copies, - name='add_copies_by_book_id'), - path('book/add', views.add_book, name='add_book'), - path('book/isbn/<isbn>', views.edit_book, name='edit_book_by_isbn'), - path('books', views.books, name='books'), - path('books/borrowing/person', views.person_borrow, name='person_borrow') + path("book/<int:id_>", views.book, {"template": "full"}, name="book_by_id"), + path( + "book/<int:id_>/card", views.book, {"template": "card"}, name="book_card_by_id" + ), + path("book/<int:id_>/edit", views.edit_book, name="edit_book_by_id"), + path("book/<int:id_>/delete", views.delete_book, name="delete_book_by_id"), + path("book/get_copy", views.get_copy, name="get_copy"), + path( + "book/copy/<barcode>", + views.book_copy, + {"template": "full"}, + name="book_copy_by_barcode", + ), + path( + "book/<int:id_>/copies/labels", + views.book_copies_labels, + name="copies_labels_by_book_id", + ), + path("book/copy/<int:id_>/edit", views.edit_book_copy, name="edit_book_copy_by_id"), + path( + "book/copy/<int:id_>/delete", + views.delete_book_copy, + name="delete_book_copy_by_id", + ), + path( + "book/<int:id_>/copies/add", views.add_book_copies, name="add_copies_by_book_id" + ), + path("book/add", views.add_book, name="add_book"), + path("book/isbn/<isbn>", views.edit_book, name="edit_book_by_isbn"), + path("books", views.books, name="books"), + path("books/borrowing/person", views.person_borrow, name="person_borrow"), ] diff --git a/biscuit/apps/exlibris/util.py b/biscuit/apps/exlibris/util.py index 645ad2f436b9c365560a8e5b323d264eba197850..6cd6db0cb09ef6b3f144c0a6deb57c963c39f774 100644 --- a/biscuit/apps/exlibris/util.py +++ b/biscuit/apps/exlibris/util.py @@ -6,24 +6,24 @@ import isbnlib def get_book_meta(isbn: str) -> Dict[str, str]: meta_result = {} - for provider in 'dnb', 'openl', 'goob': + for provider in "dnb", "openl", "goob": try: meta_result.update(isbnlib.meta(isbn, provider)) except: pass meta_translated = {} - if 'Title' in meta_result: - meta_translated['title'] = meta_result['Title'] - if 'Authors' in meta_result: - meta_translated['author'] = ', '.join(meta_result['Authors']) - if 'Publisher' in meta_result: - meta_translated['publisher'] = meta_result['Publisher'] - if 'Year' in meta_result: + if "Title" in meta_result: + meta_translated["title"] = meta_result["Title"] + if "Authors" in meta_result: + meta_translated["author"] = ", ".join(meta_result["Authors"]) + if "Publisher" in meta_result: + meta_translated["publisher"] = meta_result["Publisher"] + if "Year" in meta_result: try: - meta_translated['year'] = int(meta_result['Year']) + meta_translated["year"] = int(meta_result["Year"]) except ValueError: pass - meta_translated['isbn'] = isbn + meta_translated["isbn"] = isbn return meta_translated diff --git a/biscuit/apps/exlibris/views.py b/biscuit/apps/exlibris/views.py index f223f2f44e755a08d0e6c30903b42675ddd4a29b..70350f4b2e4686134e03dfa2213bf23e683187bd 100644 --- a/biscuit/apps/exlibris/views.py +++ b/biscuit/apps/exlibris/views.py @@ -1,5 +1,5 @@ -from io import BytesIO import os +from io import BytesIO from tempfile import TemporaryDirectory from typing import Optional @@ -9,17 +9,24 @@ from django.shortcuts import get_object_or_404, redirect, render from django.utils.text import slugify from django.utils.translation import ugettext as _ -from django_tables2 import RequestConfig import labels import PIL +from django_tables2 import RequestConfig from reportlab.graphics import barcode, shapes from biscuit.core.models import School from biscuit.core.util import messages -from .forms import BookAddISBNForm, BookEditForm, BookCopiesBulkAddForm, BookCopyEditForm, BookGetCopyForm, PersonBorrowForm +from .forms import ( + BookAddISBNForm, + BookCopiesBulkAddForm, + BookCopyEditForm, + BookEditForm, + BookGetCopyForm, + PersonBorrowForm, +) from .models import Book, BookCopy -from .tables import BooksTable, BookCopiesTable +from .tables import BookCopiesTable, BooksTable from .util import get_book_meta @@ -33,9 +40,9 @@ def books(request: HttpRequest) -> HttpResponse: # Build table books_table = BooksTable(books) RequestConfig(request).configure(books_table) - context['books_table'] = books_table + context["books_table"] = books_table - return render(request, 'exlibris/books.html', context) + return render(request, "exlibris/books.html", context) @login_required @@ -44,17 +51,21 @@ def add_book(request: HttpRequest) -> HttpResponse: book_add_isbn_form = BookAddISBNForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": if book_add_isbn_form.is_valid(): - return redirect('edit_book_by_isbn', isbn=book_add_isbn_form.cleaned_data['isbn']) + return redirect( + "edit_book_by_isbn", isbn=book_add_isbn_form.cleaned_data["isbn"] + ) - context['book_add_isbn_form'] = book_add_isbn_form + context["book_add_isbn_form"] = book_add_isbn_form - return render(request, 'exlibris/add_book.html', context) + return render(request, "exlibris/add_book.html", context) @login_required -def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[str] = None) -> HttpResponse: +def edit_book( + request: HttpRequest, id_: Optional[int] = None, isbn: Optional[str] = None +) -> HttpResponse: context = {} if id_: @@ -62,9 +73,10 @@ def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[st book = get_object_or_404(Book, pk=id_) book_edit_form = BookEditForm( - request.POST or None, request.FILES or None, instance=book) + request.POST or None, request.FILES or None, instance=book + ) - context['book'] = book + context["book"] = book else: # If no id was passed, create a new book @@ -73,24 +85,24 @@ def edit_book(request: HttpRequest, id_: Optional[int] = None, isbn: Optional[st initial = get_book_meta(isbn) if initial: - messages.info(request, _( - 'Information found for this ISBN was pre-filled.')) + messages.info(request, _("Information found for this ISBN was pre-filled.")) else: - messages.warning(request, _('No information found for this ISBN.')) + messages.warning(request, _("No information found for this ISBN.")) book_edit_form = BookEditForm( - request.POST or None, request.FILES or None, initial=initial) + request.POST or None, request.FILES or None, initial=initial + ) - if request.method == 'POST': + if request.method == "POST": if book_edit_form.is_valid(): book_edit_form.save(commit=True) - messages.success(request, _('The book has been saved.')) - return redirect('books') + messages.success(request, _("The book has been saved.")) + return redirect("books") - context['book_edit_form'] = book_edit_form + context["book_edit_form"] = book_edit_form - return render(request, 'exlibris/edit_book.html', context) + return render(request, "exlibris/edit_book.html", context) @login_required @@ -100,12 +112,13 @@ def delete_book(request: HttpRequest, id_: int) -> HttpResponse: if book.is_deleteable(): book.delete() - messages.success(request, _('Book %s has been deleted.') % title) + messages.success(request, _("Book %s has been deleted.") % title) else: - messages.error(request, - _('Books with copies that have been borrowed cannot be deleted.')) + messages.error( + request, _("Books with copies that have been borrowed cannot be deleted.") + ) - return redirect('books') + return redirect("books") @login_required @@ -113,7 +126,7 @@ def book(request: HttpRequest, id_: int, template: str) -> HttpResponse: context = {} book = get_object_or_404(Book, pk=id_) - context['book'] = book + context["book"] = book # Get all copies copies = book.copies.all() @@ -121,9 +134,9 @@ def book(request: HttpRequest, id_: int, template: str) -> HttpResponse: # Build table copies_table = BookCopiesTable(copies) RequestConfig(request).configure(copies_table) - context['copies_table'] = copies_table + context["copies_table"] = copies_table - return render(request, 'exlibris/book_%s.html' % template, context) + return render(request, "exlibris/book_%s.html" % template, context) @login_required @@ -131,25 +144,28 @@ def add_book_copies(request: HttpRequest, id_: int) -> HttpResponse: context = {} book = get_object_or_404(Book, pk=id_) - context['book'] = book + context["book"] = book bulk_add_form = BookCopiesBulkAddForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": if bulk_add_form.is_valid(): - new_copies = [BookCopy(book=book) for _ in range( - bulk_add_form.cleaned_data['count'])] + new_copies = [ + BookCopy(book=book) for _ in range(bulk_add_form.cleaned_data["count"]) + ] for new_copy in new_copies: new_copy.save() - messages.success(request, _('%d copies have been created.') % - bulk_add_form.cleaned_data['count']) - return redirect('book_by_id', id_=book.pk) + messages.success( + request, + _("%d copies have been created.") % bulk_add_form.cleaned_data["count"], + ) + return redirect("book_by_id", id_=book.pk) - context['book'] = book - context['bulk_add_form'] = bulk_add_form + context["book"] = book + context["bulk_add_form"] = bulk_add_form - return render(request, 'exlibris/add_book_copies.html', context) + return render(request, "exlibris/add_book_copies.html", context) @login_required @@ -157,21 +173,20 @@ def edit_book_copy(request: HttpRequest, id_: int) -> HttpResponse: context = {} book_copy = get_object_or_404(BookCopy, pk=id_) - book_copy_edit_form = BookCopyEditForm( - request.POST or None, instance=book_copy) + book_copy_edit_form = BookCopyEditForm(request.POST or None, instance=book_copy) - context['book_copy'] = book_copy + context["book_copy"] = book_copy - if request.method == 'POST': + if request.method == "POST": if book_copy_edit_form.is_valid(): book_copy_edit_form.save(commit=True) - messages.success(request, _('The book copy has been saved.')) - return redirect('book_by_id', id_=book_copy.book.pk) + messages.success(request, _("The book copy has been saved.")) + return redirect("book_by_id", id_=book_copy.book.pk) - context['book_copy_edit_form'] = book_copy_edit_form + context["book_copy_edit_form"] = book_copy_edit_form - return render(request, 'exlibris/edit_book_copy.html', context) + return render(request, "exlibris/edit_book_copy.html", context) @login_required @@ -181,13 +196,13 @@ def delete_book_copy(request: HttpRequest, id_: int) -> HttpResponse: if book_copy.is_deleteable(): book_copy.delete() - messages.success(request, _( - 'Book copy of %s has been deleted.') % book.title) + messages.success(request, _("Book copy of %s has been deleted.") % book.title) else: - messages.error(request, - _('Book copies that have been borrowed cannot be deleted.')) + messages.error( + request, _("Book copies that have been borrowed cannot be deleted.") + ) - return redirect('book_by_id', id_=book.id) + return redirect("book_by_id", id_=book.id) @login_required @@ -196,32 +211,46 @@ def book_copies_labels(request: HttpRequest, id_: int) -> HttpResponse: copies = book.copies.all() with TemporaryDirectory() as temp_dir: + def draw_label(label, width, height, obj): title = shapes.String(0, height - 10, obj.book.title, fontSize=10) label.add(title) copy_desc = shapes.String( - 0, height - 20, _('Copy number: %d') % obj.copy_num, fontSize=8) + 0, height - 20, _("Copy number: %d") % obj.copy_num, fontSize=8 + ) label.add(copy_desc) barcode_raw = barcode.createBarcodeImageInMemory( - 'Code128', value=obj.barcode, width=400, height=120) + "Code128", value=obj.barcode, width=400, height=120 + ) barcode_image = PIL.Image.open(BytesIO(barcode_raw)) barcode_file = os.path.join(temp_dir, "%s.png" % obj.barcode) - barcode_image.save(barcode_file, 'png') - label.add(shapes.Image(0, 30, width, 30, - os.path.join(temp_dir, barcode_file))) + barcode_image.save(barcode_file, "png") + label.add( + shapes.Image(0, 30, width, 30, os.path.join(temp_dir, barcode_file)) + ) - school = shapes.String( - 0, 8, School.objects.first().name, fontSize=10) + school = shapes.String(0, 8, School.objects.first().name, fontSize=10) label.add(school) bottom_line = shapes.String( - 0, 0, 'BiscuIT, the Free School Information System', fontSize=6) + 0, 0, "BiscuIT, the Free School Information System", fontSize=6 + ) label.add(bottom_line) specs = labels.Specification( - 210, 297, 3, 7, 63, 40, left_padding=3, top_padding=3, bottom_padding=3, right_padding=3) + 210, + 297, + 3, + 7, + 63, + 40, + left_padding=3, + top_padding=3, + bottom_padding=3, + right_padding=3, + ) sheet = labels.Sheet(specs, draw_label) sheet.add_labels(copies) @@ -229,7 +258,7 @@ def book_copies_labels(request: HttpRequest, id_: int) -> HttpResponse: pdf_file = os.path.join(temp_dir, "label_%s.pdf" % slugify(book.title)) sheet.save(pdf_file) - return FileResponse(open(pdf_file, 'rb'), as_attachment=True) + return FileResponse(open(pdf_file, "rb"), as_attachment=True) @login_required @@ -238,13 +267,15 @@ def get_copy(request: HttpRequest) -> HttpResponse: book_copy_form = BookGetCopyForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": if book_copy_form.is_valid(): - return redirect('book_copy_by_barcode', barcode=book_copy_form.cleaned_data['barcode']) + return redirect( + "book_copy_by_barcode", barcode=book_copy_form.cleaned_data["barcode"] + ) - context['book_copy_form'] = book_copy_form + context["book_copy_form"] = book_copy_form - return render(request, 'exlibris/get_copy.html', context) + return render(request, "exlibris/get_copy.html", context) @login_required @@ -252,9 +283,9 @@ def book_copy(request: HttpRequest, barcode: str, template: str) -> HttpResponse context = {} book_copy = get_object_or_404(BookCopy, barcode=barcode) - context['book_copy'] = book_copy + context["book_copy"] = book_copy - return render(request, 'exlibris/copy_%s.html' % template, context) + return render(request, "exlibris/copy_%s.html" % template, context) @login_required @@ -263,27 +294,35 @@ def person_borrow(request: HttpRequest) -> HttpResponse: person_borrow_form = PersonBorrowForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": if person_borrow_form.is_valid(): - person = person_borrow_form.cleaned_data['borrower'] + person = person_borrow_form.cleaned_data["borrower"] - for barcode_line in person_borrow_form.cleaned_data['barcodes'].splitlines(): + for barcode_line in person_borrow_form.cleaned_data[ + "barcodes" + ].splitlines(): try: book_copy = BookCopy.objects.get(barcode=barcode_line) except BookCopy.DoesNotExist: - messages.error(request, _('Barcode %(barcode)s is invalid.') % - {'barcode': barcode_line}) + messages.error( + request, + _("Barcode %(barcode)s is invalid.") + % {"barcode": barcode_line}, + ) continue book_copy.borrower = person book_copy.borrow_count = book_copy.borrow_count + 1 book_copy.save() - messages.success(request, _('Book %(title)s borrowed to %(person)s.') % - {'title': book_copy.book.title, 'person': person}) + messages.success( + request, + _("Book %(title)s borrowed to %(person)s.") + % {"title": book_copy.book.title, "person": person}, + ) person_borrow_form = PersonBorrowForm() - context['person_borrow_form'] = person_borrow_form + context["person_borrow_form"] = person_borrow_form - return render(request, 'exlibris/person_borrow.html', context) + return render(request, "exlibris/person_borrow.html", context)