Merge commit '645219bfa68384dad930269b94e2ddf8b4cd3488' into api
[wolnelektury.git] / apps / api / handlers.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4
5 from datetime import datetime
6 from django.shortcuts import get_object_or_404
7 from django.contrib.auth.decorators import login_required, user_passes_test
8 from django.utils import simplejson as json
9 from piston.handler import BaseHandler
10 from piston.utils import rc, validate
11
12 from api.models import Deleted
13 from api.helpers import timestamp
14 from catalogue.models import Book, Tag
15 from catalogue.forms import BookImportForm
16 from catalogue.views import tagged_object_list 
17 """
18 class TagHandler(BaseHandler):
19    allowed_methods = ('GET',)
20    model = Tag   
21
22    def read(self, request, tags=''):
23       if tags == '':
24         return Tag.objects.all()
25       else:
26         return tagged_object_list(request, tags, api=True)
27
28 class BookHandler(BaseHandler):
29     model = Book
30     #fields = ('slug', 'title')
31
32     def read(self, request, slug=None):
33         if slug:
34             return get_object_or_404(Book, slug=slug)
35         else:
36             return Book.objects.all()
37 """
38
39
40 class WLHandler(BaseHandler):
41
42     @staticmethod
43     def fields(request, name):
44         fields_str = request.GET.get(name) if request is not None else None
45         return fields_str.split(',') if fields_str is not None else None
46
47     @staticmethod
48     def book_dict(book, fields=None, extra_fields=None):
49         obj = {}
50         for field in ('slug', 'title', 'description',
51                       'extra_info', 'gazeta_link', 'wiki_link'):
52             if getattr(book, field):
53                 obj[field] = getattr(book, field)
54         for field in ('created_at', 'changed_at'):
55             obj[field] = timestamp(getattr(book, field))
56         for field in ('xml', 'epub', 'txt', 'pdf', 'html'):
57             f = getattr(book, field+'_file') 
58             if f:
59                 obj[field] = f.url
60         for media in book.medias.all():
61             obj.setdefault(media.type, []).append(media.file.url)
62         if book.parent:
63             obj['parent'] = book.parent.id
64             obj['parent_number'] = book.parent_number
65         if fields is not None:
66             for key in obj.keys():
67                 if key not in fields:
68                     del obj[key]
69
70         # if there's still extra_info, we can parse it
71         if 'extra_info' in obj:
72             extra = json.loads(obj['extra_info'])
73             if extra_fields is not None:
74                 for key in extra.keys():
75                     if key not in extra_fields:
76                         del extra[key]
77             obj['extra_info'] = extra
78
79         obj['id'] = book.id
80         return obj
81
82     @classmethod
83     def book_changes(cls, since=0, request=None):
84         since = datetime.fromtimestamp(float(since))
85         book_fields = cls.fields(request, 'book_fields')
86         extra_fields = cls.fields(request, 'extra_fields')
87
88         added = []
89         changed = []
90         deleted = []
91
92         last_change = since
93         for book in Book.objects.filter(changed_at__gt=since):
94             if book.changed_at > last_change:
95                 last_change = book.changed_at
96             book_d = cls.book_dict(book, book_fields, extra_fields)
97             if book.created_at > since:
98                 added.append(book_d)
99             else:
100                 changed.append(book_d)
101
102         for book in Deleted.objects.filter(type='Book', deleted_at__gt=since, created_at__lte=since):
103             if book.deleted_at > last_change:
104                 last_change = book.deleted_at
105             deleted.append(book.id)
106         return {'added': added, 'changed': changed, 'deleted': deleted, 'last_change': timestamp(last_change)}
107
108     @staticmethod
109     def tag_dict(tag, fields=None):
110         obj = {}
111         for field in ('name', 'slug', 'sort_key', 'category', 'description', 'main_page', #'created_at', 'changed_at',
112                       'gazeta_link', 'wiki_link'):
113             if getattr(tag, field):
114                 obj[field] = getattr(tag, field)
115         if fields is not None:
116             for key in obj.keys():
117                 if key not in fields:
118                     del obj[key]
119         obj['id'] = tag.id
120         return obj
121
122     @classmethod
123     def tag_changes(cls, since=0, request=None):
124         since = datetime.fromtimestamp(float(since))
125         tag_fields = cls.fields(request, 'tag_fields')
126
127         added = []
128         changed = []
129         deleted = []
130
131         last_change = since
132         for tag in Tag.objects.filter(changed_at__gt=since):
133             if tag.changed_at > last_change:
134                 last_change = tag.changed_at
135             tag_d = cls.tag_dict(tag, tag_fields)
136             if tag.created_at > since:
137                 added.append(tag_d)
138             else:
139                 changed.append(tag_d)
140
141         for tag in Deleted.objects.filter(type='Tag', deleted_at__gt=since, created_at__lte=since):
142             if tag.deleted_at > last_change:
143                 last_change = tag.deleted_at
144             deleted.append(tag.id)
145         return {'added': added, 'changed': changed, 'deleted': deleted, 'last_change': timestamp(last_change)}
146
147
148 class BookChangesHandler(WLHandler):
149     allowed_methods = ('GET',)
150
151     def read(self, request, since):
152         return self.book_changes(since, request)
153
154
155 class TagChangesHandler(WLHandler):
156     allowed_methods = ('GET',)
157
158     def read(self, request, since):
159         return self.tag_changes(since, request)
160
161
162 class ChangesHandler(WLHandler):
163     allowed_methods = ('GET',)
164
165     def read(self, request, since):
166         changes = {
167             'books': self.book_changes(since, request),
168             'tags': self.tag_changes(since, request),
169         }
170
171         last_change = 0
172         changes_rev = {}
173         for model in changes:
174             for field in changes[model]:
175                 if field == 'last_change':
176                     if changes[model][field] > last_change:
177                         last_change = changes[model][field]
178                 else:
179                     changes_rev.setdefault(field, {})[model] = changes[model][field]
180         changes_rev['last_change'] = last_change
181         return changes_rev
182
183
184
185 # old
186 """
187 staff_required = user_passes_test(lambda user: user.is_staff)
188
189 class BookHandler(BaseHandler):
190     model = Book
191     fields = ('slug', 'title')
192
193     @staff_required
194     def read(self, request, slug=None):
195         if slug:
196             return get_object_or_404(Book, slug=slug)
197         else:
198             return Book.objects.all()
199
200     @staff_required
201     def create(self, request):
202         form = BookImportForm(request.POST, request.FILES)
203         if form.is_valid():
204             form.save()
205             return rc.CREATED
206         else:
207             return rc.BAD_REQUEST
208 """