Work on admin interface and user pages + added stat metacategories count for annotations + refactored views module #41
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/migrations/0014_auto_20161108_1458.py Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2016-11-08 14:58
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('iconolab', '0013_auto_20160923_1404'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='MetaCategoriesCountInfo',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('count', models.IntegerField(default=1)),
+ ('annotation_stats_obj', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iconolab.AnnotationStats')),
+ ('metacategory', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iconolab.MetaCategory')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='annotationstats',
+ name='metacategories',
+ field=models.ManyToManyField(through='iconolab.MetaCategoriesCountInfo', to='iconolab.MetaCategory'),
+ ),
+ ]
--- a/src/iconolab/models.py Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/models.py Wed Nov 09 14:16:49 2016 +0100
@@ -1,7 +1,7 @@
from django.db import models, transaction
from django.conf import settings
from django.contrib.auth.models import User
-from django.contrib.contenttypes.fields import GenericForeignKey
+from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django_comments_xtd.models import XtdComment
from django.utils.text import slugify
@@ -209,6 +209,93 @@
iconolab_signals.revision_created.send(sender=AnnotationRevision, instance=initial_revision)
return new_annotation
+ @transaction.atomic
+ def get_annotations_contributed_for_user(self, user):
+ """
+ user is the user whom we want to get the contributed annotations
+
+ Returns the list of all the annotations on which the user submitted a revision but did not create the annotation
+ List of dict in the format:
+
+ {
+ "annotation_obj": annotation object,
+ "revisions_count": revisions count for user
+ "awaiting_count": awaiting revisions for user on this annotation
+ "accepted_count": accepted revisions for user
+ "latest_submitted_revision": date of the latest submitted revision from user on annotation
+ }
+ """
+ latest_revision_on_annotations = []
+ user_contributed_annotations = Annotation.objects.filter(revisions__author=user).exclude(author=user).prefetch_related(
+ 'current_revision',
+ 'revisions',
+ 'image',
+ 'image__item',
+ 'image__item__collection').distinct()
+ for annotation in user_contributed_annotations.all():
+ latest_revision_on_annotations.append(annotation.revisions.filter(author=user).latest(field_name="created"))
+ contributed_list = []
+ if latest_revision_on_annotations:
+ latest_revision_on_annotations.sort(key=lambda item:item.created, reverse=True)
+ contributed_list= [
+ {
+ "annotation_obj": revision.annotation,
+ "revisions_count": revision.annotation.revisions.filter(author=user).count(),
+ "awaiting_count": revision.annotation.revisions.filter(author=user, state=AnnotationRevision.AWAITING).count(),
+ "accepted_count": revision.annotation.revisions.filter(author=user, state=AnnotationRevision.ACCEPTED).count(),
+ "latest_submitted_revision": revision.created
+ }
+ for revision in latest_revision_on_annotations
+ ]
+ logger.debug(contributed_list)
+ return contributed_list
+
+ @transaction.atomic
+ def get_annotations_commented_for_user(self, user, ignore_revisions_comments=True):
+ """
+ user is the user for which we want to get the commented annotations
+ ignore_revisions_comment allows to filter comments that are associated with a revision
+
+
+ Returns a list of all annotations on which a given user commented with user-comments-related data
+ List of dict in the format:
+
+ {
+ "annotation_obj": annotation object,
+ "comment_count": comment count for user
+ "latest_comment_date": date of the latest comment from user on annotation
+ }
+ """
+ user_comments = IconolabComment.objects.filter(user=user, content_type__app_label='iconolab', content_type__model='annotation').order_by('-submit_date')
+ if ignore_revisions_comments:
+ logger.debug(user_comments.count())
+ user_comments = user_comments.filter(revision__isnull=True)
+ logger.debug(user_comments.count())
+ all_user_comments_data = [(comment.object_pk, comment.submit_date) for comment in user_comments]
+ unique_ordered_comments_data = []
+ for (id, submit_date) in all_user_comments_data:
+ if id not in [item["annotation_id"] for item in unique_ordered_comments_data]:
+ unique_ordered_comments_data.append({"annotation_id": id, "latest_comment_date": submit_date})
+ commented_annotations = Annotation.objects.filter(id__in=[item["annotation_id"] for item in unique_ordered_comments_data]).prefetch_related(
+ 'current_revision',
+ 'revisions',
+ 'image',
+ 'image__item',
+ 'image__item__collection'
+ ).distinct()
+ sorted_annotations_list = []
+ logger.debug(unique_ordered_comments_data)
+ for comment_data in unique_ordered_comments_data:
+ annotation_obj = commented_annotations.get(id=comment_data["annotation_id"])
+ sorted_annotations_list.append(
+ {
+ "annotation_obj": annotation_obj,
+ "comment_count_for_user": user_comments.filter(object_pk=annotation_obj.id).count(),
+ "latest_comment_date": comment_data["latest_comment_date"]
+ }
+ )
+ return sorted_annotations_list
+
class AnnotationStats(models.Model):
annotation = models.OneToOneField('Annotation', related_name='stats', blank=False, null=False)
@@ -219,6 +306,7 @@
views_count = models.IntegerField(blank=True, null=True, default=0)
comments_count = models.IntegerField(blank=True, null=True, default=0)
tag_count = models.IntegerField(blank=True, null=True, default=0)
+ metacategories = models.ManyToManyField('MetaCategory', through='MetaCategoriesCountInfo', through_fields=('annotation_stats_obj', 'metacategory'))
def __str__(self):
return "stats:for:"+str(self.annotation.annotation_guid)
@@ -261,8 +349,35 @@
# contributors_count
self.contributors_count = len(self.contributors)
# tag_count
+
+ annotation_comments_with_metacategories = IconolabComment.objects.filter(
+ content_type__app_label="iconolab",
+ content_type__model="annotation",
+ object_pk=self.annotation.id,
+ metacategories__collection=self.annotation.image.item.collection
+ )
+ m2m_objects = MetaCategoriesCountInfo.objects.filter(annotation_stats_obj=self)
+ for obj in m2m_objects.all():
+ obj.count = 0
+ obj.save()
+ for comment in annotation_comments_with_metacategories.all():
+ for metacategory in comment.metacategories.all():
+ if metacategory not in self.metacategories.all():
+ MetaCategoriesCountInfo.objects.create(annotation_stats_obj=self, metacategory=metacategory, count=1)
+ else:
+ m2m_object = MetaCategoriesCountInfo.objects.filter(annotation_stats_obj=self, metacategory=metacategory).first()
+ m2m_object.count += 1
+ m2m_object.save()
self.set_tags_stats()
self.save()
+
+class MetaCategoriesCountInfo(models.Model):
+ annotation_stats_obj = models.ForeignKey('AnnotationStats', on_delete=models.CASCADE)
+ metacategory = models.ForeignKey('MetaCategory', on_delete=models.CASCADE)
+ count = models.IntegerField(default=1, blank=False, null=False)
+
+ def __str__(self):
+ return "metacategory_count_for:"+self.metacategory.label+":on:"+str(self.annotation_stats_obj.annotation.annotation_guid)
class Annotation(models.Model):
@@ -272,6 +387,7 @@
current_revision = models.OneToOneField('AnnotationRevision', related_name='current_for_annotation', blank=True, null=True)
author = models.ForeignKey(User, null=True)
created = models.DateTimeField(auto_now_add=True, null=True)
+ comments = GenericRelation('IconolabComment', content_type_field='content_type_id', object_id_field='object_pk')
objects = AnnotationManager()
@@ -307,6 +423,11 @@
current_revision_tags = json.loads(self.current_revision.get_tags_json())
return [tag_infos['tag_label'] for tag_infos in current_revision_tags if tag_infos.get('tag_label') is not None ]
+ def latest_revision_for_user(self, user):
+ user_revisions = self.revisions.filter(creator=user)
+ if user_revisions.exists():
+ return user_revisions.filter(creator=author).order_by("-created").first()
+ return None
# Call to create a new revision, possibly from a merge
@transaction.atomic
@@ -509,6 +630,12 @@
class Meta:
ordering = ["thread_id", "id"]
+ @property
+ def annotation(self):
+ if self.content_type.app_label == "iconolab" and self.content_type.model == "annotation":
+ return Annotation.objects.get(pk=self.object_pk)
+ return None
+
# Get page for considered comment, with COMMENTS_PER_PAGE_DEFAULT comments per page
def get_comment_page(self):
return (IconolabComment.objects.for_app_models("iconolab.annotation").filter(
--- a/src/iconolab/signals/handlers.py Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/signals/handlers.py Wed Nov 09 14:16:49 2016 +0100
@@ -2,6 +2,9 @@
from django.db.models.signals import post_save
from django.dispatch import Signal, receiver
from notifications.signals import notify
+import logging
+
+logger = logging.getLogger(__name__)
# Signal sent during method Annotation.validate_existing_revision to update stats
revision_accepted = Signal(providing_args=['instance'])
@@ -28,20 +31,32 @@
image = instance.annotation.image
image.stats.submitted_revisions_count += 1
image.stats.set_tags_stats()
- image.stats.save()
-
+ image.stats.save()
def increment_stats_on_new_comment(sender, instance, created, **kwargs):
from iconolab.models import IconolabComment
if created and sender == IconolabComment:
model = apps.get_model(instance.content_type.app_label,instance.content_type.model)
object_pk = instance.object_pk
- annotation = model._default_manager.get(pk=object_pk)
+ annotation = model.objects.get(pk=object_pk)
annotation.stats.comments_count +=1
annotation.stats.save()
annotation.image.stats.comments_count +=1
annotation.image.stats.save()
+def increment_stats_on_new_metacategory(sender, instance, created, **kwargs):
+ from iconolab.models import MetaCategoryInfo, MetaCategoriesCountInfo
+ if created and sender == MetaCategoryInfo:
+ metacategory = instance.metacategory
+ comment = instance.comment
+ annotation = comment.annotation
+ if metacategory not in annotation.stats.metacategories.all():
+ MetaCategoriesCountInfo.objects.create(annotation_stats_obj=annotation.stats, metacategory=metacategory, count=1)
+ else:
+ m2m_object = MetaCategoriesCountInfo.objects.get(annotation_stats_obj=annotation.stats, metacategory=metacategory)
+ m2m_object.count += 1
+ m2m_object.save()
+ logger.debug("NEW METACATEGORY %r on comment %r on annotation %r", metacategory, comment, annotation)
def increment_stats_on_accepted_revision(sender, instance, **kwargs):
from iconolab.models import AnnotationRevision
@@ -82,8 +97,7 @@
if parent_comment.user == comment_annotation.author:
notified_author = True
if instance.user != comment_annotation.author and not notified_author:
- notify.send(instance.user, recipient=comment_annotation.author, verb='a écrit un commentaire sur votre annotation', action_object=instance, target=comment_annotation)
-
+ notify.send(instance.user, recipient=comment_annotation.author, verb='a écrit un commentaire sur votre annotation', action_object=instance, target=comment_annotation)
def notify_users_on_metacategory(sender, instance, created, **kwargs):
from iconolab.models import MetaCategory, MetaCategoryInfo, Annotation, UserProfile
@@ -106,15 +120,13 @@
from iconolab.models import AnnotationRevision
if sender == AnnotationRevision:
if instance.author != instance.annotation.author:
- notify.send(instance.author, recipient=instance.annotation.author, verb='a proposé une révision sur votre annotation', action_object=instance, target=instance.annotation)
-
+ notify.send(instance.author, recipient=instance.annotation.author, verb='a proposé une révision sur votre annotation', action_object=instance, target=instance.annotation)
def notify_users_on_accepted_revision(sender, instance, **kwargs):
from iconolab.models import AnnotationRevision
if sender == AnnotationRevision:
if instance.author != instance.annotation.author and instance.state in [AnnotationRevision.ACCEPTED, AnnotationRevision.STUDIED]:
- notify.send(instance.annotation.author, recipient=instance.author, verb='a étudié votre révision', action_object=instance, target=instance.annotation)
-
+ notify.send(instance.annotation.author, recipient=instance.author, verb='a étudié votre révision', action_object=instance, target=instance.annotation)
def create_user_profile(sender, instance, created, **kwargs):
from iconolab.models import UserProfile
@@ -128,6 +140,7 @@
# Stats handlers connect
post_save.connect(increment_annotations_count)
post_save.connect(increment_stats_on_new_comment)
+post_save.connect(increment_stats_on_new_metacategory)
revision_created.connect(increment_stats_on_new_revision)
revision_accepted.connect(increment_stats_on_accepted_revision)
revision_rejected.connect(increment_stats_on_rejected_revision)
--- a/src/iconolab/static/iconolab/css/iconolab.css Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/static/iconolab/css/iconolab.css Wed Nov 09 14:16:49 2016 +0100
@@ -7,11 +7,25 @@
.form-drawing-wrapper .selected {border: 1px solid orange; color: white; background-color: orange}
.showPointer {cursor: pointer;}
-.zoom-action-list {padding-left:21px;}
-.zoomTarget-wrapper { padding: 0px;}
-#zoomTarget, .cut-canvas {border: 1px solid #C3C3C3; padding-top: 2px; padding-bottom: 2px}
+.zoom-action-list {
+ padding-left:21px;
+}
+
+.zoomTarget-wrapper {
+ padding: 0px;
+}
-.no-padding {padding-left: 0; padding-right: 0;}
+#zoomTarget, .cut-canvas {
+ border: 1px solid #C3C3C3;
+ padding-top: 2px;
+ padding-bottom: 2px
+}
+
+.no-padding {
+ padding-left: 0;
+ padding-right: 0;
+}
+
.annotation-content{
margin-top: 15px;
margin-bottom: 15px;
@@ -21,7 +35,9 @@
border: 1px solid orange;
}
-.revision-proposal {background-color: #ECF0F1;}
+.revision-proposal {
+ background-color: #ECF0F1;
+}
.collection-home-btn{
margin-top: 5px;
@@ -101,11 +117,38 @@
min-width: 535px;
}
.annotation-detail{
- vertical-align: middle;
+ display:inline-block;
+ margin-right: 5px;
+ margin-left: 5px;
+ margin-top: 5px;
+ white-space: normal;
+ vertical-align: top;
+ padding: 10px;
+}
+
+.stats-annotation-userpage{
display:inline-block;
- margin-right: 15px;
- margin-left: 15px;
+ vertical-align: top;
+ padding: 10px;
+}
+
+.image-detail{
+ display:inline-block;
+ vertical-align: top;
+ width:150px;
}
+.large-image-detail{
+ display:inline-block;
+ vertical-align: top;
+ width:450px;
+}
+
+
+.panel .dl-horizontal dt {
+ white-space: normal;
+ text-align: left;
+}
+
.no-user-annotation{
margin-left: 15px;
}
@@ -115,8 +158,7 @@
.userpage-annotation-btn{
display:inline-block;
vertical-align: top;
- margin-top: 15px;
- margin-right: 15px;
+ margin-bottom:5px;
}
/* COLLECTION HOME PAGE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/iconolab/user_annotations.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,63 @@
+{% extends 'iconolab_base.html' %}
+
+{% load staticfiles %}
+
+{% load thumbnail %}
+
+{% load iconolab_tags %}
+
+{% load notifications_tags %}
+
+{% block content %}
+ <div id="user-profile-block" class="row" style="border: 1px solid gray; padding:15px;">
+ <h3>{{profile_user.username}}: Annotations créées <a class="btn btn-default" href="{% url 'user_home' profile_user.id %}"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Retour au profil</a></h3>
+ <hr>
+ {% if not user_annotations %}
+ <h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
+ {% else %}
+ <ul class="list-unstyled">
+ {% for annotation in user_annotations %}
+ {% include "partials/user_pages/annotations_created_panel.html" with annotation=annotation user=profile_user with_stats=True large_image=True %}
+ {% endfor %}
+ </ul>
+ <ul class="pagination pull-right img-ann-{{image.obj.guid}}-perpage" style="margin-left: 15px;">
+ <li class="active pagination-label"><a>Annotations par page : </a></li>
+ <li class="{% if user_annotations.paginator.per_page == 5 %}active{% endif %}">
+ <a {% if user_annotations.paginator.per_page != 5 %}href="{% url 'user_annotations' profile_user.id %}?&page=1&perpage=5"{% endif %}>5</a>
+ </li>
+ <li class="{% if user_annotations.paginator.per_page == 10 %}active{% endif %}">
+ <a {% if user_annotations.paginator.per_page != 10 %}href="{% url 'user_annotations' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=10"{% endif %}>10</a>
+ </li>
+ <li class="{% if user_annotations.paginator.per_page == 25 %}active{% endif %}">
+ <a {% if user_annotations.paginator.per_page != 25 %}href="{% url 'user_annotations' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=25"{% endif %}>25</a>
+ </li>
+ <li class="{% if user_annotations.paginator.per_page == 100 %}active{% endif %}">
+ <a {% if user_annotations.paginator.per_page != 100 %}href="{% url 'user_annotations' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=100"{% endif %}>100</a>
+ </li>
+ </ul>
+ {% if user_annotations.has_previous or user_annotations.has_next %}
+ <ul class="pagination pull-right">
+ {% if user_annotations.has_previous %}
+ <li>
+ <a href="{% url 'user_annotations' profile_user.id %}?page={{user_annotations.previous_page_number}}" aria-label="Précédent">
+ <span aria-hidden="true">«</span>
+ </a>
+ </li>
+ {% endif %}
+ {% for page in user_annotations.paginator.page_range %}
+ <li id="page-link-{{page}}" class="pagination-link {% if page == user_annotations.number %}active{% endif %}">
+ <a {% if page != user_annotations.number %}href="{% url 'user_annotations' profile_user.id %}?page={{page}}&perpage={{user_annotations.paginator.per_page}}"{% endif %}>{{page}}</a>
+ </li>
+ {% endfor %}
+ {% if user_annotations.has_next %}
+ <li>
+ <a href="{% url 'user_annotations' profile_user.id %}?page={{user_annotations.next_page_number}}" aria-label="Suivant">
+ <span aria-hidden="true">»</span>
+ </a>
+ </li>
+ {% endif %}
+ </ul>
+ {% endif %}
+ {% endif %}
+ </div>
+{% endblock %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/iconolab/user_collection_admin.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,71 @@
+{% extends 'iconolab_base.html' %}
+
+{% load staticfiles %}
+
+{% load thumbnail %}
+
+{% load iconolab_tags %}
+
+{% load notifications_tags %}
+
+{% block content %}
+ <div id="user-profile-block" class="row" style="border: 1px solid gray; padding:15px;">
+ <h3>Tableau de bord - Fonds {{collection.verbose_name}}</h3>
+ <h2><small>Filtres et tri</small></h2>
+ <form class="form" method="GET" target="">
+ <div class="row">
+ <div class="form-group col-md-4">
+ <label>Trier par
+<!-- <a class="btn btn-default btn-sm">Ajouter un tri</a> -->
+ </label><br>
+ <select id="first_ordering_select" name="first" class="form-control">
+ <option id="first_oldest" value="oldest">Date (plus vieux d'abord)</option>
+ <option id="first_recent" value="recent">Date (plus récents d'abord)</option>
+ <option id="first_most_viewed" value="most_viewed">Nombre de vues</option>
+ <option id="first_most_commented" value="most_commented">Nombre de commentaires</option>
+ <option id="first_most_revised" value="most_revised">Nombre de révisions</option>
+ <option id="first_most_tagged" value="most_tagged">Nombre de mots-clés</option>
+ </select>
+<!-- <select id="second_ordering_select" name="second" class="form-control"> -->
+<!-- <option id="second_oldest" value="oldest">Date (plus vieux d'abord)</option> -->
+<!-- <option id="second_recent" value="recent">Date (plus récents d'abord)</option> -->
+<!-- <option id="second_most_viewed" value="most_viewed">Nombre de vues</option> -->
+<!-- <option id="second_most_commented" value="most_commented">Nombre de commentaires</option> -->
+<!-- <option id="second_most_revised" value="most_revised">Nombre de révisions</option> -->
+<!-- <option id="second_most_tagged" value="most_tagged">Nombre de mots-clés</option> -->
+<!-- </select> -->
+<!-- <select id="third_ordering_select" name="third" class="form-control"> -->
+<!-- <option id="third_oldest" value="oldest">Date (plus vieux d'abord)</option> -->
+<!-- <option id="third_recent" value="recent">Date (plus récents d'abord)</option> -->
+<!-- <option id="third_most_viewed" value="most_viewed">Nombre de vues</option> -->
+<!-- <option id="third_most_commented" value="most_commented">Nombre de commentaires</option> -->
+<!-- <option id="third_most_revised" value="most_revised">Nombre de révisions</option> -->
+<!-- <option id="third_most_tagged" value="most_tagged">Nombre de mots-clés</option> -->
+<!-- </select> -->
+<!-- <select id="fourth_ordering_select" name="fourth" class="form-control"> -->
+<!-- <option id="fourth_oldest" value="oldest">Date (plus vieux d'abord)</option> -->
+<!-- <option id="fourth_recent" value="recent">Date (plus récents d'abord)</option> -->
+<!-- <option id="fourth_most_viewed" value="most_viewed">Nombre de vues</option> -->
+<!-- <option id="fourth_most_commented" value="most_commented">Nombre de commentaires</option> -->
+<!-- <option id="fourth_most_revised" value="most_revised">Nombre de révisions</option> -->
+<!-- <option id="fourth_most_tagged" value="most_tagged">Nombre de mots-clés</option> -->
+<!-- </select> -->
+ </div>
+ <div class="form-group col-md-6">
+ <label>Filtrer par</label><br>
+ <b>Mots-clés pertinents:</b> qualification minimale <input type="number" name="min_relevancy" min="0" max="5"></input><br>
+ <b>Mots-clés précis:</b> qualification minimale <input type="number" name="min_accuracy" min="0" max="5"></input><br>
+ <b>Nombre de commentaires:</b> au moins <input type="number" name="min_comments" min="0"></input><br>
+ <b>Nombre de révisions:</b> au moins <input type="number" name="min_revisions" min="0"></input><br>
+ <b>Métacatégories:</b><br>
+ {% for metacategory in collection.metacategories.all %}
+ au moins <input type="number" name="min_metacategory_{{metacategory.id}}" min="0"></input> {{metacategory.label}}<br>
+ {% endfor %}
+ </div>
+ </div>
+ <input class="btn btn-default" type="submit" value="Filtrer"></input>
+ </form>
+ <h2><small>Listes des annotations</small></h2>
+ {% include "partials/image_annotations_list.html" with annotation_list=collection_filtered_annotations collection_name=collection.name %}
+ </div>
+{% endblock %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/iconolab/user_commented.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,64 @@
+{% extends 'iconolab_base.html' %}
+
+{% load staticfiles %}
+
+{% load thumbnail %}
+
+{% load iconolab_tags %}
+
+{% load notifications_tags %}
+
+{% block content %}
+ <div id="user-profile-block" class="row" style="border: 1px solid gray; padding:15px;">
+ <h3>{{profile_user.username}}: Annotations commentées <a class="btn btn-default" href="{% url 'user_home' profile_user.id %}"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Retour au profil</a></h3>
+ <hr>
+ {% if not user_commented_annotations %}
+ <h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
+ {% else %}
+ <ul class="list-unstyled">
+ {% for annotation_data in user_commented_annotations %}
+ {% include "partials/user_pages/annotations_commented_panel.html" with annotation_data=annotation_data user=profile_user with_stats=True large_image=True %}
+ {% endfor %}
+ </ul>
+ <ul class="pagination pull-right img-ann-{{image.obj.guid}}-perpage" style="margin-left: 15px;">
+ <li class="active pagination-label"><a>Annotations par page : </a></li>
+ <li class="{% if user_commented_annotations.paginator.per_page == 5 %}active{% endif %}">
+ <a {% if user_commented_annotations.paginator.per_page != 5 %}href="{% url 'user_commented' profile_user.id %}?&page=1&perpage=5"{% endif %}>5</a>
+ </li>
+ <li class="{% if user_commented_annotations.paginator.per_page == 10 %}active{% endif %}">
+ <a {% if user_commented_annotations.paginator.per_page != 10 %}href="{% url 'user_commented' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=10"{% endif %}>10</a>
+ </li>
+ <li class="{% if user_commented_annotations.paginator.per_page == 25 %}active{% endif %}">
+ <a {% if user_commented_annotations.paginator.per_page != 25 %}href="{% url 'user_commented' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=25"{% endif %}>25</a>
+ </li>
+ <li class="{% if user_commented_annotations.paginator.per_page == 100 %}active{% endif %}">
+ <a {% if user_commented_annotations.paginator.per_page != 100 %}href="{% url 'user_commented' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=100"{% endif %}>100</a>
+ </li>
+ </ul>
+ {% if user_commented_annotations.has_previous or user_commented_annotations.has_next %}
+ <ul class="pagination pull-right">
+ {% if user_commented_annotations.has_previous %}
+ <li>
+ <a href="{% url 'user_commented' profile_user.id %}?page={{user_commented_annotations.previous_page_number}}&perpage={{user_commented_annotations.paginator.per_page}}" aria-label="Précédent">
+ <span aria-hidden="true">«</span>
+ </a>
+ </li>
+ {% endif %}
+ {% for page in user_commented_annotations.paginator.page_range %}
+ <li id="page-link-{{page}}" class="pagination-link {% if page == user_commented_annotations.number %}active{% endif %}">
+ <a {% if page != user_commented_annotations.number %}href="{% url 'user_commented' profile_user.id %}?page={{page}}&perpage={{user_commented_annotations.paginator.per_page}}"{% endif %}>{{page}}</a>
+ </li>
+ {% endfor %}
+
+ {% if user_commented_annotations.has_next %}
+ <li>
+ <a href="{% url 'user_commented' profile_user.id %}?page={{user_commented_annotations.next_page_number}}&perpage={{user_commented_annotations.paginator.per_page}}" aria-label="Suivant">
+ <span aria-hidden="true">»</span>
+ </a>
+ </li>
+ {% endif %}
+ </ul>
+ {% endif %}
+ {% endif %}
+ </div>
+{% endblock %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/iconolab/user_contributed.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,64 @@
+{% extends 'iconolab_base.html' %}
+
+{% load staticfiles %}
+
+{% load thumbnail %}
+
+{% load iconolab_tags %}
+
+{% load notifications_tags %}
+
+{% block content %}
+ <div id="user-profile-block" class="row" style="border: 1px solid gray; padding:15px;">
+ <h3>{{profile_user.username}}: Toutes les contributions <a class="btn btn-default" href="{% url 'user_home' profile_user.id %}"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Retour au profil</a></h3>
+ <hr>
+ {% if not user_contributed_annotations %}
+ <h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
+ {% else %}
+ <ul class="list-unstyled">
+ {% for annotation_data in user_contributed_annotations %}
+ {% include "partials/user_pages/annotations_contributed_panel.html" with annotation_data=annotation_data user=profile_user with_stats=True large_image=True %}
+ {% endfor %}
+ </ul>
+ <ul class="pagination pull-right img-ann-{{image.obj.guid}}-perpage" style="margin-left: 15px;">
+ <li class="active pagination-label"><a>Annotations par page : </a></li>
+ <li class="{% if user_contributed_annotations.paginator.per_page == 5 %}active{% endif %}">
+ <a {% if user_contributed_annotations.paginator.per_page != 5 %}href="{% url 'user_contributed' profile_user.id %}?&page=1&perpage=5"{% endif %}>5</a>
+ </li>
+ <li class="{% if user_contributed_annotations.paginator.per_page == 10 %}active{% endif %}">
+ <a {% if user_contributed_annotations.paginator.per_page != 10 %}href="{% url 'user_contributed' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=10"{% endif %}>10</a>
+ </li>
+ <li class="{% if user_contributed_annotations.paginator.per_page == 25 %}active{% endif %}">
+ <a {% if user_contributed_annotations.paginator.per_page != 25 %}href="{% url 'user_contributed' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=25"{% endif %}>25</a>
+ </li>
+ <li class="{% if user_contributed_annotations.paginator.per_page == 100 %}active{% endif %}">
+ <a {% if user_contributed_annotations.paginator.per_page != 100 %}href="{% url 'user_contributed' profile_user.id %}?show={{image.obj.image_guid}}&page=1&perpage=100"{% endif %}>100</a>
+ </li>
+ </ul>
+ {% if user_contributed_annotations.has_previous or user_contributed_annotations.has_next %}
+ <ul class="pagination pull-right">
+ {% if user_contributed_annotations.has_previous %}
+ <li>
+ <a href="{% url 'user_contributed' profile_user.id %}?page={{user_contributed_annotations.previous_page_number}}&perpage={{user_contributed_annotations.paginator.per_page}}" aria-label="Précédent">
+ <span aria-hidden="true">«</span>
+ </a>
+ </li>
+ {% endif %}
+ {% for page in user_contributed_annotations.paginator.page_range %}
+ <li id="page-link-{{page}}" class="pagination-link {% if page == user_contributed_annotations.number %}active{% endif %}">
+ <a {% if page != user_contributed_annotations.number %}href="{% url 'user_contributed' profile_user.id %}?page={{page}}&perpage={{user_contributed_annotations.paginator.per_page}}"{% endif %}>{{page}}</a>
+ </li>
+ {% endfor %}
+
+ {% if user_contributed_annotations.has_next %}
+ <li>
+ <a href="{% url 'user_contributed' profile_user.id %}?page={{user_contributed_annotations.next_page_number}}&perpage={{user_contributed_annotations.paginator.per_page}}" aria-label="Suivant">
+ <span aria-hidden="true">»</span>
+ </a>
+ </li>
+ {% endif %}
+ </ul>
+ {% endif %}
+ {% endif %}
+ </div>
+{% endblock %}
\ No newline at end of file
--- a/src/iconolab/templates/iconolab/user_home.html Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/templates/iconolab/user_home.html Wed Nov 09 14:16:49 2016 +0100
@@ -52,54 +52,63 @@
{% endif %}
<div class="row">
<div class="col-md-6">
- <h4>{% if profile_user == request.user %}Mes annotations :{% else %}Annotations de {{profile_user.username}}{% endif %} </h4>
+ <h4>{% if profile_user == request.user %}Mes dernières annotations :{% else %}Dernières annotations de {{profile_user.username}}{% endif %}</h4>
{% if not user_annotations %}
<h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
{% else %}
<ul class="list-inline">
{% for annotation in user_annotations.all %}
- {% include "partials/user_page_annotation_panel.html" with annotation=annotation %}
+ {% include "partials/user_pages/annotations_created_panel.html" with annotation=annotation user=profile_user %}
{% endfor %}
+ <li>
+ <a class="btn btn-default btn-sm" href="{% url 'user_annotations' profile_user.id %}"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Voir toutes les annotations</a>
+ </li>
</ul>
{% endif %}
</div>
<div class="col-md-6">
- <h4>{% if profile_user == request.user %}Mes autres contributions :{% else %}Contributions de {{profile_user.username}}{% endif %} </h4>
+ <h4>{% if profile_user == request.user %}Mes contributions :{% else %}Contributions de {{profile_user.username}}{% endif %}</h4>
<dl>
<dt class="dt-annotation">
{% if profile_user == request.user %}
- Annotations sur lesquelles j'ai proposé des révisions :
+ Dernières annotations sur lesquelles j'ai proposé des révisions :
{% else %}
- Annotations sur lesquelles {{profile_user.username}} a proposé des révisions :
+ Dernières annotations sur lesquelles {{profile_user.username}} a proposé des révisions :
{% endif %}
</dt>
<dd>
- {% if not user_revisions_annotations %}
+ {% if not user_contributed_annotations %}
<h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
{% else %}
<ul class="list-inline">
- {% for annotation in user_revisions_annotations.all %}
- {% include "partials/user_page_annotation_panel.html" with annotation=annotation %}
+ {% for annotation_data in user_contributed_annotations %}
+ {% include "partials/user_pages/annotations_contributed_panel.html" with annotation_data=annotation_data user=profile_user %}
{% endfor %}
+ <li>
+ <a class="btn btn-default btn-sm" href="{% url 'user_contributed' profile_user.id %}"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Voir toutes les contributions</a>
+ </li>
</ul>
{% endif %}
</dd>
<dt class="dt-annotation">
{% if profile_user == request.user %}
- Annotations sur lesquelles j'ai commenté (sans proposer de révision) :
+ Dernières annotation sur lesquelles j'ai commenté (sans proposer de révision) :
{% else %}
- Annotations sur lesquelles {{profile_user.username}} a commenté (sans proposer de révision) :
+ Dernières annotations sur lesquelles {{profile_user.username}} a commenté (sans proposer de révision) :
{% endif %}
</dt>
<dd>
- {% if not user_comments_annotations %}
+ {% if not user_commented_annotations %}
<h4 class="no-user-annotation"><small>Aucune annotation à afficher</small></h4>
{% else %}
- <ul class="list-inline">
- {% for annotation in user_comments_annotations.all %}
- {% include "partials/user_page_annotation_panel.html" with annotation=annotation %}
+ <ul class="list-unstyled">
+ {% for annotation_data in user_commented_annotations %}
+ {% include "partials/user_pages/annotations_commented_panel.html" with annotation_data=annotation_data user=profile_user %}
{% endfor %}
+ <li>
+ <a class="btn btn-default btn-sm" href="{% url 'user_commented' profile_user.id %}"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Voir toutes les annotations commentées</a>
+ </li>
</ul>
{% endif %}
</dd>
@@ -117,7 +126,7 @@
</div>
<h3><small>Administration du Fonds</small> {{user.profile.administers_collection.verbose_name}}</h3>
<div class="text-center">
- <a href="#" class="btn btn-default disabled text-center">Tableau de bord</a>
+ <a href="{% url 'user_admin_panel' profile_user.id %}" class="btn btn-default text-center">Tableau de bord</a>
</div>
</div>
</div>
--- a/src/iconolab/templates/partials/user_page_annotation_panel.html Mon Oct 31 10:08:18 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-{% load thumbnail %}
-{% load iconolab_tags %}
-<li>
- <div class="panel panel-default annotation-panel">
- <div class="panel-heading">{{annotation.current_revision.title}}</div>
-
- <div class="fragment-container" style="position:relative; display:inline-block">
- {% thumbnail annotation.image.media "150x150" crop=False as im %}
- <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
- <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
- <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
- <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
- <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
- </g>
- </svg>
- </a>
- {% endthumbnail %}
- </div>
- <div class="annotation-detail">
- <dl class="dl-horizontal">
- <dt>Commentaires : </dt>
- <dd><span class="badge">{{annotation.stats.comments_count}}</span></dd>
- <dt>Révisions en attente :</dt>
- <dd><span class="badge {% if annotation.stats.awaiting_revisions_count > 0 %}badge-warning{% endif %}">{{annotation.stats.awaiting_revisions_count}}</span></dd>
- <dt>Révisions acceptée :</dt>
- <dd><span class="badge">{{annotation.stats.accepted_revisions_count}}</span></dd>
- </dl>
- </div>
- <a class="btn btn-default btn-sm userpage-annotation-btn pull-right" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
- </div>
-</li>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/partials/user_pages/annotations_commented_panel.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,58 @@
+{% load thumbnail %}
+{% load iconolab_tags %}
+{% with annotation_data.annotation_obj as annotation %}
+<li>
+ <div class="panel panel-default annotation-panel">
+ <div class="panel-heading">
+ {% if annotation.current_revision.title %}
+ {{annotation.current_revision.title}}
+ {% else %}
+ <i>Annotation sans titre</i>
+ {% endif %}
+ </div>
+ <div class="panel-content">
+ <div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
+ {% if large_image %}
+ {% thumbnail annotation.image.media "450x450" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% else %}
+ {% thumbnail annotation.image.media "150x150" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% endif %}
+ </div>
+ <div class="annotation-detail">
+ <dl class="dl-horizontal">
+ <dt>Total commentaires : </dt>
+ <dd><span class="badge">{{annotation.stats.comments_count}}</span></dd>
+ <dt>.. Ecrits par {{user.username}} : </dt>
+ <dd><span class="badge badge-warning">{{annotation_data.comment_count_for_user}}</span></dd>
+ <dt>A commenté le : </dt>
+ <dd>{{annotation_data.latest_comment_date}}</dd>
+ </dl>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
+ </div>
+ {% if with_stats %}
+ <div class="stats-annotation-userpage">
+ {% include "partials/annotation_stats_panel.html" with annotation=annotation label="Statistiques sur cette annotation:" %}
+ </div>
+ {% endif %}
+ </div>
+ </div>
+</li>
+{% endwith %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/partials/user_pages/annotations_contributed_panel.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,60 @@
+{% load thumbnail %}
+{% load iconolab_tags %}
+{% with annotation_data.annotation_obj as annotation %}
+<li>
+ <div class="panel panel-default annotation-panel">
+ <div class="panel-heading">
+ {% if annotation.current_revision.title %}
+ {{annotation.current_revision.title}}
+ {% else %}
+ <i>Annotation sans titre</i>
+ {% endif %}
+ </div>
+ <div class="panel-content">
+ <div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
+ {% if large_image %}
+ {% thumbnail annotation.image.media "450x450" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% else %}
+ {% thumbnail annotation.image.media "150x150" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% endif %}
+ </div>
+ <div class="annotation-detail">
+ <dl class="dl-horizontal">
+ <dt>Total révisions: {{annotations.stats.revisions_count}} </dt>
+ <dd><span class="badge">{{annotation.stats.comments_count}}</span></dd>
+ <dt>Soumises par <i>{{user.username}}</i>: </dt>
+ <dd><span class="badge">{{annotation_data.revisions_count}}</span></dd>
+ <dt>.. Révisions en attente: </dt>
+ <dd><span class="badge {% if annotation_data.awaiting_count %}badge-warning{% endif %}">{{annotation_data.awaiting_count}}</span></dd>
+ <dt>.. Révisions acceptées: </dt>
+ <dd><span class="badge {% if annotation_data.accepted_count %}badge-success{% endif %}">{{annotation_data.accepted_count}}</span></dd>
+ </dl>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
+ </div>
+ {% if with_stats %}
+ <div class="stats-annotation-userpage">
+ {% include "partials/annotation_stats_panel.html" with annotation=annotation label="Statistiques sur cette annotation:" %}
+ </div>
+ {% endif %}
+ </div>
+ </div>
+</li>
+{% endwith %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/templates/partials/user_pages/annotations_created_panel.html Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,58 @@
+{% load thumbnail %}
+{% load iconolab_tags %}
+<li>
+ <div class="panel panel-default annotation-panel">
+ <div class="panel-heading">
+ {% if annotation.current_revision.title %}
+ {{annotation.current_revision.title}}
+ {% else %}
+ <i>Annotation sans titre</i>
+ {% endif %}
+ </div>
+ <div class="panel-content">
+ <div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
+ {% if large_image %}
+ {% thumbnail annotation.image.media "450x450" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% else %}
+ {% thumbnail annotation.image.media "150x150" crop=False as im %}
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
+ <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
+ <g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
+ <path d="{{ annotation.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
+ </g>
+ </svg>
+ </a>
+ {% endthumbnail %}
+ {% endif %}
+ </div>
+ <div class="annotation-detail">
+ <dl class="dl-horizontal">
+ <dl class="dl-horizontal">
+ <dt>A créé l'annotation le : </dt>
+ <dd><span>{{annotation.created}}</span></dd>
+ <dt>Commentaires : </dt>
+ <dd><span class="badge">{{annotation.stats.comments_count}}</span></dd>
+ <dt>Révisions en attente :</dt>
+ <dd><span class="badge {% if annotation.stats.awaiting_revisions_count > 0 %}badge-warning{% endif %}">{{annotation.stats.awaiting_revisions_count}}</span></dd>
+ </dl>
+ </dl>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
+ </div>
+ {% if with_stats %}
+ <div class="stats-annotation-userpage">
+ {% include "partials/annotation_stats_panel.html" with annotation=annotation label="Statistiques sur cette annotation:" %}
+ </div>
+ {% endif %}
+ </div>
+ </div>
+</li>
\ No newline at end of file
--- a/src/iconolab/urls.py Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/urls.py Wed Nov 09 14:16:49 2016 +0100
@@ -29,38 +29,42 @@
urlpatterns = [
url(r'^$', django_views.generic.RedirectView.as_view(url=reverse_lazy("home"))),
url(r'^admin/', admin.site.urls),
- url(r'^home$', views.iconolab_objects.GlobalHomepageView.as_view(), name="home"),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)$', views.iconolab_objects.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/items/(?P<item_guid>[^/]+)$', views.iconolab_objects.ShowItemView.as_view(), name='item_detail'),
+ url(r'^home$', views.objects.GlobalHomepageView.as_view(), name="home"),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)$', views.objects.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/items/(?P<item_guid>[^/]+)$', views.objects.ShowItemView.as_view(), name='item_detail'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/items/?$', django_views.generic.RedirectView.as_view(pattern_name="collection_home")),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/?$', django_views.generic.RedirectView.as_view(pattern_name="collection_home")),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)$', views.iconolab_objects.ShowImageView.as_view(), name='image_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)$', views.objects.ShowImageView.as_view(), name='image_detail'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/?$', django_views.generic.RedirectView.as_view(pattern_name="image_detail")),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.iconolab_objects.CreateAnnotationView.as_view()), name='annotation_create'),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.iconolab_objects.ShowAnnotationView.as_view(), name='annotation_detail'),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.iconolab_objects.EditAnnotationView.as_view()), name='annotation_edit'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.objects.CreateAnnotationView.as_view()), name='annotation_create'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.objects.ShowAnnotationView.as_view(), name='annotation_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.objects.EditAnnotationView.as_view()), name='annotation_edit'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/?$', django_views.generic.RedirectView.as_view(pattern_name="annotation_detail")),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.iconolab_objects.ShowRevisionView.as_view(), name='revision_detail'),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.iconolab_objects.MergeProposalView.as_view()), name='annotation_merge'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.objects.ShowRevisionView.as_view(), name='revision_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.objects.MergeProposalView.as_view()), name='annotation_merge'),
- url(r'^user/(?P<slug>[a-z0-9\-]+)/home/?$', views.iconolab_objects.UserHomeView.as_view(), name="user_home"),
- url(r'^user/notifications/all/?$', login_required(views.iconolab_objects.UserNotificationsView.as_view()), name="user_notifications"),
+ url(r'^user/(?P<slug>[a-z0-9\-]+)/home/?$', views.userpages.UserHomeView.as_view(), name="user_home"),
+ url(r'^user/(?P<slug>[a-z0-9\-]+)/commented/?$', views.userpages.UserCommentedView.as_view(), name="user_commented"),
+ url(r'^user/(?P<slug>[a-z0-9\-]+)/contributed/?$', views.userpages.UserContributedView.as_view(), name="user_contributed"),
+ url(r'^user/(?P<slug>[a-z0-9\-]+)/annotations/?$', views.userpages.UserAnnotationsView.as_view(), name="user_annotations"),
+ url(r'^user/(?P<slug>[a-z0-9\-]+)/adminpanel/$', views.userpages.UserCollectionAdminView.as_view(), name="user_admin_panel"),
+ url(r'^user/notifications/all/?$', login_required(views.userpages.UserNotificationsView.as_view()), name="user_notifications"),
url(r'^user/notifications/', include(notifications.urls, namespace='notifications')),
- url(r'^errors/404', views.iconolab_misc.NotFoundErrorView.as_view(), name="404error"),
+ url(r'^errors/404', views.misc.NotFoundErrorView.as_view(), name="404error"),
- url(r'^help/', views.iconolab_misc.HelpView.as_view(), name="iconolab_help"),
- url(r'^glossary/', views.iconolab_misc.GlossaryView.as_view(), name="iconolab_glossary"),
- url(r'^credits/', views.iconolab_misc.CreditsView.as_view(), name="iconolab_credits"),
- url(r'^contributioncharter/', views.iconolab_misc.ContributionCharterView.as_view(), name="iconolab_charter"),
- url(r'^legalmentions/', views.iconolab_misc.LegalMentionsView.as_view(), name="iconolab_legals"),
+ url(r'^help/', views.misc.HelpView.as_view(), name="iconolab_help"),
+ url(r'^glossary/', views.misc.GlossaryView.as_view(), name="iconolab_glossary"),
+ url(r'^credits/', views.misc.CreditsView.as_view(), name="iconolab_credits"),
+ url(r'^contributioncharter/', views.misc.ContributionCharterView.as_view(), name="iconolab_charter"),
+ url(r'^legalmentions/', views.misc.LegalMentionsView.as_view(), name="iconolab_legals"),
url(r'^account/', include('iconolab.auth.urls', namespace='account')),
url(r'^search/', include('iconolab.search_indexes.urls', namespace='search_indexes')),
url(r'^comments/', include('django_comments_xtd.urls')),
url(r'^comments/annotation/post', views.comments.post_comment_iconolab, name="post_comment"),
- url(r'^compare/$', views.iconolab_objects.TestView.as_view(), name="compare_view")
+ url(r'^compare/$', views.objects.TestView.as_view(), name="compare_view")
#url(r'^search/', include('haystack.urls'), name="search_iconolab"),
]
--- a/src/iconolab/views/__init__.py Mon Oct 31 10:08:18 2016 +0100
+++ b/src/iconolab/views/__init__.py Wed Nov 09 14:16:49 2016 +0100
@@ -1,3 +1,4 @@
from . import comments
-from . import iconolab_objects
-from . import iconolab_misc
\ No newline at end of file
+from . import objects
+from . import misc
+from . import userpages
\ No newline at end of file
--- a/src/iconolab/views/iconolab_misc.py Mon Oct 31 10:08:18 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-from django.views.generic import TemplateView
-
-class NotFoundErrorView(TemplateView):
- template_name='errors/404error.html'
-
-class HelpView(TemplateView):
- template_name='iconolab/misc/help.html'
-
-class GlossaryView(TemplateView):
- template_name='iconolab/misc/glossary.html'
-
-class CreditsView(TemplateView):
- template_name='iconolab/misc/credits.html'
-
-class LegalMentionsView(TemplateView):
- template_name='iconolab/misc/legalmentions.html'
-
-class ContributionCharterView(TemplateView):
- template_name='iconolab/misc/charter.html'
-
--- a/src/iconolab/views/iconolab_objects.py Mon Oct 31 10:08:18 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,653 +0,0 @@
-from django.shortcuts import HttpResponse, get_object_or_404, render
-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
-import logging
-
-logger = logging.getLogger(__name__)
-
-class GlobalHomepageView(View):
- def get(self, request, *args, **kwargs):
- context = {}
- context['collections'] = Collection.objects
- 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 UserHomeView(DetailView):
- model = User
- slug_field = 'id'
-
- def get_context_data(self, **kwargs):
- context = super(UserHomeView, self).get_context_data(**kwargs)
- return context
-
- def get(self, request, *args, **kwargs):
- self.object = self.get_object()
- context = self.get_context_data()
- profile_user = self.object
- context['profile_user'] = profile_user
- context['user_annotations'] = Annotation.objects.filter(author=profile_user).prefetch_related(
- 'current_revision',
- 'revisions',
- 'image',
- 'image__item',
- 'image__item__collection'
- )
- context['user_revisions_annotations'] = Annotation.objects.filter(revisions__author=profile_user).exclude(author=profile_user).prefetch_related(
- 'current_revision',
- 'revisions',
- 'image',
- 'image__item',
- 'image__item__collection'
- ).distinct()
- comments_annotations_str_id = IconolabComment.objects.filter(user=profile_user, content_type__app_label='iconolab', content_type__model='annotation').values_list('object_pk', flat=True)
- comments_annotations_id = [int(str_id) for str_id in comments_annotations_str_id]
- context['user_comments_annotations'] = Annotation.objects.filter(id__in=comments_annotations_id).exclude(author=profile_user).exclude(annotation_guid__in=context['user_revisions_annotations'].values_list('annotation_guid', flat=True)).prefetch_related(
- 'current_revision',
- 'revisions',
- 'image',
- 'image__item',
- 'image__item__collection'
- ).distinct()
- if request.user.is_authenticated() and self.object == request.user:
- if request.GET.get('clear_notifications', False):
- Notification.objects.filter(recipient=request.user).mark_all_as_read()
- context['notifications'] = Notification.objects.filter(recipient=request.user)
- return render(request, 'iconolab/user_home.html', context)
-
-class UserNotificationsView(View):
-
- def get(self, request, *args, **kwargs):
- context = {}
- notifications = Notification.objects.filter(recipient=request.user)
- context['notifications_unread_ids'] = notifications.unread().values_list('id', flat=True)
- page = request.GET.get('page', 1)
- paginator = Paginator(notifications, 50)
- try:
- notifications_list = paginator.page(page)
- except PageNotAnInteger:
- notifications_list = paginator.page(1)
- except EmptyPage:
- notifications_list = paginator.page(paginator.num_pages)
- context['notifications'] = notifications_list
- return render(request, 'iconolab/user_notifications.html', context)
-
-# Class with check_kwargs method to fetch objects from database depending on what level in the app we're currently at
-class IconolabObjectView(object):
- 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.select_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.select_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
-
-class CollectionHomepageView(View, ContextMixin, IconolabObjectView):
- def get(self, request, *args, **kwargs):
- 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
-
- # Paginated objects list
- context["items_page"] = items_page
- context["items_perpage"] = items_per_page
- items_paginator = Paginator(collection.items.all(), items_per_page)
- try:
- context["items_list"] = items_paginator.page(items_page)
- except PageNotAnInteger:
- context["items_list"] = items_paginator.page(1)
- except EmptyPage:
- context["items_list"] = items_paginator.page(items_paginator.num_pages)
-
- # Paginated recent annotations list
- context["recent_page"] = recent_page
- context["recent_perpage"] = recent_per_page
- recent_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
- 'current_revision',
- 'stats'
- ).order_by('-current_revision__created')
- recent_paginator = Paginator(recent_annotations, recent_per_page)
- try:
- context["recent_list"] = recent_paginator.page(recent_page)
- except PageNotAnInteger:
- context["recent_list"] = recent_paginator.page(1)
- except EmptyPage:
- context["recent_list"] = recent_paginator.page(recent_paginator.num_pages)
-
- # Paginated revised annotations list
- context["revised_page"] = revised_page
- context["revised_perpage"] = revised_per_page
- 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')
- revised_paginator = Paginator(revised_annotations, revised_per_page)
- try:
- context["revised_list"] = revised_paginator.page(revised_page)
- except PageNotAnInteger:
- context["revised_list"] = revised_paginator.page(1)
- except EmptyPage:
- context["revised_list"] = revised_paginator.page(revised_paginator.num_pages)
-
- # Paginated contribution calls annotation list
- context["contributions_page"] = contributions_page
- context["contributions_perpage"] = contributions_per_page
- 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]
- contributions_paginator = Paginator(contributions_annotations, contributions_per_page)
- try:
- context["contributions_list"] = contributions_paginator.page(contributions_page)
- except PageNotAnInteger:
- context["contributions_list"] = contributions_paginator.page(1)
- except EmptyPage:
- context["contributions_list"] = contributions_paginator.page(contributions_paginator.num_pages)
-
- return render(request, 'iconolab/collection_home.html', context)
-
-
-
-class ShowItemView(View, ContextMixin, IconolabObjectView):
- def get(self, request, *args, **kwargs):
- 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):
- 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
- return render(request, 'iconolab/detail_image.html', context)
-
-class CreateAnnotationView(View, ContextMixin, IconolabObjectView):
-
- 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)
- revision_comment = annotation_form.cleaned_data['comment']
- IconolabComment.objects.create(
- comment = revision_comment,
- revision = new_annotation.current_revision,
- content_type = ContentType.objects.get(app_label='iconolab', model='annotation'),
- content_object = new_annotation,
- site = Site.objects.get(id=settings.SITE_ID),
- object_pk = new_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': new_annotation.annotation_guid}))(request)
- 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):
-
- 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):
- 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 EditAnnotationView(View, ContextMixin, IconolabObjectView):
-
- 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)
- revision_comment = annotation_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['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):
-
- 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):
- 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):
-
- 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)
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/views/misc.py Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,20 @@
+from django.views.generic import TemplateView
+
+class NotFoundErrorView(TemplateView):
+ template_name='errors/404error.html'
+
+class HelpView(TemplateView):
+ template_name='iconolab/misc/help.html'
+
+class GlossaryView(TemplateView):
+ template_name='iconolab/misc/glossary.html'
+
+class CreditsView(TemplateView):
+ template_name='iconolab/misc/credits.html'
+
+class LegalMentionsView(TemplateView):
+ template_name='iconolab/misc/legalmentions.html'
+
+class ContributionCharterView(TemplateView):
+ template_name='iconolab/misc/charter.html'
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/views/objects.py Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,592 @@
+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
+import logging
+
+logger = logging.getLogger(__name__)
+
+class GlobalHomepageView(View):
+ def get(self, request, *args, **kwargs):
+ context = {}
+ context['collections'] = Collection.objects
+ 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):
+ 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
+
+class CollectionHomepageView(View, ContextMixin, IconolabObjectView):
+ def get(self, request, *args, **kwargs):
+ 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
+
+ # Paginated objects list
+ context["items_page"] = items_page
+ context["items_perpage"] = items_per_page
+ items_paginator = Paginator(collection.items.order_by("metadatas__inventory_number").all(), items_per_page)
+ try:
+ context["items_list"] = items_paginator.page(items_page)
+ except PageNotAnInteger:
+ context["items_list"] = items_paginator.page(1)
+ except EmptyPage:
+ context["items_list"] = items_paginator.page(items_paginator.num_pages)
+
+ # Paginated recent annotations list
+ context["recent_page"] = recent_page
+ context["recent_perpage"] = recent_per_page
+ recent_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
+ 'current_revision',
+ 'stats'
+ ).order_by('-current_revision__created')
+ recent_paginator = Paginator(recent_annotations, recent_per_page)
+ try:
+ context["recent_list"] = recent_paginator.page(recent_page)
+ except PageNotAnInteger:
+ context["recent_list"] = recent_paginator.page(1)
+ except EmptyPage:
+ context["recent_list"] = recent_paginator.page(recent_paginator.num_pages)
+
+ # Paginated revised annotations list
+ context["revised_page"] = revised_page
+ context["revised_perpage"] = revised_per_page
+ 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')
+ revised_paginator = Paginator(revised_annotations, revised_per_page)
+ try:
+ context["revised_list"] = revised_paginator.page(revised_page)
+ except PageNotAnInteger:
+ context["revised_list"] = revised_paginator.page(1)
+ except EmptyPage:
+ context["revised_list"] = revised_paginator.page(revised_paginator.num_pages)
+
+ # Paginated contribution calls annotation list
+ context["contributions_page"] = contributions_page
+ context["contributions_perpage"] = contributions_per_page
+ 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]
+ contributions_paginator = Paginator(contributions_annotations, contributions_per_page)
+ try:
+ context["contributions_list"] = contributions_paginator.page(contributions_page)
+ except PageNotAnInteger:
+ context["contributions_list"] = contributions_paginator.page(1)
+ except EmptyPage:
+ context["contributions_list"] = contributions_paginator.page(contributions_paginator.num_pages)
+
+ return render(request, 'iconolab/collection_home.html', context)
+
+
+
+class ShowItemView(View, ContextMixin, IconolabObjectView):
+ def get(self, request, *args, **kwargs):
+ 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):
+ 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
+ return render(request, 'iconolab/detail_image.html', context)
+
+class CreateAnnotationView(View, ContextMixin, IconolabObjectView):
+
+ 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)
+ revision_comment = annotation_form.cleaned_data['comment']
+ IconolabComment.objects.create(
+ comment = revision_comment,
+ revision = new_annotation.current_revision,
+ content_type = ContentType.objects.get(app_label='iconolab', model='annotation'),
+ content_object = new_annotation,
+ site = Site.objects.get(id=settings.SITE_ID),
+ object_pk = new_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': new_annotation.annotation_guid}))(request)
+ 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):
+
+ 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):
+ 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 EditAnnotationView(View, ContextMixin, IconolabObjectView):
+
+ 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)
+ revision_comment = annotation_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['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):
+
+ 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):
+ 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):
+
+ 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)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/views/userpages.py Wed Nov 09 14:16:49 2016 +0100
@@ -0,0 +1,231 @@
+from django.shortcuts import HttpResponse, get_object_or_404, render, redirect
+from django.views.generic import View, DetailView
+from django.core.urlresolvers import reverse_lazy
+from django.core.exceptions import ObjectDoesNotExist
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.sites.models import Site
+from django.conf import settings
+from django.urls import reverse
+from notifications.models import Notification
+from iconolab.models import Annotation, IconolabComment, Image, MetaCategoriesCountInfo
+from uuid import UUID
+import logging
+
+logger = logging.getLogger(__name__)
+
+class UserHomeView(DetailView):
+ model = User
+ slug_field = 'id'
+
+ def get_context_data(self, **kwargs):
+ context = super(UserHomeView, self).get_context_data(**kwargs)
+ return context
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ context = self.get_context_data()
+ profile_user = self.object
+ context['profile_user'] = profile_user
+ context['user_annotations'] = Annotation.objects.filter(author=profile_user).prefetch_related(
+ 'current_revision',
+ 'revisions',
+ 'image',
+ 'image__item',
+ 'image__item__collection'
+ ).order_by("-created")[:5]
+ context['user_contributed_annotations'] = Annotation.objects.get_annotations_contributed_for_user(profile_user)[:5]
+ context['user_commented_annotations'] = Annotation.objects.get_annotations_commented_for_user(profile_user)[:5]
+ # .exclude(annotation_guid__in=[annotation.annotation_guid for annotation in context['user_revisions_annotations']])
+
+ if request.user.is_authenticated() and self.object == request.user:
+ if request.GET.get('clear_notifications', False):
+ Notification.objects.filter(recipient=request.user).mark_all_as_read()
+ logger.debug(Notification.objects.filter(recipient=request.user))
+ context['notifications'] = Notification.objects.filter(recipient=request.user)
+ logger.debug(context)
+ return render(request, 'iconolab/user_home.html', context)
+
+class UserNotificationsView(View):
+
+ def get(self, request, *args, **kwargs):
+ context = {}
+ notifications = Notification.objects.filter(recipient=request.user)
+ context['notifications_unread_ids'] = notifications.unread().values_list('id', flat=True)
+ page = request.GET.get('page', 1)
+ paginator = Paginator(notifications, 50)
+ try:
+ notifications_list = paginator.page(page)
+ except PageNotAnInteger:
+ notifications_list = paginator.page(1)
+ except EmptyPage:
+ notifications_list = paginator.page(paginator.num_pages)
+ context['notifications'] = notifications_list
+ return render(request, 'iconolab/user_notifications.html', context)
+
+class UserAnnotationsView(DetailView):
+ model = User
+ slug_field = 'id'
+
+ def get_context_data(self, **kwargs):
+ context = super(UserAnnotationsView, self).get_context_data(**kwargs)
+ return context
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ profile_user = self.object
+ context = self.get_context_data()
+ page = request.GET.get('page', 1)
+ per_page=request.GET.get('perpage', 10)
+ paginator = Paginator(Annotation.objects.filter(author=profile_user).prefetch_related(
+ 'current_revision',
+ 'revisions',
+ 'image',
+ 'image__item',
+ 'image__item__collection'
+ ).order_by("-created").all(), per_page)
+ try:
+ annotations_list = paginator.page(page)
+ except PageNotAnInteger:
+ annotations_list = paginator.page(1)
+ except EmptyPage:
+ annotations_list = paginator.page(paginator.num_pages)
+ context['user_annotations'] = annotations_list
+ context['profile_user'] = profile_user
+ return render(request, 'iconolab/user_annotations.html', context)
+
+class UserCommentedView(DetailView):
+ model = User
+ slug_field = 'id'
+
+ def get_context_data(self, **kwargs):
+ context = super(UserCommentedView, self).get_context_data(**kwargs)
+ return context
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ profile_user = self.object
+ context = self.get_context_data()
+ page = request.GET.get('page', 1)
+ per_page=request.GET.get('perpage', 10)
+ paginator = Paginator(Annotation.objects.get_annotations_commented_for_user(profile_user), per_page)
+ try:
+ contributions_list = paginator.page(page)
+ except PageNotAnInteger:
+ contributions_list = paginator.page(1)
+ except EmptyPage:
+ contributions_list = paginator.page(paginator.num_pages)
+ context['user_commented_annotations'] = contributions_list
+ context['profile_user'] = profile_user
+ return render(request, 'iconolab/user_commented.html', context)
+
+class UserContributedView(DetailView):
+ model = User
+ slug_field = 'id'
+
+ def get_context_data(self, **kwargs):
+ context = super(UserContributedView, self).get_context_data(**kwargs)
+ return context
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ profile_user = self.object
+ context = self.get_context_data()
+ page = request.GET.get('page', 1)
+ per_page=request.GET.get('perpage', 10)
+ paginator = Paginator(Annotation.objects.get_annotations_contributed_for_user(profile_user), per_page)
+ try:
+ commented_list = paginator.page(page)
+ except PageNotAnInteger:
+ commented_list = paginator.page(1)
+ except EmptyPage:
+ commented_list = paginator.page(paginator.num_pages)
+ context['user_contributed_annotations'] = commented_list
+ context['profile_user'] = profile_user
+ return render(request, 'iconolab/user_contributed.html', context)
+
+class UserCollectionAdminView(DetailView):
+ model = User
+ slug_field = 'id'
+
+ def get_context_data(self, **kwargs):
+ context = super(UserCollectionAdminView, self).get_context_data(**kwargs)
+ return context
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ profile_user = self.object
+ context = self.get_context_data()
+
+ if not request.user.is_staff and not request.user.is_authenticated or profile_user != request.user or not request.user.profile.administers_collection:
+ return redirect(reverse_lazy('user_home', kwargs={'slug': profile_user.id}))
+ collection = request.user.profile.administers_collection
+
+ annotation_queryset = Annotation.objects.distinct().filter(image__item__collection=collection).prefetch_related('current_revision', 'stats', 'image', 'image__item')
+
+ # filtering
+ comments_count_filter = request.GET.get("min_comments", "")
+ if comments_count_filter and comments_count_filter.isdigit():
+ comments_count_filter = int(comments_count_filter)
+ annotation_queryset = annotation_queryset.filter(stats__comments_count__gte=comments_count_filter)
+ revisions_count_filter = request.GET.get("min_revisions", "")
+ if revisions_count_filter and revisions_count_filter.isdigit():
+ revisions_count_filter = int(revisions_count_filter)
+ annotation_queryset = annotation_queryset.filter(stats__submitted_revisions_count__gte=revisions_count_filter)
+ relevancy_filter = request.GET.get("min_relevancy", "")
+ if relevancy_filter and relevancy_filter.isdigit():
+ min_relevancy = min(int(relevancy_filter), 5)
+ annotation_queryset = annotation_queryset.filter(current_revision__tagginginfo__relevancy__gte=min_relevancy)
+ accuracy_filter = request.GET.get("min_accuracy", "")
+ if accuracy_filter and accuracy_filter.isdigit():
+ min_accuracy = min(int(accuracy_filter), 5)
+ annotation_queryset = annotation_queryset.filter(current_revision__tagginginfo__accuracy__gte=min_accuracy)
+ on_image_filter = request.GET.get("on_image", "")
+ is_uuid = True
+ try:
+ UUID(on_image_filter, version=4)
+ except ValueError:
+ # If it's a value error, then the string
+ # is not a valid hex code for a UUID.
+ is_uuid = False
+ if is_uuid and Image.objects.filter(image_guid = on_image_filter).exists():
+ annotation_queryset = annotation_queryset.filter(image__image_guid=on_image_filter)
+
+ metacategories_filter = []
+ mtcg_annotations_ids = []
+ filtering_on_metacategories = False
+ for metacategory in collection.metacategories.all():
+ mtcg_filter = request.GET.get("min_metacategory_"+str(metacategory.id), "")
+ if mtcg_filter:
+ filtering_on_metacategories = True
+ for annotation in annotation_queryset.all():
+ if MetaCategoriesCountInfo.objects.filter(metacategory=metacategory, annotation_stats_obj=annotation.stats, count__gte=int(mtcg_filter)).exists():
+ mtcg_annotations_ids.append(annotation.annotation_guid)
+# mtcg_annotations_ids.append(
+# annotation_queryset.filter(
+# stats__metacategoriescountinfo_set__metacategory__id=metacategory.id,
+# ).values_list('annotation_guid', flat=True))
+ logger.debug("FILTERING %r metacategory %r", str(mtcg_filter), metacategory.label)
+ if filtering_on_metacategories:
+ annotation_queryset = annotation_queryset.filter(annotation_guid__in=mtcg_annotations_ids)
+
+ # ordering
+ ordering = []
+ orderby_map = {
+ "oldest": "created",
+ "recent": "-created",
+ "most_commented": "-stats__comments_count",
+ "most_tagged": "-stats__tag_count",
+ "most_revised": "-stats__submitted_revisions_count",
+ "most_viewed": "-stats__views_count"
+ }
+ for ordering_qarg in ["first", "second", "third", "fourth"]:
+ if request.GET.get(ordering_qarg, "") in ["oldest", "recent", "most_commented", "most_tagged", "most_revised", "most_viewed"] and orderby_map.get(request.GET.get(ordering_qarg)) not in ordering:
+ ordering.append(orderby_map.get(request.GET.get(ordering_qarg)))
+ annotation_queryset = annotation_queryset.order_by(*ordering)
+ context["collection_filtered_annotations"] = annotation_queryset
+ context["collection"] = collection
+ logger.debug(ordering)
+ logger.debug(annotation_queryset)
+ return render(request, 'iconolab/user_collection_admin.html', context)
\ No newline at end of file