From 7c0590355001858385b5a7a8ff2a22996d5e7201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Schweigh=C3=B6fer?= Date: Fri, 4 Aug 2017 16:09:38 +0200 Subject: [PATCH] Changed many things: Added Literature Info models Separated Literature sources Given students ability to add literature to models ... more --- pyBuchaktion/admin.py | 119 +++- pyBuchaktion/forms.py | 21 +- pyBuchaktion/locale/de/LC_MESSAGES/django.po | 516 ++++++++++-------- pyBuchaktion/messages.py | 5 +- .../migrations/0014_auto_20170606_1829.py | 33 ++ .../migrations/0015_auto_20170713_0649.py | 31 ++ pyBuchaktion/models.py | 20 +- .../static/pyBuchaktion/pyBuchaktion.css | 38 +- .../templates/pyBuchaktion/admin/import.html | 10 + .../templates/pyBuchaktion/module.html | 36 +- .../templates/pyBuchaktion/module_base.html | 20 + .../module_literature_create.html | 19 + .../pyBuchaktion/tags/grid_books.html | 4 + .../pyBuchaktion/tags/grid_books_header.html | 13 + .../pyBuchaktion/tags/grid_row_book.html | 33 ++ .../pyBuchaktion/tags/table_row_book.html | 32 +- pyBuchaktion/templatetags/buchaktion_tags.py | 4 + pyBuchaktion/urls.py | 6 +- pyBuchaktion/views.py | 51 +- tucan-export/tucan-export.py | 15 +- 20 files changed, 742 insertions(+), 284 deletions(-) create mode 100644 pyBuchaktion/migrations/0014_auto_20170606_1829.py create mode 100644 pyBuchaktion/migrations/0015_auto_20170713_0649.py create mode 100644 pyBuchaktion/templates/pyBuchaktion/admin/import.html create mode 100644 pyBuchaktion/templates/pyBuchaktion/module_base.html create mode 100644 pyBuchaktion/templates/pyBuchaktion/module_literature_create.html create mode 100644 pyBuchaktion/templates/pyBuchaktion/tags/grid_books.html create mode 100644 pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html create mode 100644 pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html diff --git a/pyBuchaktion/admin.py b/pyBuchaktion/admin.py index 4431f54..c23daf3 100644 --- a/pyBuchaktion/admin.py +++ b/pyBuchaktion/admin.py @@ -4,6 +4,8 @@ and filters for the list view. """ +import re + from django.contrib.admin import ModelAdmin, register, helpers from django.db.models import Count from django.db.models.query import Prefetch @@ -76,6 +78,12 @@ class BookAdmin(ImportExportMixin, ModelAdmin): 'accept_selected', ] + fieldsets = [ + ("", { + 'fields': (('title',), ('author',), ('publisher', 'year'), ('isbn_13', 'price', 'state'), ('note',)) + }), + ] + # Annotate the queryset with the number of orders. def get_queryset(self, request): qs = super().get_queryset(request) @@ -161,6 +169,15 @@ class OrderAdmin(ImportExportMixin, ModelAdmin): "reject_selected", ] + fieldsets = ( + (_('General'), { + 'fields': (('book',), ('student',), ('status', 'order_timeframe')) + }), + (_('Details'), { + 'fields': (('hint',),) + }), + ) + # The title of the book to be ordered def book_title(self, order): return order.book.title @@ -301,6 +318,12 @@ class StudentAdmin(ModelAdmin): 'tuid_user', ) + fieldsets = [ + ("", { + 'fields': (('tuid_user', 'email'), ('library_id','language')) + }), + ] + # Annotate the queryset with the number of orders. def get_queryset(self, request): qs = super().get_queryset(request) @@ -358,6 +381,12 @@ class OrderTimeframeAdmin(ModelAdmin): 'semester', ) + fieldsets = [ + ("", { + 'fields': (('semester',), ('start_date', 'end_date'), ('allowed_orders', 'spendings')) + }), + ] + @register(Semester) class SemesterAdmin(ModelAdmin): @@ -366,14 +395,32 @@ class SemesterAdmin(ModelAdmin): The admin for a semester. """ + fieldsets = [ + ("", { + 'fields': (('season','year'), ('budget',)) + }), + ] + #radio_fields = {"season": admin.VERTICAL} pass +SEMESTER_REGEX = re.compile("(W|S)(\d*)") + +class SemesterWidget(Widget): + + def clean(self, value, row=None, *args, **kwargs): + match = SEMESTER_REGEX.match(value) + get_args = {'season': match.groups()[0], 'year': match.groups()[1]} + return Semester.objects.get(**get_args) + + def render(self, value, obj=None): + return "{0}{1}".format(value.season, value.year) + class TUCaNLiteratureWidget(ManyToManyWidget): def __init__(self): - super().__init__(Book, separator = '|', field = 'isbn_13') + super().__init__(Book, separator = ', ', field = 'isbn_13') class TUCaNLiteratureField(Field): @@ -383,17 +430,25 @@ def __init__(self): def save(self, obj, data): ids = [] for book in self.clean(data): - literature, created = Literature.objects.get_or_create( - book=book, module=obj, source=Literature.TUCAN, - ) - ids.append(literature.pk) + try: + literature_info = Literature.objects.get(book=book, module=obj) + if not literature_info.in_tucan: + literature_info.update(in_tucan=True) + except Literature.DoesNotExist: + literature_info = Literature.objects.create( + book=book, module=module, source=Literature.TUCAN, in_tucan=True + ) + ids.append(literature_info.pk) obj.refresh_from_db(fields=['literature',]) - Literature.objects.filter(source=Literature.TUCAN, module=obj).exclude(pk__in=ids).delete() + + literature = Literature.objects.filter(module=obj).exclude(pk__in=ids) + literature.filter(source=Literature.TUCAN).delete() + literature.filter(in_tucan=True).update(in_tucan=False) def get_value(self, obj): return Book.objects.filter( literature_info__module=obj, - literature_info__source__in=[Literature.TUCAN, Literature.STAFF], + literature_info__in_tucan=True, ) @@ -407,7 +462,7 @@ def get_queryset(self): books = TUCaNLiteratureField() category = Field( - column_name = 'category__name_de', + column_name = 'category', attribute = 'category', widget = ForeignKeyWidget( ModuleCategory, @@ -415,17 +470,22 @@ def get_queryset(self): ), ) + last_offered = Field( + column_name = 'last_offered', + attribute = 'last_offered', + widget = SemesterWidget() + ) + class Meta: model = Module import_id_fields = ( 'module_id', - 'last_offered__year', - 'last_offered__season', ) fields = import_id_fields + ( 'name_de', 'name_en', 'category', + 'last_offered', 'books', ) @@ -438,10 +498,11 @@ class ModuleAdmin(ImportExportMixin, ModelAdmin): """ resource_class = ModuleResource + import_template_name = 'pyBuchaktion/admin/import.html' list_display = ( - 'name_de', - 'name_en', + 'name_de_short', + 'name_en_short', 'module_id', 'category', ) @@ -456,6 +517,22 @@ class ModuleAdmin(ImportExportMixin, ModelAdmin): 'category', ) + fieldsets = [ + ("", { + 'fields': (('name_de','name_en'), ('module_id', 'category'), ('last_offered')) + }), + ] + + def name_de_short(self, obj): + return Truncator(obj.name_de).chars(30) + name_de_short.short_description = _("german name") + name_de_short.admin_order_field = 'name_de' + + def name_en_short(self, obj): + return Truncator(obj.name_en).chars(30) + name_en_short.short_description = _("english name") + name_en_short.admin_order_field = 'name_en' + @register(Literature) class LiteratureAdmin(ModelAdmin): @@ -477,6 +554,12 @@ def get_queryset(self, request): 'source', ) + fieldsets = [ + ("", { + 'fields': (('module',), ('book',), ('source', 'in_tucan', 'active')) + }), + ] + def title(self, obj): return Truncator(obj.book.title).chars(50) title.short_description = _("title") @@ -505,6 +588,7 @@ class ModuleCategoryAdmin(ImportExportMixin, ModelAdmin): 'id', 'name_de', 'name_en', + 'visible', ) list_display_links = ( @@ -512,9 +596,12 @@ class ModuleCategoryAdmin(ImportExportMixin, ModelAdmin): ) fieldsets = ( - ('Namen', { + (_('Names'), { 'fields': (('name_de', 'name_en'),) }), + (_('Settings'), { + 'fields': (('visible',),) + }), ) @@ -544,6 +631,12 @@ class DisplayMessageAdmin(ImportExportMixin, ModelAdmin): 'trunc_en', ) + fieldsets = ( + ("", { + 'fields': (('key'), ('text_de','text_en')) + }), + ) + def trunc_de(self, obj): return Truncator(obj.text_de).chars(60) trunc_de.short_description = _("german text") diff --git a/pyBuchaktion/forms.py b/pyBuchaktion/forms.py index bfbd299..39519a4 100644 --- a/pyBuchaktion/forms.py +++ b/pyBuchaktion/forms.py @@ -6,7 +6,7 @@ from django.http.request import QueryDict from django.db.models import Sum -from .models import Student, Order, Book, OrderTimeframe +from .models import Student, Order, Book, OrderTimeframe, Literature class BookOrderForm(forms.ModelForm): class Meta: @@ -39,6 +39,25 @@ def clean(self): raise ValidationError(_("You may not order any more books in this timeframe."), code='no_budget_left') +class LiteratureCreateForm(forms.ModelForm): + class Meta: + model = Literature + fields = ['book'] + + def clean(self): + cleaned_data = super().clean() + literature = self.instance + + book = cleaned_data['book'] + + # if book.state != Book.ACCEPTED: + # raise ValidationError({'book':_("This book has not been accepted yet")}, code='not_accepted') + + if Literature.objects.filter(module=literature.module, book=book).count() > 0: + raise ValidationError({'book':_("This book is already proposed for this module")}, code='exists') + + return cleaned_data + class BookSearchForm(forms.Form): title = forms.CharField(label=_("Title"), max_length=100, required=False) diff --git a/pyBuchaktion/locale/de/LC_MESSAGES/django.po b/pyBuchaktion/locale/de/LC_MESSAGES/django.po index ecd3303..197225b 100644 --- a/pyBuchaktion/locale/de/LC_MESSAGES/django.po +++ b/pyBuchaktion/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: pyBuchaktion\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-05 23:00+0200\n" -"PO-Revision-Date: 2017-06-05 23:03+0100\n" +"POT-Creation-Date: 2017-08-04 16:07+0200\n" +"PO-Revision-Date: 2017-08-04 16:08+0100\n" "Last-Translator: Daniel Schweighöfer \n" "Language-Team: UA Buchaktion \n" "Language: de\n" @@ -18,206 +18,256 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.6.10\n" -#: admin.py:89 +#: pyBuchaktion/admin.py:98 msgid "# ord." msgstr "# Best." -#: admin.py:94 +#: pyBuchaktion/admin.py:103 msgid "Accept selected books" msgstr "Ausgewählte Bücher akzeptieren" -#: admin.py:99 admin.py:167 models.py:48 +#: pyBuchaktion/admin.py:108 pyBuchaktion/admin.py:185 +#: pyBuchaktion/admin.py:565 pyBuchaktion/models.py:48 msgid "title" msgstr "Titel" -#: admin.py:104 models.py:79 +#: pyBuchaktion/admin.py:113 pyBuchaktion/models.py:79 msgid "author" msgstr "Autor" -#: admin.py:109 forms.py:46 mail.py:80 -#: templates/pyBuchaktion/tags/dlist_book.html:7 -#: templates/pyBuchaktion/tags/table_book.html:7 -#: templates/pyBuchaktion/tags/table_books.html:7 -#: templates/pyBuchaktion/tags/table_orders.html:8 +#: pyBuchaktion/admin.py:118 pyBuchaktion/forms.py:65 pyBuchaktion/mail.py:80 +#: pyBuchaktion/templates/pyBuchaktion/tags/dlist_book.html:7 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html:7 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_book.html:7 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_books.html:7 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_orders.html:8 msgid "ISBN-13" msgstr "ISBN-13" -#: admin.py:171 admin.py:172 models.py:387 models.py:388 +#: pyBuchaktion/admin.py:173 +msgid "General" +msgstr "" + +#: pyBuchaktion/admin.py:176 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html:29 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html:29 +msgid "Details" +msgstr "Details" + +#: pyBuchaktion/admin.py:189 pyBuchaktion/admin.py:190 +#: pyBuchaktion/models.py:387 pyBuchaktion/models.py:388 msgid "{:%Y-%m-%d}" msgstr "{:%d.%m.%Y}" -#: admin.py:173 +#: pyBuchaktion/admin.py:191 #, python-format msgid "%(start)s to %(end)s" msgstr "%(start)s bis %(end)s" -#: admin.py:175 models.py:215 models.py:401 +#: pyBuchaktion/admin.py:193 pyBuchaktion/models.py:215 +#: pyBuchaktion/models.py:401 msgid "order timeframe" msgstr "Bestellzeitraum" -#: admin.py:183 +#: pyBuchaktion/admin.py:201 msgid "Export orders to custom CSV" msgstr "Exportiere Bestellungen als CSV" -#: admin.py:200 +#: pyBuchaktion/admin.py:218 msgid "Rejecting orders: Are you sure?" msgstr "Bestellungen ablehnen: Bist du sicher?" -#: admin.py:201 +#: pyBuchaktion/admin.py:219 msgid "The follwing orders will be rejected. Are you sure?" msgstr "Die folgenden Bestellungen werden abgelehnt. Bist du sicher?" -#: admin.py:209 +#: pyBuchaktion/admin.py:227 msgid "reject selected orders" msgstr "Ausgewählte Bestellungen ablehnen" -#: admin.py:226 +#: pyBuchaktion/admin.py:244 msgid "Marking as arrived: Are you sure?" msgstr "Als angekommen markieren: Bist du sicher?" -#: admin.py:227 +#: pyBuchaktion/admin.py:245 msgid "" "The follwing orders will be marked as having been delivered. Are you sure?" msgstr "" "Die folgenden Bestellungen werden als angekommen markiert. Bist du sicher?" -#: admin.py:235 +#: pyBuchaktion/admin.py:253 msgid "mark selected orders as arrived" msgstr "Ausgewählte Bestellungen als Angekommen markieren" -#: admin.py:251 +#: pyBuchaktion/admin.py:269 msgid "Ordering: CSV-Export" msgstr "Bestellen: CSV-Export" -#: admin.py:262 +#: pyBuchaktion/admin.py:280 msgid "Ordering: Are you sure?" msgstr "Bestellen: Bist du sicher?" -#: admin.py:263 +#: pyBuchaktion/admin.py:281 msgid "The following orders will be marked as ordered. Are you sure?" msgstr "" "Die folgenden Bestellungen werden als bestellt markiert. Bist du sicher?" -#: admin.py:271 +#: pyBuchaktion/admin.py:289 msgid "order selected orders" msgstr "Ausgewählte Bestellungen bestellen" -#: admin.py:314 models.py:231 +#: pyBuchaktion/admin.py:338 pyBuchaktion/models.py:231 msgid "orders" msgstr "Bestellungen" -#: admin.py:319 models.py:258 +#: pyBuchaktion/admin.py:343 pyBuchaktion/models.py:258 msgid "library id" msgstr "Büchereinummer" -#: admin.py:333 +#: pyBuchaktion/admin.py:357 msgid "Send notification email" msgstr "Hinweis-Nachricht senden" -#: admin.py:334 +#: pyBuchaktion/admin.py:358 msgid "" "Write a custom notification here, which will be sent to all selected students" msgstr "" "Gebe eine beliebige Nachricht ein, die an alle ausgewählten Studenten " "gesendet werden soll" -#: admin.py:342 +#: pyBuchaktion/admin.py:366 msgid "send mail to students" msgstr "Ausgewählten Studenten eine E-Mail senden" -#: admin.py:495 models.py:539 +#: pyBuchaktion/admin.py:528 pyBuchaktion/models.py:480 +#: pyBuchaktion/models.py:555 +msgid "german name" +msgstr "deutscher Name" + +#: pyBuchaktion/admin.py:533 pyBuchaktion/models.py:483 +#: pyBuchaktion/models.py:558 +msgid "english name" +msgstr "englischer Name" + +#: pyBuchaktion/admin.py:569 pyBuchaktion/models.py:508 +#: pyBuchaktion/models.py:514 +msgid "module" +msgstr "Modul" + +#: pyBuchaktion/admin.py:599 +msgid "Names" +msgstr "Namen" + +#: pyBuchaktion/admin.py:602 +msgid "Settings" +msgstr "Einstellungen" + +#: pyBuchaktion/admin.py:642 pyBuchaktion/models.py:581 msgid "german text" msgstr "deutscher Text" -#: admin.py:499 models.py:542 +#: pyBuchaktion/admin.py:646 pyBuchaktion/models.py:584 msgid "english text" msgstr "englischer Text" -#: cms_apps.py:9 +#: pyBuchaktion/cms_apps.py:9 msgid "pyBuchaktion" msgstr "" -#: cms_menus.py:10 +#: pyBuchaktion/cms_menus.py:10 msgid "Buchaktion Menu" msgstr "Buchaktionsmenü" -#: cms_menus.py:15 templates/pyBuchaktion/books/base.html:12 +#: pyBuchaktion/cms_menus.py:15 +#: pyBuchaktion/templates/pyBuchaktion/books/base.html:12 msgid "Books" msgstr "Bücher" -#: cms_menus.py:16 +#: pyBuchaktion/cms_menus.py:16 msgid "All Books" msgstr "Alle Bücher" -#: cms_menus.py:17 templates/pyBuchaktion/module_list.html:9 +#: pyBuchaktion/cms_menus.py:17 +#: pyBuchaktion/templates/pyBuchaktion/module_list.html:9 msgid "Modules" msgstr "Module" -#: cms_menus.py:18 templates/pyBuchaktion/search_base.html:10 -#: templates/pyBuchaktion/search_base.html:15 +#: pyBuchaktion/cms_menus.py:18 +#: pyBuchaktion/templates/pyBuchaktion/search_base.html:10 +#: pyBuchaktion/templates/pyBuchaktion/search_base.html:15 msgid "Search" msgstr "Suchen" -#: cms_menus.py:21 +#: pyBuchaktion/cms_menus.py:21 msgid "Account" msgstr "Account" -#: cms_menus.py:26 templates/pyBuchaktion/book_propose.html:16 +#: pyBuchaktion/cms_menus.py:26 +#: pyBuchaktion/templates/pyBuchaktion/book_propose.html:16 msgid "Propose" msgstr "Vorschlagen" -#: cms_menus.py:43 +#: pyBuchaktion/cms_menus.py:43 msgid "Order book" msgstr "Buch bestellen" -#: cms_menus.py:66 +#: pyBuchaktion/cms_menus.py:66 #, python-format msgid "Order #%s" msgstr "Bestellung #%s" -#: forms.py:23 +#: pyBuchaktion/forms.py:23 msgid "This book is not available for ordering" msgstr "Dieses Buch kann nicht bestellt werden" -#: forms.py:31 messages.py:9 +#: pyBuchaktion/forms.py:31 pyBuchaktion/messages.py:9 msgid "Book ordering is not active for the current date" msgstr "Buchbestellungen sind für das aktuelle Datum nicht aktiviert." -#: forms.py:39 +#: pyBuchaktion/forms.py:39 msgid "You may not order any more books in this timeframe." msgstr "Sie können in diesem Zeitrahmen keine Bücher mehr bestellen." -#: forms.py:44 mail.py:77 templates/pyBuchaktion/tags/table_orders.html:6 +#: pyBuchaktion/forms.py:57 +msgid "This book is already proposed for this module" +msgstr "Dieses Buch ist für dieses Modul bereits vorgeschlagen" + +#: pyBuchaktion/forms.py:63 pyBuchaktion/mail.py:77 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_orders.html:6 msgid "Title" msgstr "Titel" -#: forms.py:45 mail.py:78 templates/pyBuchaktion/tags/dlist_book.html:3 -#: templates/pyBuchaktion/tags/table_book.html:5 -#: templates/pyBuchaktion/tags/table_books.html:6 -#: templates/pyBuchaktion/tags/table_orders.html:7 +#: pyBuchaktion/forms.py:64 pyBuchaktion/mail.py:78 +#: pyBuchaktion/templates/pyBuchaktion/tags/dlist_book.html:3 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html:4 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_book.html:5 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_books.html:6 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_orders.html:7 msgid "Author" msgstr "Autor" -#: forms.py:47 templates/pyBuchaktion/tags/dlist_book.html:5 -#: templates/pyBuchaktion/tags/table_book.html:6 -#: templates/pyBuchaktion/tags/table_books.html:8 +#: pyBuchaktion/forms.py:66 +#: pyBuchaktion/templates/pyBuchaktion/tags/dlist_book.html:5 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html:10 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_book.html:6 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_books.html:8 msgid "Publisher" msgstr "Verlag" -#: forms.py:62 +#: pyBuchaktion/forms.py:81 msgid "Book proposal is not active for the current date." msgstr "Buchvorschläge sind für das aktuelle Datum nicht aktiviert." -#: forms.py:70 +#: pyBuchaktion/forms.py:89 msgid "You may not order or propose any more books in this timeframe." msgstr "" "Sie können in diesem Zeitrahmen keine Bücher mehr bestellen oder vorschlagen." -#: forms.py:76 +#: pyBuchaktion/forms.py:95 msgid "Name" msgstr "Name" -#: forms.py:85 +#: pyBuchaktion/forms.py:104 msgid "" "The library id number assigned by the ULB, required for if you want the book " "to be reserved for you" @@ -225,40 +275,41 @@ msgstr "" "Die von der ULB zugeordnete Büchereinummer. Notwendig, wenn das bestellte " "Buch auf deinen Namen zur Ausleihe vorgemerkt werden soll" -#: forms.py:86 +#: pyBuchaktion/forms.py:105 msgid "The preferred language for notification emails" msgstr "Bevorzugte Sprache für Hinweis-Nachrichten" -#: forms.py:87 +#: pyBuchaktion/forms.py:106 msgid "The e-mail address to recieve status updates" msgstr "E-Mail um Hinweise über Statusänderungen zu empfangen" -#: mail.py:11 +#: pyBuchaktion/mail.py:11 msgid "This message does not have any content" msgstr "Diese Nachricht enthält keinen Inhalt" -#: mail.py:21 +#: pyBuchaktion/mail.py:21 #, python-brace-format msgid "Dear {0}" msgstr "Hallo {0}" -#: mail.py:24 +#: pyBuchaktion/mail.py:24 msgid "The Buchaktion Team" msgstr "Das Buchaktions Team" -#: mail.py:79 +#: pyBuchaktion/mail.py:79 msgid "Published" msgstr "Erschienen" -#: mail.py:86 templates/pyBuchaktion/order_detail.html:17 +#: pyBuchaktion/mail.py:86 +#: pyBuchaktion/templates/pyBuchaktion/order_detail.html:17 msgid "Hint" msgstr "Hinweis" -#: mail.py:90 +#: pyBuchaktion/mail.py:90 msgid "View Order" msgstr "Bestellung ansehen" -#: mail.py:102 +#: pyBuchaktion/mail.py:102 msgid "" "Your order for the book below has been accepted and forwarded to our book " "retailer. We will inform you when it has arrived at the university library." @@ -267,11 +318,11 @@ msgstr "" "weitergeleitet. Wir werden dich informieren, wenn es in der " "Universitätsbibliothek angekommen ist." -#: mail.py:106 +#: pyBuchaktion/mail.py:106 msgid "Order accepted" msgstr "Bestellung angenommen" -#: mail.py:112 +#: pyBuchaktion/mail.py:112 msgid "" "Your order for the book below has been rejected. Additional information may " "be provided in the hint below." @@ -279,11 +330,11 @@ msgstr "" "Deine Bestellung für dieses Buch wurde abgelehnt. Zusätzliche Informationen " "können im Hinweis weiter unten stehen." -#: mail.py:116 +#: pyBuchaktion/mail.py:116 msgid "Order rejected" msgstr "Bestellung abgelehnt" -#: mail.py:122 +#: pyBuchaktion/mail.py:122 msgid "" "Your ordered book has arrived at the university library. Please pick it up " "within the next week." @@ -291,11 +342,11 @@ msgstr "" "Dein bestelltes Buch ist in der Universitätsbibliothek angekommen. Bitte hol " "es innerhalb der nächsten Woche ab." -#: mail.py:126 +#: pyBuchaktion/mail.py:126 msgid "Order arrived" msgstr "Bestellung angekommen" -#: messages.py:7 +#: pyBuchaktion/messages.py:7 msgid "" "This list contains all modules for which books are available for ordering " "through this system." @@ -303,7 +354,7 @@ msgstr "" "Diese Liste enthält alle Module, für die mit diesem System Bücher bestellt " "werden können." -#: messages.py:8 +#: pyBuchaktion/messages.py:8 #, python-brace-format msgid "" "If you order now, the order will be posted to our merchant by {date}." @@ -311,7 +362,7 @@ msgstr "" "Der voraussichtliche Termin für Bestellung bei unserem Händler ist der " "{date}" -#: messages.py:11 +#: pyBuchaktion/messages.py:11 msgid "" "You may use this form to propose a book to us. This will automatically " "generate an order for that book for the current timeframe, helping us keep " @@ -327,7 +378,7 @@ msgstr "" "wieder zurückgezogen werden und damit deinen Anteil am Buchvorschlag " "zurücknehmen." -#: messages.py:15 +#: pyBuchaktion/messages.py:15 msgid "" "This order is associated with a proposed book. Until the book is confirmed, " "it will not be proceeded with. In any case, this order expresses your " @@ -338,7 +389,7 @@ msgstr "" "drückt die Bestellung Interesse an dem Buch aus, was die Wahrscheinlichkeit " "erhöht, dass es bestätigt wird." -#: messages.py:18 +#: pyBuchaktion/messages.py:18 #, python-brace-format msgid "" "This order is marked to be ordered from our book retailer on {date}." @@ -346,7 +397,7 @@ msgstr "" "Diese Bestellung ist für den {date} zur Weitergabe an unseren Händler " "vorgemerkt." -#: messages.py:19 +#: pyBuchaktion/messages.py:19 #, python-brace-format msgid "" "Below, you find the list of your orders. The current order timeframe is from " @@ -357,31 +408,31 @@ msgstr "" "ist vom {start_date} bis zum {end_date}. Du hast momentan " "{budget_spent} von {budget_max} erlaubte Bestellungen aufgegeben." -#: messages.py:22 +#: pyBuchaktion/messages.py:22 msgid "No orders found!" msgstr "Keine Bestellungen gefunden!" -#: messages.py:23 +#: pyBuchaktion/messages.py:23 msgid "You have not ordered any books!" msgstr "Du hast keine Bücher bestellt!" -#: messages.py:24 +#: pyBuchaktion/messages.py:24 msgid "" -"It seems that this module does not have any literature associated with it." +"It seems that this module does not have much literature associated with it." msgstr "" -"Es scheint so, als ob zu diesem Modul keine Buchvorschläge vorhanden sind." +"Es scheint so, als ob zu diesem Modul kaum Buchvorschläge vorhanden sind." -#: messages.py:25 +#: pyBuchaktion/messages.py:25 msgid "This book has been rejected, and may not be ordered" msgstr "Dieses Buch wurde abgelehnt, und kann nicht bestellt werden" -#: messages.py:26 +#: pyBuchaktion/messages.py:26 msgid "This book has been proposed, but has yet to be confirmed by our team." msgstr "" "Dieses Buch wurde vorgeschlagen, muss aber erst von unserem Team bestätigt " "werden." -#: messages.py:27 +#: pyBuchaktion/messages.py:27 msgid "" "This book has been marked obsolete, a new version is available. It may not " "be ordered" @@ -389,18 +440,22 @@ msgstr "" "Dieses Buch ist als veraltet gekennzeichnet, eine neuere Version ist " "verfügbar. Es kann nicht bestellt werden." -#: messages.py:28 +#: pyBuchaktion/messages.py:28 msgid "You have not ordered this book" msgstr "Du hast dieses Buch nicht bestellt" -#: messages.py:29 +#: pyBuchaktion/messages.py:29 msgid "" "Orders for proposed books will be proceeded with once the book is confirmed." msgstr "" "Bestellungen für vorgeschlagene Bücher werden bearbeitet sobald das Buch " "bestätigt ist." -#: mixins.py:18 +#: pyBuchaktion/messages.py:30 +msgid "At the moment, no orders may be posted!" +msgstr "Momentan dürfen keine Bestellungen aufgegeben werden!" + +#: pyBuchaktion/mixins.py:18 msgid "" "This feature is only available for students at the department of computer " "science! (dept. 20)" @@ -408,271 +463,291 @@ msgstr "" "Diese Funktion steht nur Studenten des Fachbereich Informatik (FB20) zur " "Verfügung!" -#: models.py:62 +#: pyBuchaktion/models.py:62 msgid "Accepted" msgstr "Akzeptiert" -#: models.py:63 models.py:179 +#: pyBuchaktion/models.py:63 pyBuchaktion/models.py:179 msgid "Rejected" msgstr "Abgelehnt" -#: models.py:64 +#: pyBuchaktion/models.py:64 msgid "Proposed" msgstr "Vorgeschlagen" -#: models.py:65 +#: pyBuchaktion/models.py:65 msgid "Obsolete" msgstr "Veraltet" -#: models.py:73 models.py:188 +#: pyBuchaktion/models.py:73 pyBuchaktion/models.py:188 msgid "status" msgstr "Status" -#: models.py:87 +#: pyBuchaktion/models.py:87 msgid "price" msgstr "Preis" -#: models.py:92 +#: pyBuchaktion/models.py:92 msgid "publisher" msgstr "Verlag" -#: models.py:96 models.py:435 +#: pyBuchaktion/models.py:96 pyBuchaktion/models.py:435 msgid "year" msgstr "Jahr" -#: models.py:100 models.py:193 +#: pyBuchaktion/models.py:100 pyBuchaktion/models.py:193 msgid "hint" msgstr "Hinweis" -#: models.py:122 models.py:201 +#: pyBuchaktion/models.py:122 pyBuchaktion/models.py:201 +#: pyBuchaktion/models.py:515 msgid "book" msgstr "Buch" -#: models.py:123 +#: pyBuchaktion/models.py:123 msgid "books" msgstr "Bücher" -#: models.py:177 +#: pyBuchaktion/models.py:177 msgid "Pending" msgstr "Offen" -#: models.py:178 templates/pyBuchaktion/tags/table_row_book.html:11 +#: pyBuchaktion/models.py:178 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html:13 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html:12 msgid "Ordered" msgstr "Bestellt" -#: models.py:180 +#: pyBuchaktion/models.py:180 msgid "Arrived" msgstr "Angekommen" -#: models.py:208 models.py:304 +#: pyBuchaktion/models.py:208 pyBuchaktion/models.py:304 msgid "student" msgstr "Student" -#: models.py:225 +#: pyBuchaktion/models.py:225 msgid "proposal" msgstr "Vorschlag" -#: models.py:230 +#: pyBuchaktion/models.py:230 msgid "order" msgstr "Bestellung" -#: models.py:267 +#: pyBuchaktion/models.py:267 msgid "TUID User" msgstr "TUID Benutzer" -#: models.py:271 +#: pyBuchaktion/models.py:271 msgid "email" msgstr "E-Mail" -#: models.py:280 +#: pyBuchaktion/models.py:280 msgid "Not selected" msgstr "Nicht gesetzt" -#: models.py:281 +#: pyBuchaktion/models.py:281 msgid "German" msgstr "Deutsch" -#: models.py:282 +#: pyBuchaktion/models.py:282 msgid "English" msgstr "Englisch" -#: models.py:290 +#: pyBuchaktion/models.py:290 msgid "preferred language" msgstr "bevorzugte Sprache" -#: models.py:305 +#: pyBuchaktion/models.py:305 msgid "students" msgstr "Studenten" -#: models.py:357 +#: pyBuchaktion/models.py:357 msgid "start date" msgstr "Startdatum" -#: models.py:362 +#: pyBuchaktion/models.py:362 msgid "end date" msgstr "Enddatum" -#: models.py:368 +#: pyBuchaktion/models.py:368 msgid "allowed orders" msgstr "Erlaubte Bestellungen" -#: models.py:375 +#: pyBuchaktion/models.py:375 msgid "spendings" msgstr "Ausgaben" -#: models.py:382 models.py:462 +#: pyBuchaktion/models.py:382 pyBuchaktion/models.py:462 msgid "semester" msgstr "Semester" -#: models.py:389 +#: pyBuchaktion/models.py:389 #, python-format msgid "%(start)s to %(end)s (%(semester)s)" msgstr "%(start)s bis %(end)s (%(semester)s)" -#: models.py:402 +#: pyBuchaktion/models.py:402 msgid "order timeframes" msgstr "Bestellzeiträume" -#: models.py:419 +#: pyBuchaktion/models.py:419 msgid "Winter term" msgstr "Wintersemester" -#: models.py:420 +#: pyBuchaktion/models.py:420 msgid "Summer term" msgstr "Sommersemester" -#: models.py:428 +#: pyBuchaktion/models.py:428 msgid "season" msgstr "Saison" -#: models.py:442 +#: pyBuchaktion/models.py:442 msgid "budget" msgstr "Budget" -#: models.py:448 +#: pyBuchaktion/models.py:448 #, python-format msgid "Winter term 20%(year)d/%(next_year)d" msgstr "Wintersemester 20%(year)d/%(next_year)d" -#: models.py:452 +#: pyBuchaktion/models.py:452 #, python-format msgid "Summer term 20%(year)d" msgstr "Sommersemester 20%(year)d" -#: models.py:463 +#: pyBuchaktion/models.py:463 msgid "semesters" msgstr "Semester" -#: models.py:477 +#: pyBuchaktion/models.py:477 msgid "module id" msgstr "Modul ID" -#: models.py:480 models.py:516 -msgid "german name" -msgstr "deutscher Name" - -#: models.py:483 models.py:519 -msgid "english name" -msgstr "englischer Name" - -#: models.py:486 +#: pyBuchaktion/models.py:486 msgid "last offered" msgstr "Zuletzt angeboten" -#: models.py:489 +#: pyBuchaktion/models.py:489 pyBuchaktion/models.py:548 +#: pyBuchaktion/models.py:549 msgid "literature" msgstr "Literatur" -#: models.py:492 +#: pyBuchaktion/models.py:492 msgid "category" msgstr "Kategorie" -#: models.py:508 -msgid "module" -msgstr "Modul" - -#: models.py:509 +#: pyBuchaktion/models.py:509 msgid "modules" msgstr "Module" -#: models.py:529 +#: pyBuchaktion/models.py:523 +msgid "TUCaN Export" +msgstr "TUCaN Export" + +#: pyBuchaktion/models.py:524 +msgid "Module Staff" +msgstr "Veranstalter" + +#: pyBuchaktion/models.py:525 +msgid "Student" +msgstr "Student" + +#: pyBuchaktion/models.py:533 +msgid "source" +msgstr "Quelle" + +#: pyBuchaktion/models.py:538 +msgid "in TUCaN" +msgstr "In TUCaN" + +#: pyBuchaktion/models.py:543 +msgid "active" +msgstr "aktiv" + +#: pyBuchaktion/models.py:561 +msgid "visible" +msgstr "sichtbar" + +#: pyBuchaktion/models.py:571 msgid "module category" msgstr "Modulkategorie" -#: models.py:530 +#: pyBuchaktion/models.py:572 msgid "module categories" msgstr "Modulkategorien" -#: models.py:536 +#: pyBuchaktion/models.py:578 msgid "key" msgstr "Schlüssel" -#: models.py:551 +#: pyBuchaktion/models.py:593 msgid "display message" msgstr "Anzeigenachricht" -#: models.py:552 +#: pyBuchaktion/models.py:594 msgid "display messages" msgstr "Anzeigenachrichten" -#: templates/bootstrap/pagination.html:4 +#: pyBuchaktion/templates/bootstrap/pagination.html:4 msgid "Page Navigation" msgstr "Seitennavigation" -#: templates/bootstrap/pagination.html:7 +#: pyBuchaktion/templates/bootstrap/pagination.html:7 msgid "Previous Page" msgstr "Vorherige Seite" -#: templates/bootstrap/pagination.html:22 +#: pyBuchaktion/templates/bootstrap/pagination.html:22 msgid "Page" msgstr "Seite" -#: templates/bootstrap/pagination.html:22 +#: pyBuchaktion/templates/bootstrap/pagination.html:22 msgid "of" msgstr "von" -#: templates/bootstrap/pagination.html:27 +#: pyBuchaktion/templates/bootstrap/pagination.html:27 msgid "Next Page" msgstr "Nächste Seite" -#: templates/pyBuchaktion/account.html:17 +#: pyBuchaktion/templates/pyBuchaktion/account.html:17 msgid "Update" msgstr "Speichern" -#: templates/pyBuchaktion/account.html:22 +#: pyBuchaktion/templates/pyBuchaktion/account.html:22 msgid "Logout" msgstr "Abmelden" -#: templates/pyBuchaktion/account.html:24 +#: pyBuchaktion/templates/pyBuchaktion/account.html:24 msgid "Logout & CAS Logout" msgstr "Abmelden & aus CAS abmelden" -#: templates/pyBuchaktion/account.html:31 -#: templates/pyBuchaktion/book_detail.html:24 +#: pyBuchaktion/templates/pyBuchaktion/account.html:31 +#: pyBuchaktion/templates/pyBuchaktion/book_detail.html:24 msgid "Orders" msgstr "Bestellungen" -#: templates/pyBuchaktion/account_create.html:7 +#: pyBuchaktion/templates/pyBuchaktion/account_create.html:7 msgid "Registration for the Buchaktion" msgstr "Anmeldung für die Buchaktion" -#: templates/pyBuchaktion/account_create.html:11 +#: pyBuchaktion/templates/pyBuchaktion/account_create.html:11 msgid "Currently logged in as" msgstr "Momentan angemeldet als" -#: templates/pyBuchaktion/account_create.html:16 +#: pyBuchaktion/templates/pyBuchaktion/account_create.html:16 msgid "Create" msgstr "Erstellen" -#: templates/pyBuchaktion/admin/admin_action_page.html:5 +#: pyBuchaktion/templates/pyBuchaktion/admin/admin_action_page.html:5 msgid "Home" msgstr "" -#: templates/pyBuchaktion/admin/order_modify_bulk.html:8 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_modify_bulk.html:8 msgid "You may provide an additional hint here for any relevant information." msgstr "Du kannst hier einen Hinweis mit zusätzlichen Informationen angeben." -#: templates/pyBuchaktion/admin/order_modify_bulk.html:10 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_modify_bulk.html:10 msgid "" "When the following box is checked, emails will be sent to notify students " "about the status of their order." @@ -680,70 +755,72 @@ msgstr "" "Wenn die nachfolgende Option ausgewählt wurde, werden Studenten über den " "Status ihrer Bestellung per E-Mail in informiert." -#: templates/pyBuchaktion/admin/order_modify_bulk.html:12 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_modify_bulk.html:12 msgid "Send notification emails" msgstr "Hinweis-Nachrichten senden" -#: templates/pyBuchaktion/admin/order_modify_bulk.html:18 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_modify_bulk.html:18 msgid "Yes, I'm sure" msgstr "Ja, ich bin sicher." -#: templates/pyBuchaktion/admin/order_modify_bulk.html:19 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_modify_bulk.html:19 msgid "No, cancel this." msgstr "Nein, abbrechen." -#: templates/pyBuchaktion/admin/order_order_selected_csv.html:6 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_order_selected_csv.html:6 msgid "Copy the following list into the bulk-order mask at net-library!" msgstr "" "Kopiere die folgende Liste in die Bulk-Order Oberfläche der net-library" -#: templates/pyBuchaktion/admin/order_order_selected_csv.html:14 +#: pyBuchaktion/templates/pyBuchaktion/admin/order_order_selected_csv.html:14 msgid "OK" msgstr "OK" -#: templates/pyBuchaktion/admin/student_sendmail.html:8 +#: pyBuchaktion/templates/pyBuchaktion/admin/student_sendmail.html:8 msgid "The mail will be sent to the following students" msgstr "Diese Mail wird an die folgenden Studenten versandt" -#: templates/pyBuchaktion/admin/student_sendmail.html:15 +#: pyBuchaktion/templates/pyBuchaktion/admin/student_sendmail.html:15 +#: pyBuchaktion/templates/pyBuchaktion/module_literature_create.html:14 msgid "Send" msgstr "Senden" -#: templates/pyBuchaktion/admin/student_sendmail.html:16 +#: pyBuchaktion/templates/pyBuchaktion/admin/student_sendmail.html:16 msgid "Cancel" msgstr "Abbrechen" -#: templates/pyBuchaktion/book_detail.html:9 +#: pyBuchaktion/templates/pyBuchaktion/book_detail.html:9 msgid "Recommended by" msgstr "Empfohlen von" -#: templates/pyBuchaktion/book_detail.html:35 +#: pyBuchaktion/templates/pyBuchaktion/book_detail.html:35 msgid "on" msgstr "am" -#: templates/pyBuchaktion/book_detail.html:48 -#: templates/pyBuchaktion/tags/table_row_book.html:15 +#: pyBuchaktion/templates/pyBuchaktion/book_detail.html:48 +#: pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html:17 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html:16 msgid "Order this book" msgstr "Dieses Buch bestellen" -#: templates/pyBuchaktion/book_order_form.html:8 +#: pyBuchaktion/templates/pyBuchaktion/book_order_form.html:8 msgid "Order" msgstr "Bestellung" -#: templates/pyBuchaktion/book_order_form.html:34 +#: pyBuchaktion/templates/pyBuchaktion/book_order_form.html:34 msgid "Post order" msgstr "Bestellung absenden" -#: templates/pyBuchaktion/book_propose.html:7 +#: pyBuchaktion/templates/pyBuchaktion/book_propose.html:7 msgid "Propose a book" msgstr "Buchvorschlag" -#: templates/pyBuchaktion/books/active_list.html:5 -#: templates/pyBuchaktion/books/all_list.html:7 +#: pyBuchaktion/templates/pyBuchaktion/books/active_list.html:5 +#: pyBuchaktion/templates/pyBuchaktion/books/all_list.html:7 msgid "Sorry, no books matching this query were found!" msgstr "Entschuldige, keine passenden Bücher wurden gefunden!" -#: templates/pyBuchaktion/books/active_list.html:6 +#: pyBuchaktion/templates/pyBuchaktion/books/active_list.html:6 msgid "" "The book you are searching for may have already been proposed, rejected or " "marked as obsolete. That means that this book cannot be ordered right now, " @@ -753,43 +830,51 @@ msgstr "" "Das gesuchte Buch wurde bereits vorgeschlagen, abgelehnt oder als " "veraltetgekennzeichnet. Damit kann dieses Buch nicht bestellt werden" -#: templates/pyBuchaktion/books/active_list.html:7 +#: pyBuchaktion/templates/pyBuchaktion/books/active_list.html:7 msgid "Full list" msgstr "Vollständige Liste" -#: templates/pyBuchaktion/books/all_list.html:11 +#: pyBuchaktion/templates/pyBuchaktion/books/all_list.html:11 msgid "If you want to propose this book to us, you can send an email to" msgstr "Wenn du dieses Buch vorschlagen möchtest, schreib uns eine E-Mail an" -#: templates/pyBuchaktion/books/base.html:4 +#: pyBuchaktion/templates/pyBuchaktion/books/base.html:4 msgid "Search for modules" msgstr "Suche nach Modulen" -#: templates/pyBuchaktion/module.html:11 +#: pyBuchaktion/templates/pyBuchaktion/module.html:9 +msgid "Literature" +msgstr "Literatur" + +#: pyBuchaktion/templates/pyBuchaktion/module.html:23 +msgid "Recommendations by other students" +msgstr "Empfehlungen von anderen Studierenden" + +#: pyBuchaktion/templates/pyBuchaktion/module_base.html:11 msgid "Module ID" msgstr "Modul ID" -#: templates/pyBuchaktion/module.html:13 +#: pyBuchaktion/templates/pyBuchaktion/module_base.html:13 msgid "Last offered" msgstr "Zuletzt angeboten" -#: templates/pyBuchaktion/module.html:15 +#: pyBuchaktion/templates/pyBuchaktion/module_base.html:15 msgid "Category" msgstr "Kategorie" -#: templates/pyBuchaktion/module.html:22 -msgid "Literature" -msgstr "Literatur" - -#: templates/pyBuchaktion/module_list.html:19 +#: pyBuchaktion/templates/pyBuchaktion/module_list.html:19 msgid "Sorry, no modules matching this query were found!" msgstr "Entschuldige, keine passenden Module wurden gefunden!" -#: templates/pyBuchaktion/modulecategory_list.html:9 +#: pyBuchaktion/templates/pyBuchaktion/module_literature_create.html:8 +msgid "Add student literature recommendation" +msgstr "Studentische Literaturempfehlung hinzufügen" + +#: pyBuchaktion/templates/pyBuchaktion/modulecategory_list.html:9 msgid "Miscellaneous" msgstr "Sonstiges" -#: templates/pyBuchaktion/order_abort.html:4 +#: pyBuchaktion/templates/pyBuchaktion/order_abort.html:4 msgid "" "You are about to abort the order for the book noted below. Do you really " "want to do that?" @@ -797,52 +882,48 @@ msgstr "" "Du bist dabei, die Bestellung für das unten genannte Buch abzubrechen. Bist " "du dir sicher?" -#: templates/pyBuchaktion/order_abort.html:11 +#: pyBuchaktion/templates/pyBuchaktion/order_abort.html:11 msgid "Yes, Abort the order" msgstr "Ja, Bestellung abbrechen" -#: templates/pyBuchaktion/order_abort.html:14 +#: pyBuchaktion/templates/pyBuchaktion/order_abort.html:14 msgid "No, keep the order" msgstr "Nein, Bestellung behalten" -#: templates/pyBuchaktion/order_detail.html:7 +#: pyBuchaktion/templates/pyBuchaktion/order_detail.html:7 msgid "Order #" msgstr "Bestellung #" -#: templates/pyBuchaktion/order_detail.html:28 +#: pyBuchaktion/templates/pyBuchaktion/order_detail.html:28 msgid "Abort order" msgstr "Bestellung abbrechen" -#: templates/pyBuchaktion/order_detail.html:36 +#: pyBuchaktion/templates/pyBuchaktion/order_detail.html:36 msgid "Book" msgstr "Buch" -#: templates/pyBuchaktion/tags/dlist_book.html:9 +#: pyBuchaktion/templates/pyBuchaktion/tags/dlist_book.html:9 msgid "Publication year" msgstr "Erscheinungsjahr" -#: templates/pyBuchaktion/tags/table_book.html:8 -#: templates/pyBuchaktion/tags/table_books.html:9 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_book.html:8 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_books.html:9 msgid "Year" msgstr "Jahr" -#: templates/pyBuchaktion/tags/table_orders.html:5 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_orders.html:5 msgid "ID" msgstr "ID" -#: templates/pyBuchaktion/tags/table_orders.html:9 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_orders.html:9 msgid "Order on" msgstr "Bestellung am" -#: templates/pyBuchaktion/tags/table_row_book.html:27 -msgid "Details" -msgstr "Details" - -#: templates/pyBuchaktion/tags/table_row_order.html:15 +#: pyBuchaktion/templates/pyBuchaktion/tags/table_row_order.html:15 msgid "View" msgstr "Ansehen" -#: templatetags/view_tools.py:35 +#: pyBuchaktion/templatetags/view_tools.py:35 msgid "" "This book is marked for, but has not yet been ordered from our merchant. " "Until then, the order can be aborted at any time. We'll inform you when we " @@ -852,7 +933,7 @@ msgstr "" "Bis dahin kann die Bestellung jederzeit storniert werden. Wir informieren " "dich wenn es endgültig bestellt oder abgelehnt wird." -#: templatetags/view_tools.py:38 +#: pyBuchaktion/templatetags/view_tools.py:38 msgid "" "This book has been ordered from our merchant. We'll inform you when it " "arrived." @@ -860,19 +941,22 @@ msgstr "" "Dieses Buch wurde bei unserem Händler bestellt, wir werden dich informieren " "wenn es angekommen ist" -#: templatetags/view_tools.py:39 +#: pyBuchaktion/templatetags/view_tools.py:39 msgid "This order has been rejected." msgstr "Diese Bestellung wurde abgelehnt." -#: templatetags/view_tools.py:40 +#: pyBuchaktion/templatetags/view_tools.py:40 msgid "The order was fulfilled, the book is now available." msgstr "Die Bestellung war erfolgreich, das Buch ist angekommen." -#: views.py:125 +#: pyBuchaktion/views.py:125 #, python-format msgid "No %(verbose_name)s found matching the query" msgstr "Kein(e) %(verbose_name)s zu dieser Suche gefunden" +#~ msgid "^book/" +#~ msgstr "^buch/" + #~ msgid "" #~ "This book has been proposed, but has yet to be confirmed by our team. " #~ "Orders may be posted but will not be proceeded with before confirmation. " diff --git a/pyBuchaktion/messages.py b/pyBuchaktion/messages.py index 22be205..8d64b0f 100644 --- a/pyBuchaktion/messages.py +++ b/pyBuchaktion/messages.py @@ -21,12 +21,13 @@ "of {budget_max} available orders posted."), 'orders_none_found': _("No orders found!"), 'account_no_orders': _("You have not ordered any books!"), - 'module_no_literature': _("It seems that this module does not have any literature associated with it."), + 'module_not_much_literature': _("It seems that this module does not have much literature associated with it."), 'book_state_RJ': _("This book has been rejected, and may not be ordered"), 'book_state_PP': _("This book has been proposed, but has yet to be confirmed by our team."), 'book_state_OL': _("This book has been marked obsolete, a new version is available. It may not be ordered"), 'book_not_ordered': _("You have not ordered this book"), 'order_proposed_book': _("Orders for proposed books will be proceeded with once the book is confirmed."), + 'account_orders_inactive': _("At the moment, no orders may be posted!"), } def get_message(key): @@ -45,6 +46,6 @@ def get_message(key): # When nothing was found, check for debug flag if BUCHAKTION_MESSAGES_DEBUG and message == None: - return '\\' + key + '\\' + return '[msg:' + key + ']' else: return "" diff --git a/pyBuchaktion/migrations/0014_auto_20170606_1829.py b/pyBuchaktion/migrations/0014_auto_20170606_1829.py new file mode 100644 index 0000000..4cfc7e9 --- /dev/null +++ b/pyBuchaktion/migrations/0014_auto_20170606_1829.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-06-06 16:29 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pyBuchaktion', '0013_remove_module_literature_save'), + ] + + operations = [ + migrations.AlterModelOptions( + name='literature', + options={'verbose_name': 'literature', 'verbose_name_plural': 'literature'}, + ), + migrations.AddField( + model_name='literature', + name='active', + field=models.BooleanField(default=True, verbose_name='active'), + ), + migrations.AddField( + model_name='literature', + name='in_tucan', + field=models.BooleanField(default=True, verbose_name='in TUCaN'), + ), + migrations.AlterUniqueTogether( + name='literature', + unique_together=set([('book', 'module')]), + ), + ] diff --git a/pyBuchaktion/migrations/0015_auto_20170713_0649.py b/pyBuchaktion/migrations/0015_auto_20170713_0649.py new file mode 100644 index 0000000..d71c026 --- /dev/null +++ b/pyBuchaktion/migrations/0015_auto_20170713_0649.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-07-13 04:49 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pyBuchaktion', '0014_auto_20170606_1829'), + ] + + operations = [ + migrations.AddField( + model_name='modulecategory', + name='visible', + field=models.BooleanField(default=True, verbose_name='visible'), + ), + migrations.AlterField( + model_name='literature', + name='book', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='literature_info', to='pyBuchaktion.Book', verbose_name='book'), + ), + migrations.AlterField( + model_name='literature', + name='module', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='literature_info', to='pyBuchaktion.Module', verbose_name='module'), + ), + ] diff --git a/pyBuchaktion/models.py b/pyBuchaktion/models.py index 16703e9..d14ce07 100644 --- a/pyBuchaktion/models.py +++ b/pyBuchaktion/models.py @@ -511,12 +511,12 @@ class Meta: class Literature(models.Model): - module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='literature_info') - book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='literature_info') + module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='literature_info', verbose_name=_('module')) + book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='literature_info', verbose_name=_('book')) - TUCAN='TC' STAFF='SF' STUDENT='SD' + TUCAN='TC' # The options for seasons available SOURCE_CHOICES = ( @@ -533,7 +533,18 @@ class Literature(models.Model): verbose_name=_("source"), ) + in_tucan = models.BooleanField( + default=True, + verbose_name=_("in TUCaN") + ) + + active = models.BooleanField( + default=True, + verbose_name=_("active") + ) + class Meta: + unique_together = ('book', 'module') verbose_name = _("literature") verbose_name_plural = _("literature") @@ -546,6 +557,9 @@ class ModuleCategory(models.Model): # The name for this category name_en = models.CharField(max_length = 128, verbose_name = _("english name"), blank = True) + # Whether the category should be visible + visible = models.BooleanField(default=True, verbose_name = _("visible")) + # Get the displayed name: english if given and active, else german def name(self): return self.name_en if get_language() == 'en' and self.name_en else self.name_de diff --git a/pyBuchaktion/static/pyBuchaktion/pyBuchaktion.css b/pyBuchaktion/static/pyBuchaktion/pyBuchaktion.css index 19c925d..8e5748d 100644 --- a/pyBuchaktion/static/pyBuchaktion/pyBuchaktion.css +++ b/pyBuchaktion/static/pyBuchaktion/pyBuchaktion.css @@ -1,9 +1,9 @@ -table.table.book-list > tbody > tr:nth-child(4n+1), -table.table.book-list > tbody > tr:nth-child(4n+2) { +table.table.book-list > tbody > tr.book-row:nth-child(4n+1), +table.table.book-list > tbody > tr.book-row-content:nth-child(4n+2) { background-color: #eee; } -table.table.book-list > tbody > tr:nth-child(2n+2) > td { +table.table.book-list > tbody > tr.book-row-content > td { border-top: 0 !important; padding-top: 0; vertical-align: middle; @@ -41,4 +41,36 @@ table.order-table > tbody > tr.order > td > span.label { .panel>.panel-body>*:last-child, dl.dlist-book, .list-group-item>*:last-child { margin-bottom: 0; +} + +.book-grid-row > div > div.display { + line-height: 1.5em; + padding: 0.5em 1em; +} + +.book-grid-header > div > div.display { + padding: 0.5em 1em; + font-weight: bold; +} + +.book-grid > h4 { + padding: 0.75em 0.9em; + border-bottom: 1px solid #DDD; + margin: 0; +} + +.book-grid > hr { + border-color: #ddd; +} + +.book-grid > div:not(.book-grid-header):nth-of-type(2n) { + background-color: #eee; +} + +.book-grid > div.grid-book:not(:last-child) { + border-bottom: 1px solid #ddd; +} + +.no-margin { + margin: 0; } \ No newline at end of file diff --git a/pyBuchaktion/templates/pyBuchaktion/admin/import.html b/pyBuchaktion/templates/pyBuchaktion/admin/import.html new file mode 100644 index 0000000..62fb419 --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/admin/import.html @@ -0,0 +1,10 @@ +{% extends "admin/import_export/import.html" %} + +{% block extrastyle %} +{{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/pyBuchaktion/templates/pyBuchaktion/module.html b/pyBuchaktion/templates/pyBuchaktion/module.html index dbbd65f..7d71269 100644 --- a/pyBuchaktion/templates/pyBuchaktion/module.html +++ b/pyBuchaktion/templates/pyBuchaktion/module.html @@ -1,34 +1,40 @@ -{% extends "pyBuchaktion/page.html" %} {% load buchaktion_tags i18n %} +{% extends "pyBuchaktion/module_base.html" %} {% load buchaktion_tags i18n %} {% block content %} {{ block.super }} + + {% if literature %}
-

