better related books
[wolnelektury.git] / apps / api / handlers.py
index 41b5ac6..fddff74 100644 (file)
@@ -7,6 +7,7 @@ import json
 
 from django.conf import settings
 from django.contrib.sites.models import Site
 
 from django.conf import settings
 from django.contrib.sites.models import Site
+from django.core.cache import get_cache
 from django.core.urlresolvers import reverse
 from piston.handler import AnonymousBaseHandler, BaseHandler
 from piston.utils import rc
 from django.core.urlresolvers import reverse
 from piston.handler import AnonymousBaseHandler, BaseHandler
 from piston.utils import rc
@@ -15,6 +16,8 @@ from api.helpers import timestamp
 from api.models import Deleted
 from catalogue.forms import BookImportForm
 from catalogue.models import Book, Tag, BookMedia, Fragment
 from api.models import Deleted
 from catalogue.forms import BookImportForm
 from catalogue.models import Book, Tag, BookMedia, Fragment
+from picture.models import Picture
+from picture.forms import PictureImportForm
 
 from stats.utils import piwik_track
 
 
 from stats.utils import piwik_track
 
@@ -93,14 +96,12 @@ class BookDetailHandler(BaseHandler):
 
     """
     allowed_methods = ['GET']
 
     """
     allowed_methods = ['GET']
-    fields = ['title', 'parent',
-        'xml', 'html', 'pdf', 'epub', 'txt',
+    fields = ['title', 'parent'] + Book.formats + [
         'media', 'url'] + category_singular.keys()
 
     @piwik_track
     def read(self, request, slug):
         'media', 'url'] + category_singular.keys()
 
     @piwik_track
     def read(self, request, slug):
-        """ Returns details of a book, identified by a slug. """
-
+        """ Returns details of a book, identified by a slug and lang. """
         try:
             return Book.objects.get(slug=slug)
         except Book.DoesNotExist:
         try:
             return Book.objects.get(slug=slug)
         except Book.DoesNotExist:
@@ -203,7 +204,7 @@ def _file_getter(format):
         else:
             return ''
     return get_file
         else:
             return ''
     return get_file
-for format in ('xml', 'txt', 'html', 'epub', 'pdf'):
+for format in Book.formats:
     setattr(BooksHandler, format, _file_getter(format))
 
 
     setattr(BooksHandler, format, _file_getter(format))
 
 
@@ -247,9 +248,8 @@ class TagsHandler(BaseHandler):
         except KeyError, e:
             return rc.NOT_FOUND
 
         except KeyError, e:
             return rc.NOT_FOUND
 
-        tags = Tag.objects.filter(category=category_sng)
-        tags = [t for t in tags if t.get_count() > 0]
-        if tags:
+        tags = Tag.objects.filter(category=category_sng).exclude(book_count=0)
+        if tags.exists():
             return tags
         else:
             return rc.NOT_FOUND
             return tags
         else:
             return rc.NOT_FOUND
@@ -268,7 +268,6 @@ class FragmentDetailHandler(BaseHandler):
     @piwik_track
     def read(self, request, slug, anchor):
         """ Returns details of a fragment, identified by book slug and anchor. """
     @piwik_track
     def read(self, request, slug, anchor):
         """ Returns details of a fragment, identified by book slug and anchor. """
-
         try:
             return Fragment.objects.get(book__slug=slug, anchor=anchor)
         except Fragment.DoesNotExist:
         try:
             return Fragment.objects.get(book__slug=slug, anchor=anchor)
         except Fragment.DoesNotExist:
@@ -307,7 +306,8 @@ class FragmentsHandler(BaseHandler):
     def href(cls, fragment):
         """ Returns URI in the API for the fragment. """
 
     def href(cls, fragment):
         """ Returns URI in the API for the fragment. """
 
-        return API_BASE + reverse("api_fragment", args=[fragment.book.slug, fragment.anchor])
+        return API_BASE + reverse("api_fragment", 
+            args=[fragment.book.slug, fragment.anchor])
 
     @classmethod
     def url(cls, fragment):
 
     @classmethod
     def url(cls, fragment):
@@ -353,16 +353,15 @@ class CatalogueHandler(BaseHandler):
 
     @staticmethod
     def book_dict(book, fields=None):
 
     @staticmethod
     def book_dict(book, fields=None):
