a4782dcb1bd6e0dfb6e3907aceaf50c13fe56d3c
[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 piston.handler import BaseHandler
7
8 from api.helpers import timestamp
9 from api.models import Deleted
10 from catalogue.models import Book, Tag
11
12 class CatalogueHandler(BaseHandler):
13
14     @staticmethod
15     def fields(request, name):
16         fields_str = request.GET.get(name) if request is not None else None
17         return fields_str.split(',') if fields_str is not None else None
18
19     @staticmethod
20     def book_dict(book, fields=None):
21         all_fields = ('url', 'title', 'description',
22                       'gazeta_link', 'wiki_link',
23                       'xml', 'epub', 'txt', 'pdf', 'html',
24                       'mp3', 'ogg', 'daisy',
25                       'parent', 'parent_number',
26                       'tags',
27                       'license', 'license_description', 'source_name',
28                       'technical_editors', 'editors',
29                      )
30         if fields:
31             fields = (f for f in fields if f in all_fields)
32         else:
33             fields = all_fields
34
35         extra_info = book.get_extra_info_value()
36
37         obj = {}
38         for field in fields:
39
40             if field in ('xml', 'epub', 'txt', 'pdf', 'html'):
41                 f = getattr(book, field+'_file')
42                 if f:
43                     obj[field] = {
44                         'url': f.url,
45                         'size': f.size,
46                     }
47
48             elif field in ('mp3', 'ogg', 'daisy'):
49                 media = []
50                 for m in book.medias.filter(type=''):
51                     files.append({
52                         'url': m.file.get_absolute_url(),
53                         'size': m.file.size,
54                     })
55                 if media:
56                     obj[field] = media
57
58             elif field == 'url':
59                 obj[field] = book.get_absolute_url()
60
61             elif field == 'tags':
62                 obj[field] = [t.id for t in book.tags.exclude(category__in=('book', 'set'))]
63
64             elif field in ('license', 'license_description', 'source_name',
65                       'technical_editors', 'editors'):
66                 f = extra_info.get(field)
67                 if f:
68                     obj[field] = f
69
70             else:
71                 f = getattr(book, field)
72                 if f:
73                     obj[field] = f
74
75         obj['id'] = book.id
76         return obj
77
78     @classmethod
79     def book_changes(cls, since=0, request=None, fields=None):
80         since = datetime.fromtimestamp(int(since))
81         if not fields:
82             fields = cls.fields(request, 'book_fields')
83
84         added = []
85         updated = []
86         deleted = []
87
88         last_change = since
89         for book in Book.objects.filter(changed_at__gte=since):
90             book_d = cls.book_dict(book, fields)
91             updated.append(book_d)
92
93         for book in Deleted.objects.filter(content_type=Book, deleted_at__gte=since, created_at__lt=since):
94             deleted.append(book.id)
95         return {'updated': updated, 'deleted': deleted}
96
97     @staticmethod
98     def tag_dict(tag, fields=None):
99         all_fields = ('name', 'category', 'sort_key', 'description',
100                       'gazeta_link', 'wiki_link',
101                       'url',
102                      )
103
104         if fields:
105             fields = (f for f in fields if f in all_fields)
106         else:
107             fields = all_fields
108
109         obj = {}
110         for field in fields:
111
112             if field == 'url':
113                 obj[field] = tag.get_absolute_url()
114
115             else:
116                 f = getattr(tag, field)
117                 if f:
118                     obj[field] = f
119
120         obj['id'] = tag.id
121         return obj
122
123     @classmethod
124     def tag_changes(cls, since=0, request=None, fields=None, categories=None):
125         since = datetime.fromtimestamp(int(since))
126         if not fields:
127             fields = cls.fields(request, 'tag_fields')
128         if not categories:
129             categories = cls.fields(request, 'tag_categories')
130
131         all_categories = ('author', 'theme', 'epoch', 'kind', 'genre')
132         if categories:
133             categories = (c for c in categories if c in all_categories)
134         else:
135             categories = all_categories
136
137         updated = []
138         deleted = []
139
140         for tag in Tag.objects.filter(category__in=categories, changed_at__gte=since):
141             tag_d = cls.tag_dict(tag, fields)
142             updated.append(tag_d)
143
144         for tag in Deleted.objects.filter(category__in=categories,
145                 content_type=Tag, deleted_at__gte=since, created_at__lt=since):
146             deleted.append(tag.id)
147         return {'updated': updated, 'deleted': deleted}
148
149     @classmethod
150     def changes(cls, since=0, request=None, book_fields=None,
151                 tag_fields=None, tag_categories=None):
152         changes = {
153             'time_checked': timestamp(datetime.now())
154         }
155
156         changes_by_type = {
157             'books': cls.book_changes(since, request, book_fields),
158             'tags': cls.tag_changes(since, request, tag_fields, tag_categories),
159         }
160
161         for model in changes_by_type:
162             for field in changes_by_type[model]:
163                 changes.setdefault(field, {})[model] = changes_by_type[model][field]
164         return changes
165
166
167 class BookChangesHandler(CatalogueHandler):
168     allowed_methods = ('GET',)
169
170     def read(self, request, since):
171         return self.book_changes(since, request)
172
173
174 class TagChangesHandler(CatalogueHandler):
175     allowed_methods = ('GET',)
176
177     def read(self, request, since):
178         return self.tag_changes(since, request)
179
180
181 class ChangesHandler(CatalogueHandler):
182     allowed_methods = ('GET',)
183
184     def read(self, request, since):
185         return self.changes(since, request)