Merge branch 'master' into appdev
authorRadek Czajka <rczajka@rczajka.pl>
Wed, 8 Oct 2025 12:43:07 +0000 (14:43 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Wed, 8 Oct 2025 12:43:07 +0000 (14:43 +0200)
1  2 
src/catalogue/api/serializers.py
src/catalogue/api/urls2.py
src/catalogue/api/views.py
src/catalogue/models/book.py
src/catalogue/models/bookmedia.py
src/catalogue/views.py
src/social/views.py

Simple merge
@@@ -23,9 -23,9 +23,11 @@@ urlpatterns = 
           piwik_track_view(views.BookFragmentView.as_view()),
           name='catalogue_api_book_fragment'
           ),
-     path('books/<slug:slug>/media/<slug:type>/', views.BookMediaView.as_view()),
+     path('books/<slug:slug>/media/<slug:type>/',
+          views.BookMediaView.as_view()
+          ),
 +    path('books/<slug:slug>.json',
 +        views.BookJsonView.as_view()),
  
      path('suggested-tags/',
           piwik_track_view(views.SuggestedTags.as_view()),
@@@ -537,15 -523,7 +537,17 @@@ class BookMediaView(ListAPIView)
      pagination_class = None
  
      def get_queryset(self):
-         return BookMedia.objects.filter(book__slug=self.kwargs['slug'], type=self.kwargs['type']).order_by('index')
+         return BookMedia.objects.filter(
+             book__slug=self.kwargs['slug'],
+             type=self.kwargs['type']
+         ).order_by('index')
 +
 +
 +from .tojson import conv
 +from lxml import etree
 +from rest_framework.views import APIView
 +class BookJsonView(APIView):
 +    def get(self, request, slug):
 +        book = get_object_or_404(Book, slug=slug)
 +        js = conv(etree.parse(book.xml_file.path))
 +        return JsonResponse(js, json_dumps_params={'ensure_ascii': False})
@@@ -92,8 -94,10 +94,10 @@@ class Book(models.Model)
      objects = models.Manager()
      tagged = managers.ModelTaggedItemManager(Tag)
      tags = managers.TagDescriptor(Tag)
 -    tag_relations = GenericRelation(Tag.intermediary_table_model)
 +    tag_relations = GenericRelation(Tag.intermediary_table_model, related_query_name='tagged_book')
      translators = models.ManyToManyField(Tag, blank=True)
+     narrators = models.ManyToManyField(Tag, blank=True, related_name='narrated')
+     has_audio = models.BooleanField(default=False)
  
      html_built = django.dispatch.Signal()
      published = django.dispatch.Signal()
Simple merge
@@@ -238,16 -225,12 +238,17 @@@ class TaggedObjectList(BookList)
              t for t in self.ctx['tags']
              if t is not self.ctx['main_tag']
          ]
 -        if len(self.ctx['tags']) == 1 and self.ctx['main_tag'].category == 'author':
 +        if len(self.ctx['tags']) == 1 and self.ctx['main_tag'] is not None and self.ctx['main_tag'].category == 'author':
              self.ctx['translation_list'] = self.ctx['main_tag'].book_set.all()
+             self.ctx['narrated'] = self.ctx['main_tag'].narrated.all()
  
      def get_queryset(self):
 -        qs = Book.tagged.with_all(self.ctx['work_tags']).filter(findable=True)
 +        if self.ctx['work_tags']:
 +            qs = Book.tagged.with_all(self.ctx['work_tags']).filter(findable=True)
 +        else:
 +            qs = Book.objects.filter(findable=True)
 +        for ul in self.ctx['user_lists']:
 +            qs = qs.filter(id__in=[i.id for i in ul.get_books()])
          qs = qs.exclude(ancestor__in=qs)
          if self.is_themed:
              fqs = Fragment.tagged.with_all(self.ctx['fragment_tags'])
@@@ -18,13 -19,14 +18,14 @@@ from wolnelektury.utils import is_aja
  # ====================
  
  
- @require_POST
+ @login_required
  def like_book(request, slug):
-     if not request.user.is_authenticated:
-         return HttpResponseForbidden('Login required.')
      book = get_object_or_404(Book, slug=slug)
  
 -    book.like(request.user)
+     if request.method != 'POST':
+         return redirect(book)
 +    models.UserList.like(request.user, book)
  
      if is_ajax(request):
          return JsonResponse({"success": True, "msg": "ok", "like": True})
@@@ -49,13 -51,14 +50,14 @@@ class RemoveSetView(AddSetView)
      form_class = forms.RemoveSetForm
  
  
- @require_POST
+ @login_required
  def unlike_book(request, slug):
-     if not request.user.is_authenticated:
-         return HttpResponseForbidden('Login required.')
      book = get_object_or_404(Book, slug=slug)
  
 -    book.unlike(request.user)
+     if request.method != 'POST':
+         return redirect(book)
 +    models.UserList.unlike(request.user, book)
  
      if is_ajax(request):
          return JsonResponse({"success": True, "msg": "ok", "like": False})