Work on admin interface and user pages + added stat metacategories count for annotations + refactored views module #41
authordurandn
Wed, 09 Nov 2016 14:16:49 +0100
changeset 238 ad770589f0fe
parent 237 d710b051cdc5
child 239 9b06e08f6949
Work on admin interface and user pages + added stat metacategories count for annotations + refactored views module #41
src/iconolab/migrations/0014_auto_20161108_1458.py
src/iconolab/models.py
src/iconolab/signals/handlers.py
src/iconolab/static/iconolab/css/iconolab.css
src/iconolab/templates/iconolab/user_annotations.html
src/iconolab/templates/iconolab/user_collection_admin.html
src/iconolab/templates/iconolab/user_commented.html
src/iconolab/templates/iconolab/user_contributed.html
src/iconolab/templates/iconolab/user_home.html
src/iconolab/templates/partials/user_page_annotation_panel.html
src/iconolab/templates/partials/user_pages/annotations_commented_panel.html
src/iconolab/templates/partials/user_pages/annotations_contributed_panel.html
src/iconolab/templates/partials/user_pages/annotations_created_panel.html
src/iconolab/urls.py
src/iconolab/views/__init__.py
src/iconolab/views/iconolab_misc.py
src/iconolab/views/iconolab_objects.py
src/iconolab/views/misc.py
src/iconolab/views/objects.py
src/iconolab/views/userpages.py
--- /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">&laquo;</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">&raquo;</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">&laquo;</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">&raquo;</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">&laquo;</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">&raquo;</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