# HG changeset patch # User durandn # Date 1470232023 -7200 # Node ID f747c112e8f411cc49876b08ef99f7aab5c03d8b # Parent 09b2da30cd932427a869cf6afa07e6d01ab87297 Started work on notification and user homepage + method for a comment to find back its page in his annotation's comments diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/auth/views.py --- a/src/iconolab/auth/views.py Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/auth/views.py Wed Aug 03 15:47:03 2016 +0200 @@ -62,7 +62,6 @@ form = self.get_form() if form.is_valid(): form.save() - print(request.POST) user = authenticate(username=request.POST["username"], password=request.POST["password1"]) login(request, user) return HttpResponseRedirect(self.success_url) diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/fixtures/demo_data.json --- a/src/iconolab/fixtures/demo_data.json Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/fixtures/demo_data.json Wed Aug 03 15:47:03 2016 +0200 @@ -222,7 +222,7 @@ "pk": 2, "fields": { "collection": 1, - "label": "Appel à expert" + "label": "Appel à expertise" } },{ "model": "iconolab.MetaCategory", diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/migrations/0005_auto_20160802_1211.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/migrations/0005_auto_20160802_1211.py Wed Aug 03 15:47:03 2016 +0200 @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-02 12:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('iconolab', '0004_auto_20160711_1514'), + ] + + operations = [ + migrations.AlterModelOptions( + name='iconolabcomment', + options={'ordering': ['thread_id', 'id']}, + ), + migrations.AddField( + model_name='annotationstats', + name='awaiting_revisions_count', + field=models.IntegerField(blank=True, default=0, null=True), + ), + ] diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/migrations/0006_metacategory_triggers_notifications.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/migrations/0006_metacategory_triggers_notifications.py Wed Aug 03 15:47:03 2016 +0200 @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-02 12:52 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('iconolab', '0005_auto_20160802_1211'), + ] + + operations = [ + migrations.AddField( + model_name='metacategory', + name='triggers_notifications', + field=models.IntegerField(choices=[(0, 'none'), (1, 'contributors'), (2, 'commenters'), (3, 'collection admins')], default=0), + ), + ] diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/models.py --- a/src/iconolab/models.py Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/models.py Wed Aug 03 15:47:03 2016 +0200 @@ -132,6 +132,7 @@ class AnnotationStats(models.Model): annotation = models.OneToOneField('Annotation', related_name='stats', blank=False, null=False) submitted_revisions_count = models.IntegerField(blank=True, null=True, default=1) + awaiting_revisions_count = models.IntegerField(blank=True, null=True, default=0) accepted_revisions_count = models.IntegerField(blank=True, null=True, default=1) contributors_count = models.IntegerField(blank=True, null=True, default=1) views_count = models.IntegerField(blank=True, null=True, default=0) @@ -140,11 +141,13 @@ @property def contributors(self): - contributors = [] - for revision in self.annotation.revisions.filter(state__in=[AnnotationRevision.ACCEPTED, AnnotationRevision.STUDIED]): - if revision.author not in contributors: - contributors.append(revision.author) - return contributors + user_ids_list = self.annotation.revisions.filter(state__in=[AnnotationRevision.ACCEPTED, AnnotationRevision.STUDIED]).values_list("author__id", flat=True) + return User.objects.filter(id__in=user_ids_list).distinct() + + @property + def commenters(self): + user_ids_list = IconolabComment.objects.filter(content_type__app_label="iconolab", content_type__model="annotation", object_pk=self.annotation.id).values_list("user__id", flat=True) + return User.objects.filter(id__in=user_ids_list).distinct() def set_tags_stats(self): self.tag_count = Tag.objects.filter(tagginginfo__revision__annotation = self.annotation).distinct().count() @@ -155,6 +158,8 @@ # submitted_revisions_count annotation_revisions = self.annotation.revisions self.submitted_revisions_count = annotation_revisions.count() + # aawaiting_revisions_count + self.awaiting_revisions_count = annotation_revisions.filter(state=AnnotationRevision.AWAITING).count() # accepted_revisions_count self.accepted_revisions_count = annotation_revisions.filter(state=AnnotationRevision.ACCEPTED).count() + annotation_revisions.filter(state=AnnotationRevision.STUDIED).count() # comment_count @@ -178,6 +183,11 @@ objects = AnnotationManager() + @property + def awaiting_revisions_count(self): + return self.revisions.filter(state=AnnotationRevision.AWAITING).distinct().count() + + # Call to create a new revision, possibly from a merge @transaction.atomic def make_new_revision(self, author, title, description, fragment, tags_json): @@ -362,10 +372,31 @@ class Meta: ordering = ["thread_id", "id"] + # Get page for considered comment, with COMMENTS_PER_PAGE_DEFAULT comments per page + def get_comment_page(self): + return self._default_manager.filter( + object_pk=self.object_pk, + content_type__app_label=self.content_type.app_label, + content_type__model=self.content_type.model + ).order_by("thread_id", "-order").filter(thread_id__lt=self.thread_id, order__gt=self.order).count() // settings.COMMENTS_PER_PAGE_DEFAULT + 1 + class MetaCategory(models.Model): + NONE = 0 # Notifies nobody + CONTRIBUTORS = 1 # Notifies contributors (revision owners) on target annotation + COMMENTERS = 2 # Notifies commenters (contributors + comment owners) on target annotation + COLLECTION_ADMINS = 3 # Notifies collection admins + + NOTIFIED_USERS = ( + (NONE, 'none'), + (CONTRIBUTORS, 'contributors'), + (COMMENTERS, 'commenters'), + (COLLECTION_ADMINS, 'collection admins'), + ) + collection = models.ForeignKey(Collection) label = models.CharField(max_length=255) - + triggers_notifications = models.IntegerField(choices=NOTIFIED_USERS, default=NONE) + def __str__(self): return self.label diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/settings/__init__.py --- a/src/iconolab/settings/__init__.py Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/settings/__init__.py Wed Aug 03 15:47:03 2016 +0200 @@ -58,12 +58,14 @@ 'django_comments_xtd', 'iconolab.apps.IconolabApp', 'sorl.thumbnail', + 'notifications' ] COMMENTS_APP = "django_comments_xtd" COMMENTS_XTD_MODEL = "iconolab.models.IconolabComment" COMMENTS_XTD_FORM_CLASS = 'iconolab.forms.comments.IconolabCommentForm' COMMENTS_XTD_MAX_THREAD_LEVEL = 100 +COMMENTS_PER_PAGE_DEFAULT = 10 SITE_ID = 1 diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/settings/dev.py.tmpl --- a/src/iconolab/settings/dev.py.tmpl Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/settings/dev.py.tmpl Wed Aug 03 15:47:03 2016 +0200 @@ -57,11 +57,14 @@ 'reversion_compare', 'iconolab.apps.IconolabApp', 'sorl.thumbnail', + 'notifications' ] COMMENTS_APP = "django_comments_xtd" COMMENTS_XTD_MODEL = "iconolab.models.IconolabComment" +COMMENTS_XTD_FORM_CLASS = 'iconolab.forms.comments.IconolabCommentForm' COMMENTS_XTD_MAX_THREAD_LEVEL = 100 +COMMENTS_PER_PAGE_DEFAULT = 10 SITE_ID = 1 diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/signals/handlers.py --- a/src/iconolab/signals/handlers.py Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/signals/handlers.py Wed Aug 03 15:47:03 2016 +0200 @@ -1,11 +1,12 @@ from django.apps import apps from django.db.models.signals import post_save from django.dispatch import Signal, receiver - +from notifications.signals import notify +from django_comments.signals import comment_was_posted # Signal sent during method Annotation.validate_existing_revision to update stats -revision_accepted = Signal(providing_args=["instance"]) -revision_created = Signal(providing_args=["instance"]) +revision_accepted = Signal(providing_args=['instance']) +revision_created = Signal(providing_args=['instance']) def increment_stats_on_new_revision(sender, instance, **kwargs): @@ -16,6 +17,8 @@ annotation.stats.submitted_revisions_count += 1 if instance.state in [AnnotationRevision.ACCEPTED, AnnotationRevision.STUDIED]: annotation.stats.accepted_revisions_count += 1 + if instance.state in [AnnotationRevision.AWAITING]: + annotation.stats.awaiting_revisions_count += 1 annotation.stats.set_tags_stats() annotation.stats.save() # Image stats @@ -23,7 +26,7 @@ image.stats.submitted_revisions_count += 1 image.stats.set_tags_stats() image.stats.save() - + def increment_stats_on_new_comments(sender, instance, created, **kwargs): from iconolab.models import IconolabComment @@ -53,8 +56,50 @@ image.stats.set_tags_stats() image.stats.save() + +def notify_users_on_new_comment(sender, comment, **kwargs): + from iconolab.models import IconolabComment, Annotation, MetaCategory + if sender == IconolabComment and instance.content_type.app_label == 'iconolab' and instance.content_type.model == 'annotation': + comment_annotation = Annotation.objects.get(id=instance.object_pk) + # Notifying new user comment + if instance.user != comment_annotation.author: + notify.send(instance.user, recipient=comment_annotation.author, verb='a écrit un commentaire sur votre annotation', action_object=instance, target=comment_annotation) + print(instance.parent_id) + print(instance.id) + if instance.level > 0: + parent_comment = IconolabComment.objects.get(id=instance.parent_id) + notify.send(instance.user, recipient=parent_comment.user, verb='a répondu à votre commentaire', action_object=instance, target=comment_annotation) + for metacategory in instance.metacategories.all(): + if metacategory.triggers_notifications == MetaCategory.COMMENTERS: + for commenter in comment_annotation.stats.commenters.exclude(id=instance.user.id).all(): + notify.send(instance.user, recipient=commenter, verb='a fait un appel à contribution', action_object=instance, target=comment_annotation) + elif metacategory.triggers_notifications == MetaCategory.CONTRIBUTORS: + for contributor in comment_annotation.stats.contributors.exclude(id=instance.user.id).all(): + notify.send(instance.user, recipient=contributor, verb='a fait un appel à contribution', action_object=instance, target=comment_annotation) + if metacategory.triggers_notifications == MetaCategory.COLLECTION_ADMINS: + pass + +def notify_users_on_new_revision(sender, instance, **kwargs): + 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) + + +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) + + +# Stats handlers connect post_save.connect(increment_annotations_count) post_save.connect(increment_stats_on_new_comments) revision_created.connect(increment_stats_on_new_revision) revision_accepted.connect(increment_accepted_revisions) +# Notifications handlers connect +comment_was_posted.connect(notify_users_on_new_comment) +revision_created.connect(notify_users_on_new_revision) +revision_accepted.connect(notify_users_on_accepted_revision) \ No newline at end of file diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/static/iconolab/css/iconolab.css --- a/src/iconolab/static/iconolab/css/iconolab.css Tue Aug 02 11:13:52 2016 +0200 +++ b/src/iconolab/static/iconolab/css/iconolab.css Wed Aug 03 15:47:03 2016 +0200 @@ -68,4 +68,39 @@ .pagination-shortcut{ cursor: pointer; +} + +.badge-error { + background-color: #b94a48; +} +.badge-error:hover { + background-color: #953b39; +} +.badge-warning { + background-color: #f89406; +} +.badge-warning:hover { + background-color: #c67605; +} +.badge-success { + background-color: #468847; +} +.badge-success:hover { + background-color: #356635; +} +.badge-info { + background-color: #3a87ad; +} +.badge-info:hover { + background-color: #2d6987; +} +.badge-inverse { + background-color: #333333; +} +.badge-inverse:hover { + background-color: #1a1a1a; +} + +.notif-badge{ + margin-bottom: 5px; } \ No newline at end of file diff -r 09b2da30cd93 -r f747c112e8f4 src/iconolab/templates/iconolab/user_home.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/templates/iconolab/user_home.html Wed Aug 03 15:47:03 2016 +0200 @@ -0,0 +1,106 @@ +{% extends 'iconolab_base.html' %} + +{% load staticfiles %} + +{% load thumbnail %} + +{% load iconolab_tags %} +{% load notifications_tags %} + +{% block content %} +