{{ module.name }}

+

{% trans "Literature" %}

-
-
{% trans "Module ID" %}:
-
{{ module.module_id }}
-
{% trans "Last offered" %}:
-
{{ module.last_offered }}
-
{% trans "Category" %}:
-
{{ module.category }}
+ {% message "module_literature" %} +
+
+ {% include "pyBuchaktion/tags/grid_books_header.html" %} + {% grid_books literature %}
+ {% endif %}
-

{% trans "Literature" %}

+

{% trans "Recommendations by other students" %}

- {% if literature %} - {% table_books literature %} - {% else %}
{% url "pyBuchaktion:book_propose" as propose %} - {% message "module_no_literature" propose=propose %} + {% url "pyBuchaktion:addbook" pk=module.id as addbook %} + {% if recommendations %} + {% message "module_recommendations" propose=propose addbook=addbook %} +
+
+ {% include "pyBuchaktion/tags/grid_books_header.html" %} + {% grid_books recommendations %} + {% else %} + {% message "module_no_recommendations" propose=propose addbook=addbook %} + {% endif %}
- {% endif %}
{% endblock content %} diff --git a/pyBuchaktion/templates/pyBuchaktion/module_base.html b/pyBuchaktion/templates/pyBuchaktion/module_base.html new file mode 100644 index 0000000..f431fc5 --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/module_base.html @@ -0,0 +1,20 @@ +{% extends "pyBuchaktion/page.html" %} {% load buchaktion_tags i18n %} + +{% block content %} +{{ block.super }} +
+
+