-        all_fields = ('url', 'title', 'description',
+        all_fields = ['url', 'title', 'description',
                       'gazeta_link', 'wiki_link',
                       'gazeta_link', 'wiki_link',
-                      'xml', 'epub', 'txt', 'pdf', 'html',
-                      'mp3', 'ogg', 'daisy',
+                      ] + Book.formats + BookMedia.formats + [
                       'parent', 'parent_number',
                       'tags',
                       'license', 'license_description', 'source_name',
                       'technical_editors', 'editors',
                       'author', 'sort_key',
                       'parent', 'parent_number',
                       'tags',
                       'license', 'license_description', 'source_name',
                       'technical_editors', 'editors',
                       'author', 'sort_key',
-                     )
+                     ]
         if fields:
             fields = (f for f in fields if f in all_fields)
         else:
         if fields:
             fields = (f for f in fields if f in all_fields)
         else:
@@ -373,7 +372,7 @@ class CatalogueHandler(BaseHandler):
         obj = {}
         for field in fields:
 
         obj = {}
         for field in fields:
 
-            if field in ('xml', 'epub', 'txt', 'pdf', 'html'):
+            if field in Book.formats:
                 f = getattr(book, field+'_file')
                 if f:
                     obj[field] = {
                 f = getattr(book, field+'_file')
                 if f:
                     obj[field] = {
@@ -381,7 +380,7 @@ class CatalogueHandler(BaseHandler):
                         'size': f.size,
                     }
 
                         'size': f.size,
                     }
 
-            elif field in ('mp3', 'ogg', 'daisy'):
+            elif field in BookMedia.formats:
                 media = []
                 for m in book.media.filter(type=field):
                     media.append({
                 media = []
                 for m in book.media.filter(type=field):
                     media.append({
@@ -510,7 +509,7 @@ class CatalogueHandler(BaseHandler):
                     changed_at__gte=since,
                     changed_at__lt=until):
             # only serve non-empty tags
                     changed_at__gte=since,
                     changed_at__lt=until):
             # only serve non-empty tags
-            if tag.get_count():
+            if tag.book_count:
                 tag_d = cls.tag_dict(tag, fields)
                 updated.append(tag_d)
             elif tag.created_at < since:
                 tag_d = cls.tag_dict(tag, fields)
                 updated.append(tag_d)
             elif tag.created_at < since:
@@ -533,6 +532,16 @@ class CatalogueHandler(BaseHandler):
     def changes(cls, request=None, since=0, until=None, book_fields=None,
                 tag_fields=None, tag_categories=None):
         until = cls.until(until)
     def changes(cls, request=None, since=0, until=None, book_fields=None,
                 tag_fields=None, tag_categories=None):
         until = cls.until(until)
+        since = int(since)
+
+        if not since:
+            cache = get_cache('api')
+            key = hash((book_fields, tag_fields, tag_categories,
+                    tuple(sorted(request.GET.items()))
+                  ))
+            value = cache.get(key)
+            if value is not None:
+                return value
 
         changes = {
             'time_checked': timestamp(until)
 
         changes = {
             'time_checked': timestamp(until)
@@ -548,6 +557,10 @@ class CatalogueHandler(BaseHandler):
                 if field == 'time_checked':
                     continue
                 changes.setdefault(field, {})[model] = changes_by_type[model][field]
                 if field == 'time_checked':
                     continue
                 changes.setdefault(field, {})[model] = changes_by_type[model][field]
+
+        if not since:
+            cache.set(key, changes)
+
         return changes
 
 
         return changes
 
 
@@ -573,3 +586,21 @@ class ChangesHandler(CatalogueHandler):
     @piwik_track
     def read(self, request, since):
         return self.changes(request, since)
     @piwik_track
     def read(self, request, since):
         return self.changes(request, since)
+
+
+class PictureHandler(BaseHandler):
+    model = Picture
+    fields = ('slug', 'title')
+    allowed_methods = ('POST',)
+
+    def create(self, request):
+        if not request.user.has_perm('picture.add_picture'):
+            return rc.FORBIDDEN
+
+        data = json.loads(request.POST.get('data'))
+        form = PictureImportForm(data)
+        if form.is_valid():
+            form.save()
+            return rc.CREATED
+        else:
+            return rc.NOT_FOUND