| author | Riwad Salim |
| Tue, 12 Jun 2018 13:33:18 +0200 | |
| changeset 543 | 2c172934dae2 |
| parent 538 | 5cc429500a11 |
| child 562 | 303a7b5e8e59 |
| permissions | -rw-r--r-- |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
1 |
import logging |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
2 |
|
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
3 |
from django.conf import settings |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
4 |
from django.contrib import messages |
| 298 | 5 |
from django.contrib.auth.decorators import login_required |
6 |
from django.contrib.auth.models import User |
|
7 |
from django.contrib.contenttypes.models import ContentType |
|
8 |
from django.contrib.sites.models import Site |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
9 |
from django.core.exceptions import ObjectDoesNotExist |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
10 |
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator |
|
532
a301e0bc677b
refresh dependencies version, and make it work for Django 2.0
ymh <ymh.work@gmail.com>
parents:
526
diff
changeset
|
11 |
from django.urls import reverse |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
12 |
from django.db.models import Count, Prefetch |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
13 |
from django.http import Http404 |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
14 |
from django.shortcuts import HttpResponse, get_object_or_404, redirect, render |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
15 |
from django.views.generic import DetailView, RedirectView, TemplateView, View |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
16 |
from django.views.generic.base import ContextMixin |
| 298 | 17 |
from notifications.models import Notification |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
18 |
|
| 298 | 19 |
from iconolab.forms.annotations import AnnotationRevisionForm |
|
506
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
20 |
from iconolab.forms.bookmarks import BookmarkForm |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
21 |
from iconolab.models import (Annotation, AnnotationRevision, Bookmark, |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
22 |
BookmarkCategory, Collection, Folder, |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
23 |
IconolabComment, Image, Item, MetaCategory, |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
24 |
MetaCategoryInfo, Tag, TaggingInfo) |
|
337
db6c41f04e79
Move serializers to dedicated file, do not create comment on revision creation.
Alexandre Segura <mex.zktk@gmail.com>
parents:
323
diff
changeset
|
25 |
from iconolab.serializers import AnnotationRevisionSerializer |
| 298 | 26 |
|
27 |
logger = logging.getLogger(__name__) |
|
28 |
||
29 |
class GlobalHomepageView(View): |
|
30 |
""" |
|
31 |
View for the opening page of Iconolab. |
|
32 |
""" |
|
33 |
def get(self, request, *args, **kwargs): |
|
34 |
""" |
|
35 |
Template is iconolab/home.html |
|
36 |
||
37 |
Context variables provided to the template are: |
|
38 |
collections_primary: list of collections to display as big images |
|
39 |
collections_secondary: list of collections to display as small links at the bottom |
|
40 |
homepage = True: used to pass checks in the partials/header.html |
|
41 |
template to adjust the navbar to the homepage |
|
42 |
""" |
|
43 |
context = {} |
|
44 |
context['collections_primary'] = Collection.objects.filter(show_image_on_home=True).all() |
|
45 |
context['collections_secondary'] = Collection.objects.filter(show_image_on_home=False).all() |
|
| 514 | 46 |
context['latest_annotations'] = Annotation.objects.order_by("-created").all()[:5] |
47 |
||
48 |
# Best contributors |
|
49 |
count_contributions = Annotation.objects.all()\ |
|
50 |
.values('author').annotate(contributions=Count('author')).order_by('-contributions')[:10] |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
51 |
best_authors = { u.id: u for u in User.objects.filter(id__in=[cc['author'] for cc in count_contributions])} |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
52 |
context['best_contributors'] = [ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
53 |
{'author': best_authors[cc['author']], 'contributions': cc['contributions']} |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
54 |
for cc in count_contributions |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
55 |
] |
| 514 | 56 |
|
57 |
# Most accurate tags (tags with accuracy >= 4) |
|
|
515
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
58 |
# SELECT ti.tag_id, ar.title, COUNT(DISTINCT(a.id)) AS cnt |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
59 |
# FROM iconolab_tagginginfo ti |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
60 |
# JOIN iconolab_annotationrevision ar ON ti.revision_id = ar.id |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
61 |
# JOIN iconolab_annotation a ON ar.annotation_id = a.id |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
62 |
# WHERE ti.accuracy >= 4 |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
63 |
# GROUP BY ti.tag_id |
|
c1077e8f595d
Add search in tags only.
Alexandre Segura <mex.zktk@gmail.com>
parents:
514
diff
changeset
|
64 |
# ORDER BY cnt desc |
| 514 | 65 |
rows = TaggingInfo.objects\ |
66 |
.filter(accuracy__gte=4)\ |
|
67 |
.values('tag')\ |
|
68 |
.annotate(annotation_count=Count('revision__annotation', distinct=True))\ |
|
69 |
.order_by('-annotation_count')\ |
|
70 |
.all()[:10] |
|
71 |
||
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
72 |
best_tags = {t.id: t for t in Tag.objects.filter(id__in=[r['tag'] for r in rows])} |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
73 |
context['most_accurate_tags'] = [ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
74 |
{'tag': best_tags[r['tag']], 'annotation_count': r['annotation_count']} |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
75 |
for r in rows |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
76 |
] |
| 514 | 77 |
|
|
376
3d48f9520c8d
adds contact email as a setting variable from the app (instead of raw in the template
duong tam kien <tk@deveha.com>
parents:
343
diff
changeset
|
78 |
context['contact'] = settings.CONTACT_EMAIL |
| 298 | 79 |
context['homepage'] = True |
80 |
return render(request, 'iconolab/home.html', context) |
|
81 |
||
82 |
class TestView(View): |
|
83 |
template_name = 'iconolab/compare.html' |
|
84 |
||
85 |
def get(self, request, *args, **kwargs): |
|
86 |
return render(request, self.template_name) |
|
87 |
||
88 |
# Class with check_kwargs method to fetch objects from database depending on what level in the app we're currently at |
|
89 |
class IconolabObjectView(object): |
|
90 |
""" |
|
91 |
Superclass that defines method used in all object display views. |
|
92 |
""" |
|
93 |
def check_kwargs(self, kwargs): |
|
94 |
''' |
|
95 |
Returns a boolean depending on wether (True) or not (False) the objects |
|
96 |
were found and a tuple containing the objects, with a select_related/prefetch_related |
|
97 |
on relevant related objects following this ordering: |
|
98 |
(collection, item, image, annotation, revision) |
|
99 |
''' |
|
100 |
||
101 |
objects_tuple = () |
|
102 |
if 'collection_name' in kwargs.keys(): |
|
103 |
try: |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
104 |
objects_tuple += (Collection.objects.prefetch_related( |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
105 |
'items', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
106 |
'items__images', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
107 |
Prefetch( |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
108 |
'folders', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
109 |
Folder.objects.annotate(items_nb=Count('item')).order_by('name') |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
110 |
) |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
111 |
).get(name=kwargs.get('collection_name')),) |
| 298 | 112 |
except (ValueError, Collection.DoesNotExist): |
113 |
return False, RedirectView.as_view(url=reverse('404error')) |
|
114 |
if 'item_guid' in kwargs.keys(): |
|
115 |
try: |
|
116 |
objects_tuple += (Item.objects.prefetch_related('images', 'metadatas', 'images__stats').get(item_guid=kwargs.get('item_guid')),) |
|
117 |
except (ValueError, Item.DoesNotExist): |
|
118 |
return False, RedirectView.as_view(url=reverse('404error')) |
|
119 |
if 'image_guid' in kwargs.keys(): |
|
120 |
try: |
|
121 |
objects_tuple += (Image.objects.prefetch_related('annotations', 'item', 'stats').get(image_guid=kwargs.get('image_guid')),) |
|
122 |
except (ValueError, Image.DoesNotExist): |
|
123 |
return False, RedirectView.as_view(url=reverse('404error')) |
|
124 |
if 'annotation_guid' in kwargs.keys(): |
|
125 |
try: |
|
126 |
objects_tuple += (Annotation.objects.prefetch_related('current_revision', 'stats', 'image').get(annotation_guid=kwargs.get('annotation_guid')),) |
|
127 |
except (ValueError, Annotation.DoesNotExist): |
|
128 |
return False, RedirectView.as_view(url=reverse('404error')) |
|
129 |
if 'revision_guid' in kwargs.keys(): |
|
130 |
try: |
|
131 |
objects_tuple += (AnnotationRevision.objects.prefetch_related('parent_revision').get(revision_guid=kwargs.get('revision_guid')),) |
|
132 |
except (ValueError, AnnotationRevision.DoesNotExist): |
|
133 |
return False, RedirectView.as_view(url=reverse('404error')) |
|
134 |
return True, objects_tuple |
|
135 |
||
136 |
def get_pagination_data(self, list_to_paginate, page, perpage, adjacent_pages_count, perpage_range=[5, 10, 25, 100], trailing_qarg=""): |
|
137 |
""" |
|
138 |
Takes a queryset or a list and returns a dict with pagination data for display purposes |
|
139 |
||
140 |
Dict will be of the format: |
|
141 |
{ |
|
142 |
page: the page to load (integer) |
|
143 |
perpage_range: a list of the page links to display (list of integers) |
|
144 |
perpage: the item count per page (integer) |
|
145 |
perpage_range: a list of the perpage values to display next to the page list (list of integers) |
|
146 |
trailing_qarg: optional trailing qarg for the paginations links (used in collection home to remember the state of each list between page loads) (string) |
|
147 |
list: the item list to display (list of objects) |
|
148 |
show_first: used in template to display links, will be True if 1 is not in page_range |
|
149 |
show_last: used in template to display links, will be True if page_count is not in page_range |
|
150 |
ellipsis_first: used in template to display links, will be True if page_range starts at 3 or more |
|
151 |
ellipsis_last: used in template to display links, will be True if page_range ends at last_page - 2 or less |
|
152 |
||
153 |
} |
|
154 |
""" |
|
155 |
pagination_data = {} |
|
156 |
pagination_data["page"] = page |
|
157 |
pagination_data["perpage"] = perpage |
|
158 |
pagination_data["perpage_range"] = perpage_range |
|
159 |
pagination_data["trailing_qarg"] = trailing_qarg |
|
160 |
paginator = Paginator(list_to_paginate, perpage) |
|
161 |
try: |
|
162 |
pagination_data["list"] = paginator.page(page) |
|
163 |
except PageNotAnInteger: |
|
164 |
pagination_data["list"] = paginator.page(1) |
|
165 |
except EmptyPage: |
|
166 |
pagination_data["list"] = paginator.page(paginator.num_pages) |
|
167 |
pagination_data["page_range"] = [ |
|
168 |
n for n in \ |
|
169 |
range(page - adjacent_pages_count, page + adjacent_pages_count + 1) \ |
|
170 |
if n > 0 and n <= paginator.num_pages |
|
171 |
] |
|
172 |
pagination_data["show_first"] = page - adjacent_pages_count > 1 |
|
173 |
pagination_data["ellipsis_first"] = pagination_data["show_first"] and (page - adjacent_pages_count != 2) |
|
174 |
pagination_data["show_last"] = page + adjacent_pages_count < paginator.num_pages |
|
175 |
pagination_data["ellipsis_last"] = pagination_data["show_last"] and (page + adjacent_pages_count != paginator.num_pages - 1) |
|
176 |
return pagination_data |
|
177 |
||
178 |
class CollectionHomepageView(View, ContextMixin, IconolabObjectView): |
|
179 |
""" |
|
180 |
View that displays a collection and four panels to show relevant paginated lists for collection: |
|
181 |
* item lists |
|
182 |
* annotations ordered by creation date |
|
183 |
* annotations ordered by revisions count |
|
184 |
* annotations where a metacategory that notifies contributors was called |
|
185 |
""" |
|
186 |
def get(self, request, *args, **kwargs): |
|
187 |
""" |
|
188 |
Template is iconolab/collection_home.html |
|
189 |
||
190 |
Url args are: |
|
191 |
- collection_name: 'name' attribute of the requested collection |
|
192 |
||
193 |
Queryargs understood by the view are: |
|
194 |
- show : panel that will be shown on page load, one of ['items', 'recent', 'revised', 'contributions'], default to "items" |
|
195 |
- items_page : item list page to load |
|
196 |
- items_perpage : item count per page |
|
197 |
- recent_page : recent annotations list page to load |
|
198 |
- recent_perpage : recent annotations count per page |
|
199 |
- revised_page : most revised annotations list page to load |
|
200 |
- revised_perpage : most revised annotations count per page |
|
201 |
- contributions_page : annotations with the most contribution calls list page to load |
|
202 |
- contributions_perpage : annotations with the most contribution calls count per page for item list |
|
203 |
||
204 |
Context variables provided to the template are: |
|
205 |
- collection: the collection object for the requested collection |
|
206 |
- collection_name : the collection_name url arg |
|
207 |
- items_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the items list |
|
208 |
- recent_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the recent annotations list |
|
209 |
- revised_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the revised annotations list |
|
210 |
- contributions_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the contribution calls annotations list |
|
211 |
""" |
|
212 |
||
213 |
success, result = self.check_kwargs(kwargs) |
|
214 |
if success: |
|
215 |
(collection,) = result |
|
216 |
else: |
|
217 |
return result(request) |
|
218 |
context = super(CollectionHomepageView, self).get_context_data(**kwargs) |
|
219 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
220 |
context['collection'] = collection |
|
221 |
||
222 |
# get Pagination and navigation query args |
|
223 |
try: |
|
224 |
items_page = int(request.GET.get('items_page', '1')) |
|
225 |
except ValueError: |
|
226 |
items_page = 1 |
|
227 |
try: |
|
228 |
items_per_page = int(request.GET.get('items_perpage', '12')) |
|
229 |
except ValueError: |
|
230 |
items_per_page = 12 |
|
231 |
||
232 |
try: |
|
233 |
recent_page = int(request.GET.get('recent_page', '1')) |
|
234 |
except ValueError: |
|
235 |
recent_page = 1 |
|
236 |
try: |
|
237 |
recent_per_page = int(request.GET.get('recent_perpage', '10')) |
|
238 |
except ValueError: |
|
239 |
recent_per_page = 10 |
|
240 |
||
241 |
try: |
|
242 |
revised_page = int(request.GET.get('revised_page', '1')) |
|
243 |
except ValueError: |
|
244 |
revised_page = 1 |
|
245 |
try: |
|
246 |
revised_per_page = int(request.GET.get('revised_perpage', '10')) |
|
247 |
except ValueError: |
|
248 |
revised_per_page = 10 |
|
249 |
||
250 |
try: |
|
251 |
contributions_page = int(request.GET.get('contributions_page', '1')) |
|
252 |
except ValueError: |
|
253 |
contributions_page = 1 |
|
254 |
try: |
|
255 |
contributions_per_page = int(request.GET.get('contributions_perpage', '10')) |
|
256 |
except ValueError: |
|
257 |
contributions_per_page = 10 |
|
258 |
||
259 |
active_list = request.GET.get('show', 'items') |
|
260 |
if active_list not in ['items', 'recent', 'revised', 'contributions']: |
|
261 |
active_list = 'items' |
|
262 |
context["active_list"] = active_list |
|
263 |
||
264 |
||
265 |
# Pagination values |
|
266 |
adjacent_pages_count = 2 |
|
267 |
||
268 |
# Paginated objects list |
|
|
538
5cc429500a11
Remove specific metadatas and add specific metadatas fields to model
Riwad Salim
parents:
532
diff
changeset
|
269 |
items_list = collection.items.order_by("metadatas__natural_key").prefetch_related('images', 'images__stats') |
| 416 | 270 |
|
271 |
folder = request.GET.get('folder', None) |
|
272 |
||
273 |
if folder is not None: |
|
|
467
5d0879ffa7de
Use folder GUID instead of primary key.
Alexandre Segura <mex.zktk@gmail.com>
parents:
465
diff
changeset
|
274 |
items_list = items_list.filter(folders__folder_guid=folder) |
|
486
869bb212631a
Add link to show selected folder below collection title.
Alexandre Segura <mex.zktk@gmail.com>
parents:
482
diff
changeset
|
275 |
context['folder_name'] = Folder.objects.get(folder_guid=folder).name |
| 416 | 276 |
|
|
467
5d0879ffa7de
Use folder GUID instead of primary key.
Alexandre Segura <mex.zktk@gmail.com>
parents:
465
diff
changeset
|
277 |
context['folder_guid'] = folder |
| 416 | 278 |
|
| 491 | 279 |
items_pagination_args = '&'.join([ |
280 |
"recent_page="+str(recent_page), |
|
281 |
"recent_perpage="+str(recent_per_page), |
|
282 |
"revised_page="+str(revised_page), |
|
283 |
"revised_perpage="+str(revised_per_page), |
|
284 |
"contributions_page="+str(contributions_page), |
|
285 |
"contributions_perpage="+str(contributions_per_page) |
|
286 |
]) |
|
287 |
||
288 |
if folder is not None: |
|
289 |
items_pagination_args += "&folder=" + folder |
|
290 |
||
| 298 | 291 |
context["items_pagination_data"] = self.get_pagination_data( |
| 416 | 292 |
items_list.all(), |
| 298 | 293 |
items_page, |
294 |
items_per_page, |
|
295 |
adjacent_pages_count, |
|
296 |
perpage_range=[6, 12, 48, 192], |
|
| 491 | 297 |
trailing_qarg=items_pagination_args |
| 298 | 298 |
) |
299 |
||
300 |
# Paginated recent annotations list |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
301 |
recent_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).select_related('image', 'author').prefetch_related( |
| 298 | 302 |
'current_revision', |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
303 |
'stats', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
304 |
'stats__contributors' |
| 298 | 305 |
).order_by('-current_revision__created') |
306 |
context["recent_pagination_data"] = self.get_pagination_data( |
|
307 |
recent_annotations, |
|
308 |
recent_page, |
|
309 |
recent_per_page, |
|
310 |
adjacent_pages_count, |
|
311 |
trailing_qarg="&items_page="+str(items_page) |
|
312 |
+"&items_perpage="+str(items_per_page) |
|
313 |
+"&revised_page="+str(revised_page) |
|
314 |
+"&revised_perpage="+str(revised_per_page) |
|
315 |
+"&contributions_page="+str(contributions_page) |
|
316 |
+"&contributions_perpage="+str(contributions_per_page) |
|
317 |
) |
|
318 |
||
319 |
# Paginated revised annotations list |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
320 |
revised_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).select_related('image', 'author').prefetch_related( |
| 298 | 321 |
'current_revision', |
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
322 |
'stats', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
323 |
'stats__contributors' |
| 298 | 324 |
).annotate(revision_count=Count('revisions')).order_by('-revision_count') |
325 |
context["revised_pagination_data"] = self.get_pagination_data( |
|
326 |
revised_annotations, |
|
327 |
revised_page, |
|
328 |
revised_per_page, |
|
329 |
adjacent_pages_count, |
|
330 |
trailing_qarg="&items_page="+str(items_page) |
|
331 |
+"&items_perpage="+str(items_per_page) |
|
332 |
+"&recent_page="+str(recent_page) |
|
333 |
+"&recent_perpage="+str(recent_per_page) |
|
334 |
+"&contributions_page="+str(contributions_page) |
|
335 |
+"&contributions_perpage="+str(contributions_per_page) |
|
336 |
) |
|
337 |
||
338 |
# Paginated contribution calls annotation list |
|
339 |
contrib_calls_annotations_ids = list(set(MetaCategoryInfo.objects.filter( |
|
340 |
metacategory__collection__name=collection.name, |
|
341 |
metacategory__triggers_notifications=MetaCategory.CONTRIBUTORS |
|
342 |
).order_by('comment__submit_date').values_list('comment__object_pk', flat=True))) |
|
|
526
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
343 |
collection_annotations = \ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
344 |
Annotation.objects.filter(id__in=contrib_calls_annotations_ids)\ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
345 |
.select_related('image', 'current_revision')\ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
346 |
.prefetch_related( |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
347 |
'stats', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
348 |
'stats__contributors', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
349 |
Prefetch( |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
350 |
'current_revision__tagginginfo_set', |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
351 |
queryset=TaggingInfo.objects.select_related('tag') |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
352 |
) |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
353 |
)\ |
|
6c879e963a93
Optimization: reduce the total number of queries for home and collection home
ymh <ymh.work@gmail.com>
parents:
523
diff
changeset
|
354 |
.all() |
| 298 | 355 |
collection_ann_dict = dict([(str(annotation.id), annotation) for annotation in collection_annotations]) |
356 |
contributions_annotations = [collection_ann_dict[id] for id in contrib_calls_annotations_ids] |
|
357 |
context["contributions_pagination_data"] = self.get_pagination_data( |
|
358 |
contributions_annotations, |
|
359 |
contributions_page, |
|
360 |
contributions_per_page, |
|
361 |
adjacent_pages_count, |
|
362 |
trailing_qarg="&items_page="+str(items_page) |
|
363 |
+"&items_perpage="+str(items_per_page) |
|
364 |
+"&recent_page="+str(recent_page) |
|
365 |
+"&recent_perpage="+str(recent_per_page) |
|
366 |
+"&revised_page="+str(revised_page) |
|
367 |
+"&revised_perpage="+str(revised_per_page) |
|
368 |
) |
|
369 |
||
|
506
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
370 |
context['bookmark_form'] = BookmarkForm(user=request.user) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
371 |
|
| 298 | 372 |
return render(request, 'iconolab/collection_home.html', context) |
373 |
||
374 |
||
375 |
||
376 |
class ShowItemView(View, ContextMixin, IconolabObjectView): |
|
377 |
""" |
|
378 |
View that displays informations on an item with associated metadatas and stats. Also displays images and annotation list for each image. |
|
379 |
""" |
|
380 |
def get(self, request, *args, **kwargs): |
|
381 |
""" |
|
382 |
Template is iconolab/item_detail.html |
|
383 |
||
384 |
Url args are: |
|
385 |
- collection_name : name of the collection |
|
386 |
- item_guid: 'item_guid' attribute of the requested item |
|
387 |
||
388 |
Queryargs understood by the view are: |
|
389 |
- show: image_guid for the image to show on load |
|
390 |
- page: annotation list page on load for displayed image |
|
391 |
- perpage: annotation count per page on load for displayed image |
|
392 |
||
393 |
Context variables provided to the template are: |
|
394 |
- collection_name : the collection_name url arg |
|
395 |
- item_guid: the item_guid url arg |
|
396 |
- collection: the collection object for the requested collection |
|
397 |
- item: the item object for the requested item |
|
398 |
- display_image: the image_guid for the image to display on load |
|
399 |
- images: a list of dict for the item images data in the format: |
|
400 |
{ |
|
401 |
'obj': the image object, |
|
402 |
'annotations': the list of annotations on that image |
|
403 |
} |
|
404 |
""" |
|
405 |
||
406 |
success, result = self.check_kwargs(kwargs) |
|
|
323
55c024fc7c60
Roughly implement annotation navigator.
Alexandre Segura <mex.zktk@gmail.com>
parents:
298
diff
changeset
|
407 |
|
| 298 | 408 |
if success: |
409 |
(collection, item) = result |
|
410 |
else: |
|
411 |
return result(request) |
|
412 |
||
413 |
context = super(ShowItemView, self).get_context_data(**kwargs) |
|
414 |
image_guid_to_display = request.GET.get("show", str(item.images.first().image_guid)) |
|
415 |
if image_guid_to_display not in [str(guid) for guid in item.images.all().values_list("image_guid", flat=True)]: |
|
416 |
image_guid_to_display = str(item.images.first().image_guid) |
|
417 |
context['display_image'] = image_guid_to_display |
|
418 |
try: |
|
419 |
displayed_annotations_page = int(request.GET.get('page', '1')) |
|
420 |
except ValueError: |
|
421 |
displayed_annotations_page = 1 |
|
422 |
try: |
|
423 |
displayed_annotations_per_page = int(request.GET.get('perpage', '10')) |
|
424 |
except ValueError: |
|
425 |
displayed_annotations_per_page = 10 |
|
426 |
||
427 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
428 |
context['item_guid'] = self.kwargs.get('image_guid', '') |
|
429 |
context['collection'] = collection |
|
430 |
context['item'] = item |
|
431 |
context['images'] = [] |
|
432 |
for image in item.images.all(): |
|
433 |
if str(image.image_guid) == image_guid_to_display: |
|
434 |
page = displayed_annotations_page |
|
435 |
per_page = displayed_annotations_per_page |
|
436 |
else: |
|
437 |
page = 1 |
|
438 |
per_page = 10 |
|
|
543
2c172934dae2
Remove specific import commands and alerts from generic app
Riwad Salim
parents:
538
diff
changeset
|
439 |
annotations_paginator = Paginator(image.annotations.all().order_by('created'), per_page) |
| 298 | 440 |
try: |
441 |
annotations = annotations_paginator.page(page) |
|
442 |
except PageNotAnInteger: |
|
443 |
annotations = annotations_paginator.page(1) |
|
444 |
except EmptyPage: |
|
445 |
annotations = annotations_paginator.page(recent_paginator.num_pages) |
|
446 |
context['images'].append({ |
|
447 |
'obj' : image, |
|
448 |
'annotations': annotations |
|
449 |
}) |
|
450 |
image.stats.views_count += 1 |
|
451 |
image.stats.save() |
|
452 |
return render(request, 'iconolab/detail_item.html', context); |
|
453 |
||
454 |
class ShowImageView(View, ContextMixin, IconolabObjectView): |
|
455 |
""" |
|
456 |
View that only displays an image and the associated annotations |
|
457 |
""" |
|
458 |
def get(self, request, *args, **kwargs): |
|
459 |
success, result = self.check_kwargs(kwargs) |
|
460 |
if success: |
|
461 |
(collection, image) = result |
|
462 |
else: |
|
463 |
return result(request) |
|
464 |
context = super(ShowImageView, self).get_context_data(**kwargs) |
|
465 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
466 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
467 |
context['collection'] = collection |
|
468 |
context['image'] = image |
|
|
407
74e0a5ea614a
Display item metadata below image.
Alexandre Segura <mex.zktk@gmail.com>
parents:
376
diff
changeset
|
469 |
context['item'] = image.item |
|
323
55c024fc7c60
Roughly implement annotation navigator.
Alexandre Segura <mex.zktk@gmail.com>
parents:
298
diff
changeset
|
470 |
context['form'] = AnnotationRevisionForm() |
| 298 | 471 |
return render(request, 'iconolab/detail_image.html', context) |
472 |
||
|
506
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
473 |
class BookmarkImageView(View, ContextMixin, IconolabObjectView): |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
474 |
def post(self, request, *args, **kwargs): |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
475 |
success, result = self.check_kwargs(kwargs) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
476 |
if success: |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
477 |
(collection, image) = result |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
478 |
else: |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
479 |
return result(request) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
480 |
|
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
481 |
context = super(BookmarkImageView, self).get_context_data(**kwargs) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
482 |
|
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
483 |
bookmark_form = BookmarkForm(request.POST, user=request.user) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
484 |
if bookmark_form.is_valid(): |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
485 |
bookmark = Bookmark( |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
486 |
image=image, |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
487 |
category=bookmark_form.cleaned_data['category'] |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
488 |
) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
489 |
bookmark.save() |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
490 |
|
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
491 |
context['bookmark_form'] = bookmark_form |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
492 |
|
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
493 |
redirect_url = reverse('collection_home', kwargs={'collection_name': self.kwargs.get('collection_name', '')}) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
494 |
|
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
495 |
return redirect(redirect_url) |
|
4e18e1f69db9
Introduce bookmarks feature.
Alexandre Segura <mex.zktk@gmail.com>
parents:
491
diff
changeset
|
496 |
|
| 298 | 497 |
class CreateAnnotationView(View, ContextMixin, IconolabObjectView): |
498 |
""" |
|
499 |
View that displays annotation forms and handles annotation creation |
|
500 |
""" |
|
501 |
def get_context_data(self, **kwargs): |
|
502 |
context = super(CreateAnnotationView, self).get_context_data(**kwargs) |
|
503 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
504 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
505 |
return context |
|
506 |
||
507 |
def get(self, request, *args, **kwargs): |
|
508 |
success, result = self.check_kwargs(kwargs) |
|
509 |
if success: |
|
510 |
(collection, image,) = result |
|
511 |
else: |
|
512 |
return result(request) |
|
513 |
annotation_form = AnnotationRevisionForm() |
|
514 |
context = self.get_context_data(**kwargs) |
|
515 |
context['image'] = image |
|
516 |
context['form'] = annotation_form |
|
517 |
context['tags_data'] = '[]' |
|
518 |
return render(request, 'iconolab/change_annotation.html', context) |
|
519 |
||
520 |
def post(self, request, *args, **kwargs): |
|
521 |
success, result = self.check_kwargs(kwargs) |
|
522 |
if success: |
|
523 |
(collection, image) = result |
|
524 |
else: |
|
525 |
return result(request) |
|
526 |
collection_name = kwargs['collection_name'] |
|
527 |
image_guid = kwargs['image_guid'] |
|
528 |
annotation_form = AnnotationRevisionForm(request.POST) |
|
529 |
if annotation_form.is_valid(): |
|
530 |
author = request.user |
|
531 |
title = annotation_form.cleaned_data['title'] |
|
532 |
description = annotation_form.cleaned_data['description'] |
|
533 |
fragment = annotation_form.cleaned_data['fragment'] |
|
534 |
tags_json = annotation_form.cleaned_data['tags'] |
|
535 |
new_annotation = Annotation.objects.create_annotation(author, image, title=title, description=description, fragment=fragment, tags_json=tags_json) |
|
|
323
55c024fc7c60
Roughly implement annotation navigator.
Alexandre Segura <mex.zktk@gmail.com>
parents:
298
diff
changeset
|
536 |
redirect_url = reverse('image_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid}) |
|
343
6f901f3b1510
Redirect to annotation using hash.
Alexandre Segura <mex.zktk@gmail.com>
parents:
337
diff
changeset
|
537 |
return redirect(redirect_url + '#' + str(new_annotation.annotation_guid)) |
| 298 | 538 |
context = self.get_context_data(**kwargs) |
539 |
context['image'] = image |
|
540 |
context['form'] = annotation_form |
|
541 |
context['tags_data'] = '[]' |
|
542 |
return render(request, 'iconolab/change_annotation.html', context) |
|
543 |
||
544 |
class ShowAnnotationView(View, ContextMixin, IconolabObjectView): |
|
|
470
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
545 |
def get(self, request, *args, **kwargs): |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
546 |
success, result = self.check_kwargs(kwargs) |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
547 |
if success: |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
548 |
(collection, image, annotation) = result |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
549 |
else: |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
550 |
return result(request) |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
551 |
context = super(ShowAnnotationView, self).get_context_data(**kwargs) |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
552 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
553 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
554 |
context['collection'] = collection |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
555 |
context['image'] = image |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
556 |
context['item'] = image.item |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
557 |
context['annotation'] = annotation |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
558 |
context['form'] = AnnotationRevisionForm() |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
559 |
return render(request, 'iconolab/detail_image.html', context) |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
560 |
|
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
561 |
class ShowAnnotationViewOld(View, ContextMixin, IconolabObjectView): |
| 298 | 562 |
""" |
563 |
View that show a given annotation with the corresponding data, links to |
|
564 |
submit new revisions and the paginated comments thread. |
|
565 |
""" |
|
566 |
||
567 |
||
568 |
def get_context_data(self, **kwargs): |
|
| 479 | 569 |
context = super(ShowAnnotationViewOld, self).get_context_data(**kwargs) |
| 298 | 570 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
571 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
572 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
573 |
return context |
|
574 |
||
575 |
def get(self, request, *args, **kwargs): |
|
576 |
""" |
|
577 |
Template is iconolab/detail_annotations.html |
|
578 |
||
579 |
Url args are: |
|
580 |
- collection_name: 'name' attribute of the requested collection |
|
581 |
- item_guid: 'item_guid' attribute of the requested item |
|
582 |
- annotation_guid: 'annotation_guid' attribute of the requested annotation |
|
583 |
||
584 |
Queryargs understood by the view are: |
|
585 |
- page: comment thread page on load |
|
586 |
- perpage: comment count per page on load |
|
587 |
||
588 |
Context variables provided to the template are: |
|
589 |
- collection: the collection object for the requested collection |
|
590 |
- image: the image object for the requested image |
|
591 |
- annotation: the annotation object for the requested annotation |
|
592 |
- tags_data: a json string describing tags for the annotation current revision |
|
593 |
- comments: the paginated comments list for the annotation according page and perpage queryargs |
|
594 |
- notification_comments_ids: the ids of the comments that are referenced by a notification for the authenticated user; This allows |
|
595 |
us to highlight comments that triggered a notification in the page |
|
596 |
""" |
|
597 |
success, result = self.check_kwargs(kwargs) |
|
598 |
if success: |
|
599 |
(collection, image, annotation,) = result |
|
600 |
else: |
|
601 |
return result(request) |
|
602 |
context = self.get_context_data(**kwargs) |
|
603 |
context['collection'] = collection |
|
604 |
context['image'] = image |
|
605 |
context['annotation'] = annotation |
|
606 |
context['tags_data'] = annotation.current_revision.get_tags_json() |
|
607 |
||
608 |
page = request.GET.get('page', 1) |
|
609 |
per_page = request.GET.get('perpage', 10) |
|
610 |
full_comments_list = IconolabComment.objects.for_app_models('iconolab.annotation').filter(object_pk = annotation.pk).order_by('thread_id', '-order') |
|
611 |
paginator = Paginator(full_comments_list, per_page) |
|
612 |
try: |
|
613 |
comments_list = paginator.page(page) |
|
614 |
except PageNotAnInteger: |
|
615 |
comments_list = paginator.page(1) |
|
616 |
except EmptyPage: |
|
617 |
comments_list = paginator.page(paginator.num_pages) |
|
618 |
context['comments'] = comments_list |
|
619 |
||
|
532
a301e0bc677b
refresh dependencies version, and make it work for Django 2.0
ymh <ymh.work@gmail.com>
parents:
526
diff
changeset
|
620 |
if request.user.is_authenticated: |
| 298 | 621 |
user_comment_notifications = Notification.objects.filter( |
622 |
recipient=request.user, |
|
623 |
action_object_content_type__app_label='iconolab', |
|
624 |
action_object_content_type__model='iconolabcomment', |
|
625 |
target_content_type__app_label='iconolab', |
|
626 |
target_content_type__model='annotation', |
|
627 |
target_object_id=annotation.id |
|
628 |
).unread() |
|
629 |
context['notifications_comments_ids'] = [int(val) for val in user_comment_notifications.values_list('action_object_object_id', flat=True)] |
|
630 |
comment_list_ids = [comment.id for comment in context['comments'] ] |
|
631 |
for notification in user_comment_notifications.all(): |
|
632 |
if int(notification.action_object_object_id) in comment_list_ids: |
|
633 |
notification.mark_as_read() |
|
634 |
||
635 |
image.stats.views_count += 1 |
|
636 |
image.stats.save() |
|
637 |
annotation.stats.views_count += 1 |
|
638 |
annotation.stats.save() |
|
639 |
return render(request, 'iconolab/detail_annotation.html', context) |
|
640 |
||
|
482
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
641 |
class ShowRevisionsView(View, ContextMixin, IconolabObjectView): |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
642 |
def get_context_data(self, **kwargs): |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
643 |
context = super(ShowRevisionsView, self).get_context_data(**kwargs) |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
644 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
645 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
646 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
647 |
return context |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
648 |
|
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
649 |
def get(self, request, *args, **kwargs): |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
650 |
success, result = self.check_kwargs(kwargs) |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
651 |
if success: |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
652 |
(collection, image, annotation,) = result |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
653 |
else: |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
654 |
return result(request) |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
655 |
|
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
656 |
context = self.get_context_data(**kwargs) |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
657 |
context['collection'] = collection |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
658 |
context['image'] = image |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
659 |
context['annotation'] = annotation |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
660 |
|
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
661 |
context['revisions'] = AnnotationRevision.objects.filter(annotation=annotation).order_by('-created') |
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
662 |
|
|
b71475c27159
Add page with list of revisions.
Alexandre Segura <mex.zktk@gmail.com>
parents:
479
diff
changeset
|
663 |
return render(request, 'iconolab/annotation_revisions.html', context) |
| 298 | 664 |
|
665 |
class ReadonlyAnnotationView(View, ContextMixin, IconolabObjectView): |
|
666 |
""" |
|
667 |
Same view as ShowAnnotationView but without the comments and links to the forms |
|
668 |
""" |
|
669 |
def get_context_data(self, **kwargs): |
|
670 |
context = super(ReadonlyAnnotationView, self).get_context_data(**kwargs) |
|
671 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
672 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
673 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
674 |
return context |
|
675 |
||
676 |
def get(self, request, *args, **kwargs): |
|
677 |
""" |
|
678 |
Exactly the same as ShowAnnotationView but without all the data around comments |
|
679 |
""" |
|
680 |
success, result = self.check_kwargs(kwargs) |
|
681 |
if success: |
|
682 |
(collection, image, annotation,) = result |
|
683 |
else: |
|
684 |
return result(request) |
|
685 |
context = self.get_context_data(**kwargs) |
|
686 |
context['collection'] = collection |
|
687 |
context['image'] = image |
|
688 |
context['annotation'] = annotation |
|
689 |
context['tags_data'] = annotation.current_revision.get_tags_json() |
|
690 |
||
691 |
image.stats.views_count += 1 |
|
692 |
image.stats.save() |
|
693 |
annotation.stats.views_count += 1 |
|
694 |
annotation.stats.save() |
|
695 |
return render(request, 'iconolab/detail_annotation_readonly.html', context) |
|
696 |
||
697 |
class EditAnnotationView(View, ContextMixin, IconolabObjectView): |
|
698 |
""" |
|
699 |
View that handles displaying the edition form and editing an annotation |
|
700 |
""" |
|
701 |
def get_context_data(self, **kwargs): |
|
702 |
context = super(EditAnnotationView, self).get_context_data(**kwargs) |
|
703 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
704 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
705 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
706 |
return context |
|
707 |
||
708 |
def get(self, request, *args, **kwargs): |
|
709 |
success, result = self.check_kwargs(kwargs) |
|
710 |
if success: |
|
711 |
(collection, image, annotation,) = result |
|
712 |
else: |
|
713 |
return result(request) |
|
714 |
annotation_form = AnnotationRevisionForm(instance=annotation.current_revision) |
|
715 |
context = self.get_context_data(**kwargs) |
|
716 |
context['image'] = image |
|
717 |
context['annotation'] = annotation |
|
718 |
context['form'] = annotation_form |
|
719 |
context['tags_data'] = annotation.current_revision.get_tags_json() |
|
720 |
return render(request, 'iconolab/change_annotation.html', context) |
|
721 |
||
722 |
def post(self, request, *args, **kwargs): |
|
723 |
success, result = self.check_kwargs(kwargs) |
|
724 |
if success: |
|
725 |
(collection, image, annotation) = result |
|
726 |
else: |
|
727 |
return result(request) |
|
728 |
collection_name = kwargs['collection_name'] |
|
729 |
image_guid = kwargs['image_guid'] |
|
730 |
annotation_guid = kwargs['annotation_guid'] |
|
731 |
annotation_form = AnnotationRevisionForm(request.POST) |
|
732 |
if annotation_form.is_valid(): |
|
733 |
revision_author = request.user |
|
734 |
revision_title = annotation_form.cleaned_data['title'] |
|
735 |
revision_description = annotation_form.cleaned_data['description'] |
|
736 |
revision_fragment = annotation_form.cleaned_data['fragment'] |
|
737 |
revision_tags_json = annotation_form.cleaned_data['tags'] |
|
738 |
new_revision = annotation.make_new_revision(revision_author, revision_title, revision_description, revision_fragment, revision_tags_json) |
|
|
461
4701ee4556e3
Display message when revision needs approval.
Alexandre Segura <mex.zktk@gmail.com>
parents:
416
diff
changeset
|
739 |
|
|
4701ee4556e3
Display message when revision needs approval.
Alexandre Segura <mex.zktk@gmail.com>
parents:
416
diff
changeset
|
740 |
if (annotation.author != revision_author): |
| 465 | 741 |
messages.add_message(request, messages.INFO, "Votre modification a été prise en compte. Le créateur de l'annotation a été notifié.") |
|
461
4701ee4556e3
Display message when revision needs approval.
Alexandre Segura <mex.zktk@gmail.com>
parents:
416
diff
changeset
|
742 |
|
|
470
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
743 |
redirect_url = reverse('annotation_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid, 'annotation_guid': str(annotation.annotation_guid)}) |
|
6c43539e5c67
Use browser history instead of hash for annotation URL.
Alexandre Segura <mex.zktk@gmail.com>
parents:
467
diff
changeset
|
744 |
return redirect(redirect_url) |
| 298 | 745 |
context = self.get_context_data(**kwargs) |
746 |
context['image'] = image |
|
747 |
context['form'] = annotation_form |
|
748 |
context['annotation'] = annotation |
|
749 |
context['tags_data'] = annotation.current_revision.get_tags_json() |
|
750 |
return render(request, 'iconolab/change_annotation.html', context) |
|
751 |
||
752 |
||
753 |
class ShowRevisionView(View, ContextMixin, IconolabObjectView): |
|
754 |
""" |
|
755 |
View that displays a given revision with its associated data and comment |
|
756 |
""" |
|
757 |
def get_context_data(self, **kwargs): |
|
758 |
context = super(ShowRevisionView, self).get_context_data(**kwargs) |
|
759 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
760 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
761 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
762 |
context['revision_guid'] = self.kwargs.get('revision_guid', '') |
|
763 |
return context |
|
764 |
||
765 |
def get(self, request, *args, **kwargs): |
|
766 |
""" |
|
767 |
Template is iconolab/detail_annotations.html |
|
768 |
||
769 |
Url args are: |
|
770 |
- collection_name: 'name' attribute of the requested collection |
|
771 |
- item_guid: 'item_guid' attribute of the requested item |
|
772 |
- annotation_guid: 'annotation_guid' attribute of the requested annotation |
|
773 |
- revision_guid: 'revision_guid' attribute of the requested revision |
|
774 |
||
775 |
Context variables provided to the template are: |
|
776 |
- collection: the collection object for the requested collection |
|
777 |
- image: the image object for the requested image |
|
778 |
- annotation: the annotation object for the requested annotation |
|
779 |
- revision: the revision object for the requested annotation |
|
780 |
- tags_data: a json string describing tags for the annotation current revision |
|
781 |
- comment: the comment that was posted alongside the revision |
|
782 |
- notified_revision: if True, the revision is linked from one or more unread notifications for the |
|
783 |
current user, allowing us to highlight it in the template. |
|
784 |
""" |
|
785 |
success, result = self.check_kwargs(kwargs) |
|
786 |
if success: |
|
787 |
(collection, image, annotation, revision,) = result |
|
788 |
else: |
|
789 |
return result(request) |
|
790 |
context = self.get_context_data(**kwargs) |
|
791 |
context['collection'] = collection |
|
792 |
context['image'] = image |
|
793 |
context['annotation'] = annotation |
|
794 |
context['revision'] = revision |
|
795 |
context['tags_data'] = revision.get_tags_json() |
|
796 |
context['comment'] = revision.creation_comment.first() |
|
|
532
a301e0bc677b
refresh dependencies version, and make it work for Django 2.0
ymh <ymh.work@gmail.com>
parents:
526
diff
changeset
|
797 |
if request.user.is_authenticated and annotation.author == request.user: |
| 298 | 798 |
ann_author_notified = Notification.objects.filter( |
799 |
recipient=request.user, |
|
800 |
action_object_content_type__app_label='iconolab', |
|
801 |
action_object_content_type__model='annotationrevision', |
|
802 |
action_object_object_id=revision.id, |
|
803 |
target_content_type__app_label='iconolab', |
|
804 |
target_content_type__model='annotation', |
|
805 |
target_object_id=annotation.id |
|
806 |
).unread() |
|
807 |
if ann_author_notified: |
|
808 |
ann_author_notified.first().mark_as_read() |
|
809 |
context['notified_revision'] = True |
|
|
532
a301e0bc677b
refresh dependencies version, and make it work for Django 2.0
ymh <ymh.work@gmail.com>
parents:
526
diff
changeset
|
810 |
if request.user.is_authenticated and revision.author == request.user: |
| 298 | 811 |
rev_author_notified = Notification.objects.filter( |
812 |
recipient=request.user, |
|
813 |
action_object_content_type__app_label='iconolab', |
|
814 |
action_object_content_type__model='annotationrevision', |
|
815 |
action_object_object_id=revision.id, |
|
816 |
target_content_type__app_label='iconolab', |
|
817 |
target_content_type__model='annotation', |
|
818 |
target_object_id=annotation.id |
|
819 |
).unread() |
|
820 |
if rev_author_notified: |
|
821 |
rev_author_notified.first().mark_as_read() |
|
822 |
context['notified_revision'] = True |
|
823 |
return render(request, 'iconolab/detail_revision.html', context) |
|
824 |
||
825 |
||
826 |
class MergeProposalView(View, ContextMixin, IconolabObjectView): |
|
827 |
""" |
|
828 |
View that displays the merge form, used when a user wants to "study" a revision because it was submitted from an older revision than the current revision (thus |
|
829 |
the two revisions don't have the same parents and there is a conflict) |
|
830 |
""" |
|
831 |
def get_context_data(self, **kwargs): |
|
832 |
context = super(MergeProposalView, self).get_context_data(**kwargs) |
|
833 |
context['collection_name'] = self.kwargs.get('collection_name', '') |
|
834 |
context['image_guid'] = self.kwargs.get('image_guid', '') |
|
835 |
context['annotation_guid'] = self.kwargs.get('annotation_guid', '') |
|
836 |
context['revision_guid'] = self.kwargs.get('revision_guid', '') |
|
837 |
return context |
|
838 |
||
839 |
def get(self, request, *args, **kwargs): |
|
840 |
success, result = self.check_kwargs(kwargs) |
|
841 |
if success: |
|
842 |
(collection, image, annotation, revision,) = result |
|
843 |
else: |
|
844 |
return result(request) |
|
845 |
# Only show merge form if there is a revision to merge AND the current user is the annotation author |
|
846 |
if revision.state != AnnotationRevision.AWAITING or request.user != annotation.author: |
|
847 |
return RedirectView.as_view( |
|
848 |
url=reverse('revision_detail', |
|
849 |
kwargs={ |
|
850 |
'collection_name': collection.name, |
|
851 |
'image_guid': image.image_guid, |
|
852 |
'annotation_guid': annotation.annotation_guid, |
|
853 |
'revision_guid': revision.revision_guid |
|
854 |
} |
|
855 |
) |
|
856 |
)(request) |
|
857 |
# Auto-accepts the revision only if the proper query arg is set and only if the revision parent is the current revision |
|
858 |
if 'auto_accept' in request.GET and request.GET['auto_accept'] in ['True', 'true', '1', 'yes'] and revision.parent_revision == annotation.current_revision: |
|
859 |
annotation.validate_existing_revision(revision) |
|
860 |
return RedirectView.as_view( |
|
861 |
url=reverse('annotation_detail', |
|
862 |
kwargs={ |
|
863 |
'collection_name': collection.name, |
|
864 |
'image_guid': image.image_guid, |
|
865 |
'annotation_guid': annotation.annotation_guid |
|
866 |
} |
|
867 |
) |
|
868 |
)(request) |
|
869 |
# Auto-reject the revision only if the proper query arg is set |
|
870 |
if 'auto_reject' in request.GET and request.GET['auto_reject'] in ['True', 'true', '1', 'yes']: |
|
871 |
annotation.reject_existing_revision(revision) |
|
872 |
return RedirectView.as_view( |
|
873 |
url=reverse('annotation_detail', |
|
874 |
kwargs={ |
|
875 |
'collection_name': collection.name, |
|
876 |
'image_guid': image.image_guid, |
|
877 |
'annotation_guid': annotation.annotation_guid |
|
878 |
} |
|
879 |
) |
|
880 |
)(request) |
|
881 |
||
882 |
context = self.get_context_data(**kwargs) |
|
883 |
context['collection'] = collection |
|
884 |
context['image'] = image |
|
885 |
context['annotation'] = annotation |
|
886 |
# Proposal data |
|
887 |
context['proposal_revision'] = revision |
|
888 |
context['proposal_tags_data'] = revision.get_tags_json() |
|
889 |
context['proposal_comment'] = revision.creation_comment.first() |
|
890 |
# Parent data |
|
891 |
context['parent_revision'] = revision.parent_revision |
|
892 |
context['parent_tags_data'] = revision.parent_revision.get_tags_json() |
|
893 |
context['parent_comment'] = revision.parent_revision.creation_comment.first() |
|
894 |
# Current data |
|
895 |
context['current_revision'] = annotation.current_revision |
|
896 |
context['current_tags_data'] = annotation.current_revision.get_tags_json() |
|
897 |
context['current_comment'] = annotation.current_revision.creation_comment.first() |
|
898 |
||
899 |
merge_form = AnnotationRevisionForm(instance=revision) |
|
900 |
context['merge_form'] = merge_form |
|
901 |
return render(request, 'iconolab/merge_revision.html', context) |
|
902 |
||
903 |
def post(self, request, *args, **kwargs): |
|
904 |
# Handle merge form submit here |
|
905 |
success, result = self.check_kwargs(kwargs) |
|
906 |
if success: |
|
907 |
(collection, image, annotation, revision) = result |
|
908 |
else: |
|
909 |
return result(request) |
|
910 |
collection_name = kwargs['collection_name'] |
|
911 |
image_guid = kwargs['image_guid'] |
|
912 |
annotation_guid = kwargs['annotation_guid'] |
|
913 |
revision_guid = kwargs['revision_guid'] |
|
914 |
||
915 |
merge_revision_form = AnnotationRevisionForm(request.POST) |
|
916 |
if merge_revision_form.is_valid(): |
|
917 |
revision_title = merge_revision_form.cleaned_data['title'] |
|
918 |
revision_description = merge_revision_form.cleaned_data['description'] |
|
919 |
revision_fragment = merge_revision_form.cleaned_data['fragment'] |
|
920 |
revision_tags_json = merge_revision_form.cleaned_data['tags'] |
|
921 |
new_revision = annotation.merge_existing_revision(revision_title, revision_description, revision_fragment, revision_tags_json, revision) |
|
922 |
revision_comment = merge_revision_form.cleaned_data['comment'] |
|
923 |
comment = IconolabComment.objects.create( |
|
924 |
comment = revision_comment, |
|
925 |
revision = new_revision, |
|
926 |
content_type = ContentType.objects.get(app_label='iconolab', model='annotation'), |
|
927 |
content_object = annotation, |
|
928 |
site = Site.objects.get(id=settings.SITE_ID), |
|
929 |
object_pk = annotation.id, |
|
930 |
user = request.user, |
|
931 |
user_name = request.user.username |
|
932 |
) |
|
933 |
return RedirectView.as_view(url=reverse('annotation_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid, 'annotation_guid': annotation_guid}))(request) |
|
934 |
context = self.get_context_data(**kwargs) |
|
935 |
context['image'] = image |
|
936 |
context['merge_form'] = merge_revision_form |
|
937 |
context['annotation'] = annotation |
|
938 |
# Proposal data |
|
939 |
context['proposal_revision'] = revision |
|
940 |
context['proposal_tags_data'] = revision.get_tags_json() |
|
941 |
context['proposal_comment'] = revision.creation_comment.first() |
|
942 |
# Parent data |
|
943 |
context['parent_revision'] = revision.parent_revision |
|
944 |
context['parent_tags_data'] = revision.parent_revision.get_tags_json() |
|
945 |
context['parent_comment'] = revision.parent_revision.creation_comment.first() |
|
946 |
# Current data |
|
947 |
context['current_revision'] = annotation.current_revision |
|
948 |
context['current_tags_data'] = annotation.current_revision.get_tags_json() |
|
949 |
context['current_comment'] = annotation.current_revision.creation_comment.first() |
|
950 |
return render(request, 'iconolab/merge_revision.html', context) |