{{ module.name }}

+
+
+
+
{% trans "Module ID" %}:
+
{{ module.module_id }}
+
{% trans "Last offered" %}:
+
{{ module.last_offered }}
+
{% trans "Category" %}:
+
{{ module.category }}
+
+
+
+{% endblock content %} \ No newline at end of file diff --git a/pyBuchaktion/templates/pyBuchaktion/module_literature_create.html b/pyBuchaktion/templates/pyBuchaktion/module_literature_create.html new file mode 100644 index 0000000..0c791b5 --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/module_literature_create.html @@ -0,0 +1,19 @@ +{% extends "pyBuchaktion/module_base.html" %}{% load bootstrap3 i18n %} + +{% block content %} +{{ block.super }} + +
+
+

{% trans "Add student literature recommendation" %}

+
+
+
+ {% bootstrap_form form %} + {% csrf_token %} + +
+
+
+ +{% endblock content %} diff --git a/pyBuchaktion/templates/pyBuchaktion/tags/grid_books.html b/pyBuchaktion/templates/pyBuchaktion/tags/grid_books.html new file mode 100644 index 0000000..00d10cb --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/tags/grid_books.html @@ -0,0 +1,4 @@ +{% load i18n %} +{% for book in books %} +{% include "pyBuchaktion/tags/grid_row_book.html" %} +{% endfor %} diff --git a/pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html b/pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html new file mode 100644 index 0000000..dc19d3f --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/tags/grid_books_header.html @@ -0,0 +1,13 @@ +{% load i18n %} +
+
+ {% trans "Author" %} +
+
+ {% trans "ISBN-13" %} +
+
+ {% trans "Publisher" %} +
+
+
diff --git a/pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html b/pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html new file mode 100644 index 0000000..e43cc44 --- /dev/null +++ b/pyBuchaktion/templates/pyBuchaktion/tags/grid_row_book.html @@ -0,0 +1,33 @@ +{% load i18n view_tools buchaktion_tags %} +
+
+
{{ book.title }}
+
+
+ {% if book.state != 'AC' %} + + {{ book.statename }} + + {% elif book.orderset|length > 0 %} + + {% trans "Ordered" %} + + {% else %} + + {% trans "Order this book" %} + + {% endif %} +
+
+
+
+
{{ book.author }}
+
{{ book.isbn_13|isbn }}
+
{{ book.publisher }}
+ +
+
\ No newline at end of file diff --git a/pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html b/pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html index f96d652..78abf03 100644 --- a/pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html +++ b/pyBuchaktion/templates/pyBuchaktion/tags/table_row_book.html @@ -1,23 +1,25 @@ {% load i18n view_tools buchaktion_tags %} - + {{ book.title }} - {% if book.state != 'AC' %} - - {{ book.statename }} - - {% elif book.orderset|length > 0 %} - - {% trans "Ordered" %} - - {% else %} - - {% trans "Order this book" %} - - {% endif %} +
+ {% if book.state != 'AC' %} + + {{ book.statename }} + + {% elif book.orderset|length > 0 %} + + {% trans "Ordered" %} + + {% else %} + + {% trans "Order this book" %} + + {% endif %} +
- +   {{ book.author }} {{ book.isbn_13|isbn }} diff --git a/pyBuchaktion/templatetags/buchaktion_tags.py b/pyBuchaktion/templatetags/buchaktion_tags.py index 6446cc4..ede75c4 100644 --- a/pyBuchaktion/templatetags/buchaktion_tags.py +++ b/pyBuchaktion/templatetags/buchaktion_tags.py @@ -19,6 +19,10 @@ def list_group_modules(module_list): def table_books(book_list): return {'books': book_list} +@register.inclusion_tag('pyBuchaktion/tags/grid_books.html') +def grid_books(book_list): + return {'books': book_list} + @register.inclusion_tag('pyBuchaktion/tags/dlist_book.html') def dlist_book(book): return {'book': book} diff --git a/pyBuchaktion/urls.py b/pyBuchaktion/urls.py index 9c1bdf2..21cf6ef 100644 --- a/pyBuchaktion/urls.py +++ b/pyBuchaktion/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url +from django.utils.translation import ugettext_lazy as _ from .views import * app_name = 'pyBuchaktion' @@ -13,7 +14,10 @@ ])), ])), url(r'^module/', include([ - url(r'^(?P\d*)/$', ModuleDetailView.as_view(), name = 'module'), + url(r'^(?P\d*)/', include([ + url(r'^$', ModuleDetailView.as_view(), name = 'module'), + url(r'^addbook/$', LiteratureCreateView.as_view(), name = 'addbook'), + ])), url(r'^search/', ModuleListView.as_view(), name='module_search'), url(r'^$', ModuleCategoriesView.as_view(), name = 'modules'), ])), diff --git a/pyBuchaktion/views.py b/pyBuchaktion/views.py index 6d6da13..47c0977 100644 --- a/pyBuchaktion/views.py +++ b/pyBuchaktion/views.py @@ -5,8 +5,8 @@ from django.http import HttpResponseRedirect from django.db.models import F, Count, ExpressionWrapper, Prefetch -from .forms import BookSearchForm, ModuleSearchForm, AccountEditForm, BookOrderForm, BookProposeForm -from .models import Book, Module, Order, Student, OrderTimeframe, ModuleCategory +from .forms import BookSearchForm, ModuleSearchForm, AccountEditForm, BookOrderForm, BookProposeForm, LiteratureCreateForm +from .models import Book, Module, Order, Student, OrderTimeframe, ModuleCategory, Literature from .mixins import SearchFormContextMixin, StudentRequestMixin, StudentRequiredMixin, NeverCacheMixin, UnregisteredStudentRequiredMixin @@ -159,13 +159,22 @@ class ModuleDetailView(StudentRequestMixin, DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - literature = self.object.literature.all() + books = Book.objects.filter(literature_info__module=self.object) + books = books.filter(state=Book.ACCEPTED) + get_args = {'literature_info__source': Literature.STUDENT} + literature = books.exclude(**get_args) + recommendations = books.filter(**get_args) if self.request.student: literature = Order.objects.student_annotate_book_queryset( - self.request.student, - literature, + self.request.student, literature, ).all() - context.update({'literature': literature}) + recommendations = Order.objects.student_annotate_book_queryset( + self.request.student, recommendations, + ).all() + context.update({ + 'literature': literature, + 'recommendations': recommendations, + }) return context @@ -182,6 +191,7 @@ def get_context_data(self, **kwargs): def get_queryset(self): queryset = super().get_queryset() + queryset = queryset.filter(visible=True) queryset = queryset.annotate(module_count=Count('module')) queryset = queryset.filter(module_count__gt=0) modules = Module.objects.annotate(book_count=Count('literature')) @@ -309,3 +319,32 @@ def form_invalid(self, form): except (TypeError, ValueError, Book.DoesNotExist) as e: form.add_error(ValidationError(e)) return super().form_invalid(form) + + +class LiteratureCreateView(StudentRequiredMixin, CreateView): + model = Module + form_class = LiteratureCreateForm + template_name_suffix = '_literature_create' + + def get_success_url(self): + return reverse("pyBuchaktion:module", kwargs={'pk': self.object.module.pk}) + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + if kwargs['instance'] is None: + kwargs['instance'] = Literature() + kwargs['instance'].module = Module.objects.get(pk=self.kwargs.get('pk', None)) + kwargs['instance'].source = Literature.STUDENT + kwargs['instance'].in_tucan = False + kwargs['instance'].active = True + return kwargs + + def get_form(self, form_class=None): + form = super().get_form(form_class) + # form.fields["book"].queryset = Book.objects.filter(state=Book.ACCEPTED) + return form + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update({'module': Module.objects.get(pk=self.kwargs.get('pk', None))}) + return context diff --git a/tucan-export/tucan-export.py b/tucan-export/tucan-export.py index 3eab500..d30cd08 100755 --- a/tucan-export/tucan-export.py +++ b/tucan-export/tucan-export.py @@ -24,8 +24,8 @@ GOOGLE_BOOKS_BASE_PATH = '/books/v1/volumes?' # CSS Selectors. TUCAN_CC_SELECTOR = '#pageTopNavi ul a' -#TUCAN_DEPT_SELECTOR = '#auditRegistration_list li[title="Dept. 20 - Computer Science"] a' -TUCAN_DEPT_SELECTOR = '#auditRegistration_list li[title="FB20 - Informatik"] a' +TUCAN_DEPT_SELECTOR = '#auditRegistration_list li[title="Dept. 20 - Computer Science"] a' +# TUCAN_DEPT_SELECTOR = '#auditRegistration_list li[title="FB04 - Mathematik"] a' TUCAN_MODULE_CONTAINER_SELECTOR = '#auditRegistration_list li a' TUCAN_BREADCRUMBS_SELECTOR = '.pageElementTop > h2 > a' TUCAN_MODULE_COURSE_IDNAME_SELECTOR = '#pageContent form h1'; @@ -91,8 +91,7 @@ def __init__(self, cid, name, name_en, category, url, candidates): self.books = [] self.candidates = candidates # WARNING: This has to be changed every season! - self.last_offered_year = 17 - self.last_offered_season = 'S' + self.last_offered = 'S17' def __str__(self): @@ -359,14 +358,12 @@ def _createBrowser(self): exit(1) # end: Tucan - - ############## ### SCRIPT ### ############## if len(argv) < 5: - print("Usage: python ./tucan-export.py ") + print("Usage: python ./tucan-export.py ") exit(1) tucan = Tucan() @@ -413,10 +410,10 @@ def _createBrowser(self): module_export_file = argv[2] with open(module_export_file, 'w') as file: writer = csv.writer(file, delimiter = ',', quotechar = '"', quoting = csv.QUOTE_MINIMAL) - writer.writerow(['books', 'category__name_de', 'module_id', 'name_de', 'name_en', 'last_offered__year', 'last_offered__season']) + writer.writerow(['books', 'category__name_de', 'module_id', 'name_de', 'name_en', 'last_offered']) print('Writing modules file...') for module in modules: - writer.writerow(['|'.join(module.books), module.category, module.cid, module.name, module.name_en, module.last_offered_year, module.last_offered_season]) + writer.writerow([', '.join(module.books), module.category, module.cid, module.name, module.name_en, module.last_offered]) print(" Done!") category_export_file = argv[3]