b492433502f0e84137521bad90a719713ee2ef15
[redakcja.git] / src / catalogue / templatetags / book_list.py
1 from re import split
2 from django.db.models import Q, Count
3 from django import template
4 from django.utils.translation import ugettext_lazy as _
5 from django.contrib.auth.models import User
6 from catalogue.models import Chunk, Image, Project
7
8 register = template.Library()
9
10
11 class ChunksList(object):
12     def __init__(self, chunk_qs):
13         self.chunk_qs = chunk_qs.select_related('book', 'book__project', 'stage', 'user')
14         self.book_qs = chunk_qs.values('book_id')
15
16     def __getitem__(self, key):
17         if isinstance(key, slice):
18             return self.get_slice(key)
19         elif isinstance(key, int):
20             return self.get_slice(slice(key, key+1))[0]
21         else:
22             raise TypeError('Unsupported list index. Must be a slice or an int.')
23
24     def __len__(self):
25         return self.book_qs.count()
26
27     def get_slice(self, slice_):
28         book_ids = [x['book_id'] for x in self.book_qs[slice_]]
29         chunk_qs = self.chunk_qs.filter(book__in=book_ids)
30
31         chunks_list = []
32         book = None
33         for chunk in chunk_qs:
34             if chunk.book != book:
35                 book = chunk.book
36                 chunks_list.append(ChoiceChunks(book, [chunk]))
37             else:
38                 chunks_list[-1].chunks.append(chunk)
39         return chunks_list
40
41
42 class ChoiceChunks(object):
43     """
44         Associates the given chunks iterable for a book.
45     """
46
47     chunks = None
48
49     def __init__(self, book, chunks):
50         self.book = book
51         self.chunks = chunks
52
53
54 def foreign_filter(qs, value, filter_field, model, model_field='slug', unset='-'):
55     if value == unset:
56         return qs.filter(**{filter_field: None})
57     if not value:
58         return qs
59     try:
60         obj = model._default_manager.get(**{model_field: value})
61     except model.DoesNotExist:
62         return qs.none()
63     else:
64         return qs.filter(**{filter_field: obj})
65
66
67 def search_filter(qs, value, filter_fields):
68     if not value:
69         return qs
70     q = Q(**{"%s__icontains" % filter_fields[0]: value})
71     for field in filter_fields[1:]:
72         q |= Q(**{"%s__icontains" % field: value})
73     return qs.filter(q)
74
75
76 _states = [
77         ('publishable', _('publishable'), Q(book___new_publishable=True)),
78         ('changed', _('changed'), Q(_changed=True)),
79         ('published', _('published'), Q(book___published=True)),
80         ('unpublished', _('unpublished'), Q(book___published=False)),
81         ('empty', _('empty'), Q(head=None)),
82     ]
83 _states_options = [s[:2] for s in _states]
84 _states_dict = dict([(s[0], s[2]) for s in _states])
85
86
87 def document_list_filter(request, **kwargs):
88
89     def arg_or_GET(field):
90         return kwargs.get(field, request.GET.get(field))
91
92     if arg_or_GET('all'):
93         chunks = Chunk.objects.all()
94     else:
95         chunks = Chunk.visible_objects.all()
96
97     chunks = chunks.order_by('book__title', 'book', 'number')
98
99     if not request.user.is_authenticated:
100         chunks = chunks.filter(book__public=True)
101
102     state = arg_or_GET('status')
103     if state in _states_dict:
104         chunks = chunks.filter(_states_dict[state])
105
106     chunks = foreign_filter(chunks, arg_or_GET('user'), 'user', User, 'username')
107     chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model, 'slug')
108     chunks = search_filter(chunks, arg_or_GET('title'), ['book__title', 'title'])
109     chunks = foreign_filter(chunks, arg_or_GET('project'), 'book__project', Project, 'pk')
110     return chunks
111
112
113 @register.inclusion_tag('catalogue/book_list/book_list.html', takes_context=True)
114 def book_list(context, user=None):
115     request = context['request']
116
117     if user:
118         filters = {"user": user}
119         new_context = {"viewed_user": user}
120     else:
121         filters = {}
122         new_context = {
123             "users": User.objects.annotate(
124                 count=Count('chunk')).filter(count__gt=0).order_by(
125                 '-count', 'last_name', 'first_name'),
126             "other_users": User.objects.annotate(
127                 count=Count('chunk')).filter(count=0).order_by(
128                 'last_name', 'first_name'),
129                 }
130
131     new_context.update({
132         "filters": True,
133         "request": request,
134         "books": ChunksList(document_list_filter(request, **filters)),
135         "stages": Chunk.tag_model.objects.all(),
136         "states": _states_options,
137         "projects": Project.objects.all(),
138     })
139
140     return new_context
141
142
143
144 _image_states = [
145         ('publishable', _('publishable'), Q(_new_publishable=True)),
146         ('changed', _('changed'), Q(_changed=True)),
147         ('published', _('published'), Q(_published=True)),
148         ('unpublished', _('unpublished'), Q(_published=False)),
149         ('empty', _('empty'), Q(head=None)),
150     ]
151 _image_states_options = [s[:2] for s in _image_states]
152 _image_states_dict = dict([(s[0], s[2]) for s in _image_states])
153
154 def image_list_filter(request, **kwargs):
155
156     def arg_or_GET(field):
157         return kwargs.get(field, request.GET.get(field))
158
159     images = Image.objects.all().select_related('user', 'stage', 'project')
160
161     if not request.user.is_authenticated:
162         images = images.filter(public=True)
163
164     state = arg_or_GET('status')
165     if state in _image_states_dict:
166         images = images.filter(_image_states_dict[state])
167
168     images = foreign_filter(images, arg_or_GET('user'), 'user', User, 'username')
169     images = foreign_filter(images, arg_or_GET('stage'), 'stage', Image.tag_model, 'slug')
170     images = search_filter(images, arg_or_GET('title'), ['title', 'title'])
171     images = foreign_filter(images, arg_or_GET('project'), 'project', Project, 'pk')
172     return images
173
174
175 @register.inclusion_tag('catalogue/image_table.html', takes_context=True)
176 def image_list(context, user=None):
177     request = context['request']
178
179     if user:
180         filters = {"user": user}
181         new_context = {"viewed_user": user}
182     else:
183         filters = {}
184         new_context = {
185             "users": User.objects.annotate(
186                 count=Count('image')).filter(count__gt=0).order_by(
187                 '-count', 'last_name', 'first_name'),
188             "other_users": User.objects.annotate(
189                 count=Count('image')).filter(count=0).order_by(
190                 'last_name', 'first_name'),
191                 }
192
193     new_context.update({
194         "filters": True,
195         "request": request,
196         "objects": image_list_filter(request, **filters),
197         "stages": Image.tag_model.objects.all(),
198         "states": _image_states_options,
199         "projects": Project.objects.all(),
200     })
201
202     return new_context