Introduce folders.
from django.shortcuts import HttpResponse, get_object_or_404, render, redirect
from django.http import Http404
from django.db.models import Count
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.views.generic import View, DetailView, RedirectView, TemplateView
from django.views.generic.base import ContextMixin
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.conf import settings
from notifications.models import Notification
from iconolab.models import Annotation, AnnotationRevision, Collection, Item, Image, IconolabComment, MetaCategory, MetaCategoryInfo
from iconolab.forms.annotations import AnnotationRevisionForm
from iconolab.serializers import AnnotationRevisionSerializer
import logging
logger = logging.getLogger(__name__)
class GlobalHomepageView(View):
"""
View for the opening page of Iconolab.
"""
def get(self, request, *args, **kwargs):
"""
Template is iconolab/home.html
Context variables provided to the template are:
collections_primary: list of collections to display as big images
collections_secondary: list of collections to display as small links at the bottom
homepage = True: used to pass checks in the partials/header.html
template to adjust the navbar to the homepage
"""
context = {}
context['collections_primary'] = Collection.objects.filter(show_image_on_home=True).all()
context['collections_secondary'] = Collection.objects.filter(show_image_on_home=False).all()
context['contact'] = settings.CONTACT_EMAIL
context['homepage'] = True
return render(request, 'iconolab/home.html', context)
class TestView(View):
template_name = 'iconolab/compare.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name)
# Class with check_kwargs method to fetch objects from database depending on what level in the app we're currently at
class IconolabObjectView(object):
"""
Superclass that defines method used in all object display views.
"""
def check_kwargs(self, kwargs):
'''
Returns a boolean depending on wether (True) or not (False) the objects
were found and a tuple containing the objects, with a select_related/prefetch_related
on relevant related objects following this ordering:
(collection, item, image, annotation, revision)
'''
objects_tuple = ()
if 'collection_name' in kwargs.keys():
try:
objects_tuple += (Collection.objects.prefetch_related('items', 'items__images').get(name=kwargs.get('collection_name')),)
except (ValueError, Collection.DoesNotExist):
return False, RedirectView.as_view(url=reverse('404error'))
if 'item_guid' in kwargs.keys():
try:
objects_tuple += (Item.objects.prefetch_related('images', 'metadatas', 'images__stats').get(item_guid=kwargs.get('item_guid')),)
except (ValueError, Item.DoesNotExist):
return False, RedirectView.as_view(url=reverse('404error'))
if 'image_guid' in kwargs.keys():
try:
objects_tuple += (Image.objects.prefetch_related('annotations', 'item', 'stats').get(image_guid=kwargs.get('image_guid')),)
except (ValueError, Image.DoesNotExist):
return False, RedirectView.as_view(url=reverse('404error'))
if 'annotation_guid' in kwargs.keys():
try:
objects_tuple += (Annotation.objects.prefetch_related('current_revision', 'stats', 'image').get(annotation_guid=kwargs.get('annotation_guid')),)
except (ValueError, Annotation.DoesNotExist):
return False, RedirectView.as_view(url=reverse('404error'))
if 'revision_guid' in kwargs.keys():
try:
objects_tuple += (AnnotationRevision.objects.prefetch_related('parent_revision').get(revision_guid=kwargs.get('revision_guid')),)
except (ValueError, AnnotationRevision.DoesNotExist):
return False, RedirectView.as_view(url=reverse('404error'))
return True, objects_tuple
def get_pagination_data(self, list_to_paginate, page, perpage, adjacent_pages_count, perpage_range=[5, 10, 25, 100], trailing_qarg=""):
"""
Takes a queryset or a list and returns a dict with pagination data for display purposes
Dict will be of the format:
{
page: the page to load (integer)
perpage_range: a list of the page links to display (list of integers)
perpage: the item count per page (integer)
perpage_range: a list of the perpage values to display next to the page list (list of integers)
trailing_qarg: optional trailing qarg for the paginations links (used in collection home to remember the state of each list between page loads) (string)
list: the item list to display (list of objects)
show_first: used in template to display links, will be True if 1 is not in page_range
show_last: used in template to display links, will be True if page_count is not in page_range
ellipsis_first: used in template to display links, will be True if page_range starts at 3 or more
ellipsis_last: used in template to display links, will be True if page_range ends at last_page - 2 or less
}
"""
pagination_data = {}
pagination_data["page"] = page
pagination_data["perpage"] = perpage
pagination_data["perpage_range"] = perpage_range
pagination_data["trailing_qarg"] = trailing_qarg
paginator = Paginator(list_to_paginate, perpage)
try:
pagination_data["list"] = paginator.page(page)
except PageNotAnInteger:
pagination_data["list"] = paginator.page(1)
except EmptyPage:
pagination_data["list"] = paginator.page(paginator.num_pages)
pagination_data["page_range"] = [
n for n in \
range(page - adjacent_pages_count, page + adjacent_pages_count + 1) \
if n > 0 and n <= paginator.num_pages
]
pagination_data["show_first"] = page - adjacent_pages_count > 1
pagination_data["ellipsis_first"] = pagination_data["show_first"] and (page - adjacent_pages_count != 2)
pagination_data["show_last"] = page + adjacent_pages_count < paginator.num_pages
pagination_data["ellipsis_last"] = pagination_data["show_last"] and (page + adjacent_pages_count != paginator.num_pages - 1)
return pagination_data
class CollectionHomepageView(View, ContextMixin, IconolabObjectView):
"""
View that displays a collection and four panels to show relevant paginated lists for collection:
* item lists
* annotations ordered by creation date
* annotations ordered by revisions count
* annotations where a metacategory that notifies contributors was called
"""
def get(self, request, *args, **kwargs):
"""
Template is iconolab/collection_home.html
Url args are:
- collection_name: 'name' attribute of the requested collection
Queryargs understood by the view are:
- show : panel that will be shown on page load, one of ['items', 'recent', 'revised', 'contributions'], default to "items"
- items_page : item list page to load
- items_perpage : item count per page
- recent_page : recent annotations list page to load
- recent_perpage : recent annotations count per page
- revised_page : most revised annotations list page to load
- revised_perpage : most revised annotations count per page
- contributions_page : annotations with the most contribution calls list page to load
- contributions_perpage : annotations with the most contribution calls count per page for item list
Context variables provided to the template are:
- collection: the collection object for the requested collection
- collection_name : the collection_name url arg
- items_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the items list
- recent_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the recent annotations list
- revised_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the revised annotations list
- contributions_pagination_data: pagination data dict in the format of the IconolabObjectView.get_pagination_data() method for the contribution calls annotations list
"""
success, result = self.check_kwargs(kwargs)
if success:
(collection,) = result
else:
return result(request)
context = super(CollectionHomepageView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['collection'] = collection
# get Pagination and navigation query args
try:
items_page = int(request.GET.get('items_page', '1'))
except ValueError:
items_page = 1
try:
items_per_page = int(request.GET.get('items_perpage', '12'))
except ValueError:
items_per_page = 12
try:
recent_page = int(request.GET.get('recent_page', '1'))
except ValueError:
recent_page = 1
try:
recent_per_page = int(request.GET.get('recent_perpage', '10'))
except ValueError:
recent_per_page = 10
try:
revised_page = int(request.GET.get('revised_page', '1'))
except ValueError:
revised_page = 1
try:
revised_per_page = int(request.GET.get('revised_perpage', '10'))
except ValueError:
revised_per_page = 10
try:
contributions_page = int(request.GET.get('contributions_page', '1'))
except ValueError:
contributions_page = 1
try:
contributions_per_page = int(request.GET.get('contributions_perpage', '10'))
except ValueError:
contributions_per_page = 10
active_list = request.GET.get('show', 'items')
if active_list not in ['items', 'recent', 'revised', 'contributions']:
active_list = 'items'
context["active_list"] = active_list
# Pagination values
adjacent_pages_count = 2
# Paginated objects list
items_list = collection.items.order_by("metadatas__inventory_number")
folder = request.GET.get('folder', None)
if folder is not None:
folder = int(folder)
items_list = items_list.filter(folders__id=folder)
context['folder_id'] = folder
context["items_pagination_data"] = self.get_pagination_data(
items_list.all(),
items_page,
items_per_page,
adjacent_pages_count,
perpage_range=[6, 12, 48, 192],
trailing_qarg="&recent_page="+str(recent_page)
+"&recent_perpage="+str(recent_per_page)
+"&revised_page="+str(revised_page)
+"&revised_perpage="+str(revised_per_page)
+"&contributions_page="+str(contributions_page)
+"&contributions_perpage="+str(contributions_per_page)
)
# Paginated recent annotations list
recent_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
'current_revision',
'stats'
).order_by('-current_revision__created')
context["recent_pagination_data"] = self.get_pagination_data(
recent_annotations,
recent_page,
recent_per_page,
adjacent_pages_count,
trailing_qarg="&items_page="+str(items_page)
+"&items_perpage="+str(items_per_page)
+"&revised_page="+str(revised_page)
+"&revised_perpage="+str(revised_per_page)
+"&contributions_page="+str(contributions_page)
+"&contributions_perpage="+str(contributions_per_page)
)
# Paginated revised annotations list
revised_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
'current_revision',
'stats'
).annotate(revision_count=Count('revisions')).order_by('-revision_count')
context["revised_pagination_data"] = self.get_pagination_data(
revised_annotations,
revised_page,
revised_per_page,
adjacent_pages_count,
trailing_qarg="&items_page="+str(items_page)
+"&items_perpage="+str(items_per_page)
+"&recent_page="+str(recent_page)
+"&recent_perpage="+str(recent_per_page)
+"&contributions_page="+str(contributions_page)
+"&contributions_perpage="+str(contributions_per_page)
)
# Paginated contribution calls annotation list
contrib_calls_annotations_ids = list(set(MetaCategoryInfo.objects.filter(
metacategory__collection__name=collection.name,
metacategory__triggers_notifications=MetaCategory.CONTRIBUTORS
).order_by('comment__submit_date').values_list('comment__object_pk', flat=True)))
collection_annotations = Annotation.objects.filter(id__in=contrib_calls_annotations_ids).all()
collection_ann_dict = dict([(str(annotation.id), annotation) for annotation in collection_annotations])
contributions_annotations = [collection_ann_dict[id] for id in contrib_calls_annotations_ids]
context["contributions_pagination_data"] = self.get_pagination_data(
contributions_annotations,
contributions_page,
contributions_per_page,
adjacent_pages_count,
trailing_qarg="&items_page="+str(items_page)
+"&items_perpage="+str(items_per_page)
+"&recent_page="+str(recent_page)
+"&recent_perpage="+str(recent_per_page)
+"&revised_page="+str(revised_page)
+"&revised_perpage="+str(revised_per_page)
)
return render(request, 'iconolab/collection_home.html', context)
class ShowItemView(View, ContextMixin, IconolabObjectView):
"""
View that displays informations on an item with associated metadatas and stats. Also displays images and annotation list for each image.
"""
def get(self, request, *args, **kwargs):
"""
Template is iconolab/item_detail.html
Url args are:
- collection_name : name of the collection
- item_guid: 'item_guid' attribute of the requested item
Queryargs understood by the view are:
- show: image_guid for the image to show on load
- page: annotation list page on load for displayed image
- perpage: annotation count per page on load for displayed image
Context variables provided to the template are:
- collection_name : the collection_name url arg
- item_guid: the item_guid url arg
- collection: the collection object for the requested collection
- item: the item object for the requested item
- display_image: the image_guid for the image to display on load
- images: a list of dict for the item images data in the format:
{
'obj': the image object,
'annotations': the list of annotations on that image
}
"""
success, result = self.check_kwargs(kwargs)
if success:
(collection, item) = result
else:
return result(request)
context = super(ShowItemView, self).get_context_data(**kwargs)
image_guid_to_display = request.GET.get("show", str(item.images.first().image_guid))
if image_guid_to_display not in [str(guid) for guid in item.images.all().values_list("image_guid", flat=True)]:
image_guid_to_display = str(item.images.first().image_guid)
context['display_image'] = image_guid_to_display
try:
displayed_annotations_page = int(request.GET.get('page', '1'))
except ValueError:
displayed_annotations_page = 1
try:
displayed_annotations_per_page = int(request.GET.get('perpage', '10'))
except ValueError:
displayed_annotations_per_page = 10
context['collection_name'] = self.kwargs.get('collection_name', '')
context['item_guid'] = self.kwargs.get('image_guid', '')
context['collection'] = collection
context['item'] = item
context['images'] = []
for image in item.images.all():
if str(image.image_guid) == image_guid_to_display:
page = displayed_annotations_page
per_page = displayed_annotations_per_page
else:
page = 1
per_page = 10
annotations_paginator = Paginator(image.annotations.all(), per_page)
try:
annotations = annotations_paginator.page(page)
except PageNotAnInteger:
annotations = annotations_paginator.page(1)
except EmptyPage:
annotations = annotations_paginator.page(recent_paginator.num_pages)
context['images'].append({
'obj' : image,
'annotations': annotations
})
image.stats.views_count += 1
image.stats.save()
return render(request, 'iconolab/detail_item.html', context);
class ShowImageView(View, ContextMixin, IconolabObjectView):
"""
View that only displays an image and the associated annotations
"""
def get(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image) = result
else:
return result(request)
context = super(ShowImageView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['collection'] = collection
context['image'] = image
context['item'] = image.item
context['form'] = AnnotationRevisionForm()
return render(request, 'iconolab/detail_image.html', context)
class CreateAnnotationView(View, ContextMixin, IconolabObjectView):
"""
View that displays annotation forms and handles annotation creation
"""
def get_context_data(self, **kwargs):
context = super(CreateAnnotationView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
return context
def get(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image,) = result
else:
return result(request)
annotation_form = AnnotationRevisionForm()
context = self.get_context_data(**kwargs)
context['image'] = image
context['form'] = annotation_form
context['tags_data'] = '[]'
return render(request, 'iconolab/change_annotation.html', context)
def post(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image) = result
else:
return result(request)
collection_name = kwargs['collection_name']
image_guid = kwargs['image_guid']
annotation_form = AnnotationRevisionForm(request.POST)
if annotation_form.is_valid():
author = request.user
title = annotation_form.cleaned_data['title']
description = annotation_form.cleaned_data['description']
fragment = annotation_form.cleaned_data['fragment']
tags_json = annotation_form.cleaned_data['tags']
new_annotation = Annotation.objects.create_annotation(author, image, title=title, description=description, fragment=fragment, tags_json=tags_json)
redirect_url = reverse('image_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid})
return redirect(redirect_url + '#' + str(new_annotation.annotation_guid))
context = self.get_context_data(**kwargs)
context['image'] = image
context['form'] = annotation_form
context['tags_data'] = '[]'
return render(request, 'iconolab/change_annotation.html', context)
class ShowAnnotationView(View, ContextMixin, IconolabObjectView):
"""
View that show a given annotation with the corresponding data, links to
submit new revisions and the paginated comments thread.
"""
def get_context_data(self, **kwargs):
context = super(ShowAnnotationView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['annotation_guid'] = self.kwargs.get('annotation_guid', '')
return context
def get(self, request, *args, **kwargs):
"""
Template is iconolab/detail_annotations.html
Url args are:
- collection_name: 'name' attribute of the requested collection
- item_guid: 'item_guid' attribute of the requested item
- annotation_guid: 'annotation_guid' attribute of the requested annotation
Queryargs understood by the view are:
- page: comment thread page on load
- perpage: comment count per page on load
Context variables provided to the template are:
- collection: the collection object for the requested collection
- image: the image object for the requested image
- annotation: the annotation object for the requested annotation
- tags_data: a json string describing tags for the annotation current revision
- comments: the paginated comments list for the annotation according page and perpage queryargs
- notification_comments_ids: the ids of the comments that are referenced by a notification for the authenticated user; This allows
us to highlight comments that triggered a notification in the page
"""
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation,) = result
else:
return result(request)
context = self.get_context_data(**kwargs)
context['collection'] = collection
context['image'] = image
context['annotation'] = annotation
context['tags_data'] = annotation.current_revision.get_tags_json()
page = request.GET.get('page', 1)
per_page = request.GET.get('perpage', 10)
full_comments_list = IconolabComment.objects.for_app_models('iconolab.annotation').filter(object_pk = annotation.pk).order_by('thread_id', '-order')
paginator = Paginator(full_comments_list, per_page)
try:
comments_list = paginator.page(page)
except PageNotAnInteger:
comments_list = paginator.page(1)
except EmptyPage:
comments_list = paginator.page(paginator.num_pages)
context['comments'] = comments_list
if request.user.is_authenticated():
user_comment_notifications = Notification.objects.filter(
recipient=request.user,
action_object_content_type__app_label='iconolab',
action_object_content_type__model='iconolabcomment',
target_content_type__app_label='iconolab',
target_content_type__model='annotation',
target_object_id=annotation.id
).unread()
context['notifications_comments_ids'] = [int(val) for val in user_comment_notifications.values_list('action_object_object_id', flat=True)]
comment_list_ids = [comment.id for comment in context['comments'] ]
for notification in user_comment_notifications.all():
if int(notification.action_object_object_id) in comment_list_ids:
notification.mark_as_read()
image.stats.views_count += 1
image.stats.save()
annotation.stats.views_count += 1
annotation.stats.save()
return render(request, 'iconolab/detail_annotation.html', context)
class ReadonlyAnnotationView(View, ContextMixin, IconolabObjectView):
"""
Same view as ShowAnnotationView but without the comments and links to the forms
"""
def get_context_data(self, **kwargs):
context = super(ReadonlyAnnotationView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['annotation_guid'] = self.kwargs.get('annotation_guid', '')
return context
def get(self, request, *args, **kwargs):
"""
Exactly the same as ShowAnnotationView but without all the data around comments
"""
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation,) = result
else:
return result(request)
context = self.get_context_data(**kwargs)
context['collection'] = collection
context['image'] = image
context['annotation'] = annotation
context['tags_data'] = annotation.current_revision.get_tags_json()
image.stats.views_count += 1
image.stats.save()
annotation.stats.views_count += 1
annotation.stats.save()
return render(request, 'iconolab/detail_annotation_readonly.html', context)
class EditAnnotationView(View, ContextMixin, IconolabObjectView):
"""
View that handles displaying the edition form and editing an annotation
"""
def get_context_data(self, **kwargs):
context = super(EditAnnotationView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['annotation_guid'] = self.kwargs.get('annotation_guid', '')
return context
def get(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation,) = result
else:
return result(request)
annotation_form = AnnotationRevisionForm(instance=annotation.current_revision)
context = self.get_context_data(**kwargs)
context['image'] = image
context['annotation'] = annotation
context['form'] = annotation_form
context['tags_data'] = annotation.current_revision.get_tags_json()
return render(request, 'iconolab/change_annotation.html', context)
def post(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation) = result
else:
return result(request)
collection_name = kwargs['collection_name']
image_guid = kwargs['image_guid']
annotation_guid = kwargs['annotation_guid']
annotation_form = AnnotationRevisionForm(request.POST)
if annotation_form.is_valid():
revision_author = request.user
revision_title = annotation_form.cleaned_data['title']
revision_description = annotation_form.cleaned_data['description']
revision_fragment = annotation_form.cleaned_data['fragment']
revision_tags_json = annotation_form.cleaned_data['tags']
new_revision = annotation.make_new_revision(revision_author, revision_title, revision_description, revision_fragment, revision_tags_json)
redirect_url = reverse('image_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid})
return redirect(redirect_url + '#' + str(annotation.annotation_guid))
context = self.get_context_data(**kwargs)
context['image'] = image
context['form'] = annotation_form
context['annotation'] = annotation
context['tags_data'] = annotation.current_revision.get_tags_json()
return render(request, 'iconolab/change_annotation.html', context)
class ShowRevisionView(View, ContextMixin, IconolabObjectView):
"""
View that displays a given revision with its associated data and comment
"""
def get_context_data(self, **kwargs):
context = super(ShowRevisionView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['annotation_guid'] = self.kwargs.get('annotation_guid', '')
context['revision_guid'] = self.kwargs.get('revision_guid', '')
return context
def get(self, request, *args, **kwargs):
"""
Template is iconolab/detail_annotations.html
Url args are:
- collection_name: 'name' attribute of the requested collection
- item_guid: 'item_guid' attribute of the requested item
- annotation_guid: 'annotation_guid' attribute of the requested annotation
- revision_guid: 'revision_guid' attribute of the requested revision
Context variables provided to the template are:
- collection: the collection object for the requested collection
- image: the image object for the requested image
- annotation: the annotation object for the requested annotation
- revision: the revision object for the requested annotation
- tags_data: a json string describing tags for the annotation current revision
- comment: the comment that was posted alongside the revision
- notified_revision: if True, the revision is linked from one or more unread notifications for the
current user, allowing us to highlight it in the template.
"""
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation, revision,) = result
else:
return result(request)
context = self.get_context_data(**kwargs)
context['collection'] = collection
context['image'] = image
context['annotation'] = annotation
context['revision'] = revision
context['tags_data'] = revision.get_tags_json()
context['comment'] = revision.creation_comment.first()
if request.user.is_authenticated() and annotation.author == request.user:
ann_author_notified = Notification.objects.filter(
recipient=request.user,
action_object_content_type__app_label='iconolab',
action_object_content_type__model='annotationrevision',
action_object_object_id=revision.id,
target_content_type__app_label='iconolab',
target_content_type__model='annotation',
target_object_id=annotation.id
).unread()
if ann_author_notified:
ann_author_notified.first().mark_as_read()
context['notified_revision'] = True
if request.user.is_authenticated() and revision.author == request.user:
rev_author_notified = Notification.objects.filter(
recipient=request.user,
action_object_content_type__app_label='iconolab',
action_object_content_type__model='annotationrevision',
action_object_object_id=revision.id,
target_content_type__app_label='iconolab',
target_content_type__model='annotation',
target_object_id=annotation.id
).unread()
if rev_author_notified:
rev_author_notified.first().mark_as_read()
context['notified_revision'] = True
return render(request, 'iconolab/detail_revision.html', context)
class MergeProposalView(View, ContextMixin, IconolabObjectView):
"""
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
the two revisions don't have the same parents and there is a conflict)
"""
def get_context_data(self, **kwargs):
context = super(MergeProposalView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['image_guid'] = self.kwargs.get('image_guid', '')
context['annotation_guid'] = self.kwargs.get('annotation_guid', '')
context['revision_guid'] = self.kwargs.get('revision_guid', '')
return context
def get(self, request, *args, **kwargs):
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation, revision,) = result
else:
return result(request)
# Only show merge form if there is a revision to merge AND the current user is the annotation author
if revision.state != AnnotationRevision.AWAITING or request.user != annotation.author:
return RedirectView.as_view(
url=reverse('revision_detail',
kwargs={
'collection_name': collection.name,
'image_guid': image.image_guid,
'annotation_guid': annotation.annotation_guid,
'revision_guid': revision.revision_guid
}
)
)(request)
# Auto-accepts the revision only if the proper query arg is set and only if the revision parent is the current revision
if 'auto_accept' in request.GET and request.GET['auto_accept'] in ['True', 'true', '1', 'yes'] and revision.parent_revision == annotation.current_revision:
annotation.validate_existing_revision(revision)
return RedirectView.as_view(
url=reverse('annotation_detail',
kwargs={
'collection_name': collection.name,
'image_guid': image.image_guid,
'annotation_guid': annotation.annotation_guid
}
)
)(request)
# Auto-reject the revision only if the proper query arg is set
if 'auto_reject' in request.GET and request.GET['auto_reject'] in ['True', 'true', '1', 'yes']:
annotation.reject_existing_revision(revision)
return RedirectView.as_view(
url=reverse('annotation_detail',
kwargs={
'collection_name': collection.name,
'image_guid': image.image_guid,
'annotation_guid': annotation.annotation_guid
}
)
)(request)
context = self.get_context_data(**kwargs)
context['collection'] = collection
context['image'] = image
context['annotation'] = annotation
# Proposal data
context['proposal_revision'] = revision
context['proposal_tags_data'] = revision.get_tags_json()
context['proposal_comment'] = revision.creation_comment.first()
# Parent data
context['parent_revision'] = revision.parent_revision
context['parent_tags_data'] = revision.parent_revision.get_tags_json()
context['parent_comment'] = revision.parent_revision.creation_comment.first()
# Current data
context['current_revision'] = annotation.current_revision
context['current_tags_data'] = annotation.current_revision.get_tags_json()
context['current_comment'] = annotation.current_revision.creation_comment.first()
merge_form = AnnotationRevisionForm(instance=revision)
context['merge_form'] = merge_form
return render(request, 'iconolab/merge_revision.html', context)
def post(self, request, *args, **kwargs):
# Handle merge form submit here
success, result = self.check_kwargs(kwargs)
if success:
(collection, image, annotation, revision) = result
else:
return result(request)
collection_name = kwargs['collection_name']
image_guid = kwargs['image_guid']
annotation_guid = kwargs['annotation_guid']
revision_guid = kwargs['revision_guid']
merge_revision_form = AnnotationRevisionForm(request.POST)
if merge_revision_form.is_valid():
revision_title = merge_revision_form.cleaned_data['title']
revision_description = merge_revision_form.cleaned_data['description']
revision_fragment = merge_revision_form.cleaned_data['fragment']
revision_tags_json = merge_revision_form.cleaned_data['tags']
new_revision = annotation.merge_existing_revision(revision_title, revision_description, revision_fragment, revision_tags_json, revision)
revision_comment = merge_revision_form.cleaned_data['comment']
comment = IconolabComment.objects.create(
comment = revision_comment,
revision = new_revision,
content_type = ContentType.objects.get(app_label='iconolab', model='annotation'),
content_object = annotation,
site = Site.objects.get(id=settings.SITE_ID),
object_pk = annotation.id,
user = request.user,
user_name = request.user.username
)
return RedirectView.as_view(url=reverse('annotation_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid, 'annotation_guid': annotation_guid}))(request)
context = self.get_context_data(**kwargs)
context['image'] = image
context['merge_form'] = merge_revision_form
context['annotation'] = annotation
# Proposal data
context['proposal_revision'] = revision
context['proposal_tags_data'] = revision.get_tags_json()
context['proposal_comment'] = revision.creation_comment.first()
# Parent data
context['parent_revision'] = revision.parent_revision
context['parent_tags_data'] = revision.parent_revision.get_tags_json()
context['parent_comment'] = revision.parent_revision.creation_comment.first()
# Current data
context['current_revision'] = annotation.current_revision
context['current_tags_data'] = annotation.current_revision.get_tags_json()
context['current_comment'] = annotation.current_revision.creation_comment.first()
return render(request, 'iconolab/merge_revision.html', context)