API: get changes since
[wolnelektury.git] / apps / api / handlers.py
index 151af2d..cca504f 100644 (file)
@@ -1,14 +1,20 @@
 # -*- coding: utf-8 -*-
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+
+from datetime import datetime
 from django.shortcuts import get_object_or_404
 from django.contrib.auth.decorators import login_required, user_passes_test
+from django.utils import simplejson as json
 from piston.handler import BaseHandler
 from piston.utils import rc, validate
+
+from api.models import Deleted
+from api.helpers import timestamp
 from catalogue.models import Book, Tag
 from catalogue.forms import BookImportForm
 from catalogue.views import tagged_object_list 
-
+"""
 class TagHandler(BaseHandler):
    allowed_methods = ('GET',)
    model = Tag   
@@ -28,6 +34,153 @@ class BookHandler(BaseHandler):
             return get_object_or_404(Book, slug=slug)
         else:
             return Book.objects.all()
+"""
+
+
+class WLHandler(BaseHandler):
+
+    @staticmethod
+    def fields(request, name):
+        fields_str = request.GET.get(name) if request is not None else None
+        return fields_str.split(',') if fields_str is not None else None
+
+    @staticmethod
+    def book_dict(book, fields=None, extra_fields=None):
+        obj = {}
+        for field in ('slug', 'title', 'description',
+                      'extra_info', 'gazeta_link', 'wiki_link'):
+            if getattr(book, field):
+                obj[field] = getattr(book, field)
+        for field in ('created_at', 'changed_at'):
+            obj[field] = timestamp(getattr(book, field))
+        for field in ('xml', 'epub', 'txt', 'pdf', 'html'):
+            f = getattr(book, field+'_file') 
+            if f:
+                obj[field] = f.url
+        for media in book.medias.all():
+            obj.setdefault(media.type, []).append(media.file.url)
+        if book.parent:
+            obj['parent'] = book.parent.id
+            obj['parent_number'] = book.parent_number
+        if fields is not None:
+            for key in obj.keys():
+                if key not in fields:
+                    del obj[key]
+
+        # if there's still extra_info, we can parse it
+        if 'extra_info' in obj:
+            extra = json.loads(obj['extra_info'])
+            if extra_fields is not None:
+                for key in extra.keys():
+                    if key not in extra_fields:
+                        del extra[key]
+            obj['extra_info'] = extra
+
+        obj['id'] = book.id
+        return obj
+
+    @classmethod
+    def book_changes(cls, since=0, request=None):
+        since = datetime.fromtimestamp(float(since))
+        book_fields = cls.fields(request, 'book_fields')
+        extra_fields = cls.fields(request, 'extra_fields')
+
+        added = []
+        changed = []
+        deleted = []
+
+        last_change = since
+        for book in Book.objects.filter(changed_at__gt=since):
+            if book.changed_at > last_change:
+                last_change = book.changed_at
+            book_d = cls.book_dict(book, book_fields, extra_fields)
+            if book.created_at > since:
+                added.append(book_d)
+            else:
+                changed.append(book_d)
+
+        for book in Deleted.objects.filter(type='Book', deleted_at__gt=since, created_at__lte=since):
+            if book.deleted_at > last_change:
+                last_change = book.deleted_at
+            deleted.append(book.id)
+        return {'added': added, 'changed': changed, 'deleted': deleted, 'last_change': timestamp(last_change)}
+
+    @staticmethod
+    def tag_dict(tag, fields=None):
+        obj = {}
+        for field in ('name', 'slug', 'sort_key', 'category', 'description', 'main_page', #'created_at', 'changed_at',
+                      'gazeta_link', 'wiki_link'):
+            if getattr(tag, field):
+                obj[field] = getattr(tag, field)
+        if fields is not None:
+            for key in obj.keys():
+                if key not in fields:
+                    del obj[key]
+        obj['id'] = tag.id
+        return obj
+
+    @classmethod
+    def tag_changes(cls, since=0, request=None):
+        since = datetime.fromtimestamp(float(since))
+        tag_fields = cls.fields(request, 'tag_fields')
+
+        added = []
+        changed = []
+        deleted = []
+
+        last_change = since
+        for tag in Tag.objects.filter(changed_at__gt=since):
+            if tag.changed_at > last_change:
+                last_change = tag.changed_at
+            tag_d = cls.tag_dict(tag, tag_fields)
+            if tag.created_at > since:
+                added.append(tag_d)
+            else:
+                changed.append(tag_d)
+
+        for tag in Deleted.objects.filter(type='Tag', deleted_at__gt=since, created_at__lte=since):
+            if tag.deleted_at > last_change:
+                last_change = tag.deleted_at
+            deleted.append(tag.id)
+        return {'added': added, 'changed': changed, 'deleted': deleted, 'last_change': timestamp(last_change)}
+
+
+class BookChangesHandler(WLHandler):
+    allowed_methods = ('GET',)
+
+    def read(self, request, since):
+        return self.book_changes(since, request)
+
+
+class TagChangesHandler(WLHandler):
+    allowed_methods = ('GET',)
+
+    def read(self, request, since):
+        return self.tag_changes(since, request)
+
+
+class ChangesHandler(WLHandler):
+    allowed_methods = ('GET',)
+
+    def read(self, request, since):
+        changes = {
+            'books': self.book_changes(since, request),
+            'tags': self.tag_changes(since, request),
+        }
+
+        last_change = 0
+        changes_rev = {}
+        for model in changes:
+            for field in changes[model]:
+                if field == 'last_change':
+                    if changes[model][field] > last_change:
+                        last_change = changes[model][field]
+                else:
+                    changes_rev.setdefault(field, {})[model] = changes[model][field]
+        changes_rev['last_change'] = last_change
+        return changes_rev
+
+
 
 # old
 """