Skip to content

Commit

Permalink
Merge e948733 into 41d0eb4
Browse files Browse the repository at this point in the history
  • Loading branch information
ChantyTaguan committed Jan 13, 2017
2 parents 41d0eb4 + e948733 commit 4e30796
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 18 deletions.
4 changes: 2 additions & 2 deletions templates/forum/category/forum.html
Expand Up @@ -104,7 +104,7 @@

{% block sidebar_actions %}
<li>
{% with forum_is_followed=forum|is_forum_followed %}
{% with forum_is_followed=forum|is_followed_for_new_topic %}
{% url 'forum-topics-list' forum.category.slug forum.slug as link_follow %}
{% if forum_is_followed %}
{% trans "Suivre ce forum" as data_onclick %}
Expand All @@ -117,7 +117,7 @@
{% endwith %}
</li>
<li>
{% with forum_is_email_followed=forum|is_forum_email_followed %}
{% with forum_is_email_followed=forum|is_email_followed_for_new_topic %}
{% url 'forum-topics-list' forum.category.slug forum.slug as link_follow %}
{% if forum_is_email_followed %}
{% trans "Être notifié par courriel" as data_onclick %}
Expand Down
33 changes: 32 additions & 1 deletion templates/forum/find/topic_by_tag.html
Expand Up @@ -2,6 +2,7 @@
{% load profile %}
{% load emarkdown %}
{% load i18n %}
{% load interventions %}


{% block title %}
Expand Down Expand Up @@ -37,6 +38,36 @@
{% endblock %}


{% block sidebar_actions %}
<li>
{% with tag_is_followed=tag|is_followed_for_new_topic %}
{% url 'topic-tag-find' tag.slug as link_follow %}
{% if tag_is_followed %}
{% trans "Suivre ce tag" as data_onclick %}
{% trans "Ne plus suivre ce tag" as button_text %}
{% else %}
{% trans "Suivre ce tag" as button_text %}
{% trans "Ne plus suivre ce tag" as data_onclick %}
{% endif %}
{% include 'notification/follow_template.html' with link=link_follow is_followed=tag_is_followed data_onclick=data_onclick button_text=button_text subscriber_count=subscriber_count %}
{% endwith %}
</li>
<li>
{% with tag_is_email_followed=tag|is_email_followed_for_new_topic %}
{% url 'topic-tag-find' tag.slug as link_follow %}
{% if tag_is_email_followed %}
{% trans "Être notifié par courriel" as data_onclick %}
{% trans "Ne plus être notifié par courriel" as button_text %}
{% else %}
{% trans "Être notifié par courriel" as button_text %}
{% trans "Ne plus être notifié par courriel" as data_onclick %}
{% endif %}
{% include 'notification/follow_by_email_template.html' with link=link_follow is_followed=tag_is_email_followed data_onclick=data_onclick button_text=button_text %}
{% endwith %}
</li>
{% endblock %}


{% block sidebar_blocks %}
<div class="mobile-menu-bloc mobile-all-links mobile-show-ico" data-title="Filtres">
<h3>{% trans "Filtres" %}</h3>
Expand Down Expand Up @@ -73,4 +104,4 @@ <h3>{% trans "Filtres" %}</h3>
{% endif %}
</ul>
</div>
{% endblock %}
{% endblock %}
9 changes: 5 additions & 4 deletions zds/forum/commons.py
Expand Up @@ -16,12 +16,12 @@

class ForumEditMixin(object):
@staticmethod
def perform_follow(forum, user):
return NewTopicSubscription.objects.toggle_follow(forum, user).is_active
def perform_follow(forum_or_tag, user):
return NewTopicSubscription.objects.toggle_follow(forum_or_tag, user).is_active

@staticmethod
def perform_follow_by_email(forum, user):
return NewTopicSubscription.objects.toggle_follow(forum, user, True).is_active
def perform_follow_by_email(forum_or_tag, user):
return NewTopicSubscription.objects.toggle_follow(forum_or_tag, user, True).is_active


class TopicEditMixin(object):
Expand Down Expand Up @@ -95,6 +95,7 @@ def perform_edit_info(topic, data, editor):
topic.tags.clear()
if data.get('tags'):
topic.add_tags(data.get('tags').split(','))

return topic


Expand Down
1 change: 1 addition & 0 deletions zds/forum/models.py
Expand Up @@ -259,6 +259,7 @@ def add_tags(self, tag_collection):
logging.getLogger('zds.forum').warn(e)

self.save()
signals.edit_content.send(sender=self.__class__, instance=self, action='edit_tags_and_title')

def last_read_post(self):
"""
Expand Down
19 changes: 18 additions & 1 deletion zds/forum/views.py
Expand Up @@ -388,7 +388,7 @@ def get_object(self, queryset=None):
return get_object_or_404(User, pk=self.kwargs.get(self.pk_url_kwarg))


class FindTopicByTag(FilterMixin, ZdSPagingListView, SingleObjectMixin):
class FindTopicByTag(FilterMixin, ForumEditMixin, ZdSPagingListView, SingleObjectMixin):

context_object_name = 'topics'
paginate_by = settings.ZDS_APP['forum']['topics_per_page']
Expand All @@ -401,13 +401,30 @@ def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(FindTopicByTag, self).get(request, *args, **kwargs)

@method_decorator(login_required)
@method_decorator(can_write_and_read_now)
@method_decorator(transaction.atomic)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
response = {}
if 'follow' in request.POST:
response['follow'] = self.perform_follow(self.object, request.user)
elif 'email' in request.POST:
response['email'] = self.perform_follow_by_email(self.object, request.user)

self.object.save()
if request.is_ajax():
return HttpResponse(json.dumps(response), content_type='application/json')
return redirect(u"{}?page={}".format(self.object.get_absolute_url(), self.page))

def get_context_data(self, *args, **kwargs):
context = super(FindTopicByTag, self).get_context_data(*args, **kwargs)
context['topics'] = list(context['topics'].all())
# we need to load it in memory because later we will get the
# "already read topic" set out of this list and MySQL does not support that type of subquery
context.update({
'tag': self.object,
'subscriber_count': NewTopicSubscription.objects.get_subscriptions(self.object).count(),
'topic_read': TopicRead.objects.list_read_topic_pk(self.request.user, context['topics'])
})
return context
Expand Down
48 changes: 45 additions & 3 deletions zds/notification/receivers.py
Expand Up @@ -7,6 +7,8 @@

import zds

from zds.utils.models import Tag

try:
from functools import wraps
except ImportError:
Expand Down Expand Up @@ -81,6 +83,12 @@ def mark_topic_notifications_read(sender, **kwargs):
if subscription:
subscription.mark_notification_read(content=topic)

# Subscription to the tags
for tag in topic.tags.all():
subscription = NewTopicSubscription.objects.get_existing(user, tag, is_active=True)
if subscription:
subscription.mark_notification_read(content=topic)

content_type = ContentType.objects.get_for_model(topic)
notifications = Notification.objects.filter(subscription__user=user, object_id=topic.pk,
content_type__pk=content_type.pk, is_read=False,
Expand Down Expand Up @@ -152,18 +160,19 @@ def edit_topic_event(sender, **kwargs):
- instance: the topic edited.
- action: action of the edit.
"""
topic = kwargs.get('instance')
topic_content_type = ContentType.objects.get_for_model(topic)

if kwargs.get('action') == 'move':
topic = kwargs.get('instance')

# If the topic is moved to a restricted forum, users who cannot read this topic any more unfollow it.
# This avoids unreachable notifications.
TopicAnswerSubscription.objects.unfollow_and_mark_read_everybody_at(topic)
NewTopicSubscription.objects.mark_read_everybody_at(topic)
# If the topic is moved to a forum followed by the user, we update the subscription of the notification.
# Otherwise, we update the notification as dead.
content_type = ContentType.objects.get_for_model(topic)
notifications = Notification.objects \
.filter(object_id=topic.pk, content_type__pk=content_type.pk, is_read=False).all()
.filter(object_id=topic.pk, content_type__pk=topic_content_type.pk, is_read=False).all()
for notification in notifications:
subscription = NewTopicSubscription.objects \
.get_existing(notification.subscription.user, topic.forum, is_active=True)
Expand All @@ -174,6 +183,39 @@ def edit_topic_event(sender, **kwargs):
notification.is_dead = True
notification.save()

elif kwargs.get('action') == 'edit_tags_and_title':
topic = kwargs.get('instance')

# Update notification as dead if it was triggered by a deleted tag
tag_content_type = ContentType.objects.get_for_model(Tag)
notifications = Notification.objects \
.filter(object_id=topic.pk, content_type__pk=topic_content_type.pk, is_read=False).all()
for notification in notifications:
is_still_valid = not notification.subscription.content_type == tag_content_type
if not is_still_valid:
for tag in topic.tags.all():
if tag.id == notification.subscription.object_id:
is_still_valid = True
break
if not is_still_valid:
subscription = NewTopicSubscription.objects \
.get_existing(notification.subscription.user, topic.forum, is_active=True)
if subscription:
notification.subscription = subscription
else:
notification.is_dead = True
notification.save()

# Add notification of new topic for the subscription on the new tags
for tag in topic.tags.all():
subscriptions = NewTopicSubscription.objects.filter(
object_id=tag.id, content_type__pk=tag_content_type.pk, is_active=True)
for subscription in subscriptions:
notification = Notification.objects.filter(object_id=topic.id, subscription=subscription)
if not notification:
if subscription.user != topic.author:
subscription.send_notification(content=topic, sender=topic.author)


@receiver(post_save, sender=Topic)
@disable_for_loaddata
Expand Down
91 changes: 90 additions & 1 deletion zds/notification/tests/tests_basics.py
Expand Up @@ -9,7 +9,7 @@
from django.db import IntegrityError

from zds import settings
from zds.forum.factories import CategoryFactory, ForumFactory, TopicFactory, PostFactory
from zds.forum.factories import CategoryFactory, ForumFactory, TopicFactory, PostFactory, TagFactory
from zds.forum.models import Topic
from zds.gallery.factories import UserGalleryFactory
from zds.member.factories import ProfileFactory, StaffProfileFactory, UserFactory
Expand All @@ -34,6 +34,9 @@ def setUp(self):
self.forum11 = ForumFactory(category=self.category1, position_in_category=1)
self.forum12 = ForumFactory(category=self.category1, position_in_category=2)

self.tag1 = TagFactory(title='Linux')
self.tag2 = TagFactory(title='Windows')

self.assertTrue(self.client.login(username=self.user1.username, password='hostel77'))

def test_creation_topic(self):
Expand Down Expand Up @@ -372,6 +375,92 @@ def test_move_topic_from_forum_followed_to_forum_followed_too(self):

self.assertEqual(1, len(Notification.objects.filter(object_id=topic.pk, is_read=True, is_dead=False).all()))

def test_notifications_on_a_tag_subscribed(self):
"""
When a user subscribes to a tag, they receive a notification for each topic created.
"""
# Subscribe.
NewTopicSubscription.objects.toggle_follow(self.tag1, self.user1)

topic1 = TopicFactory(forum=self.forum11, author=self.user2)
topic1.add_tags(['Linux'])

notifications = Notification.objects.filter(object_id=topic1.pk, is_read=False).all()
self.assertEqual(1, len(notifications))

# Unsubscribe.
NewTopicSubscription.objects.toggle_follow(self.tag1, self.user1)

topic2 = TopicFactory(forum=self.forum11, author=self.user2)
topic2.add_tags(['Linux'])
notifications = Notification.objects.filter(object_id=topic2.pk, is_read=False).all()
self.assertEqual(0, len(notifications))

def test_mark_read_a_topic_of_a_tag_subscribed(self):
"""
When a user has a notification on a topic, the notification should be marked as read.
"""
NewTopicSubscription.objects.toggle_follow(self.tag1, self.user1)

topic = TopicFactory(forum=self.forum11, author=self.user2)
topic.add_tags(['Linux'])

PostFactory(topic=topic, author=self.user2, position=1)
notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all()
self.assertEqual(1, len(notifications))

response = self.client.get(reverse('topic-posts-list', args=[topic.pk, topic.slug()]))
self.assertEqual(response.status_code, 200)

notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all()
self.assertEqual(0, len(notifications))

def test_add_subscribed_tag(self):
"""
When the topic is edited and a tag is added to which the user has subscribed
"""
NewTopicSubscription.objects.toggle_follow(self.tag1, self.user2)

topic = TopicFactory(forum=self.forum11, author=self.user1)
PostFactory(topic=topic, author=self.user1, position=1)

self.client.post(
reverse('topic-edit') + '?topic={0}'.format(topic.pk),
{
'title': u'Un autre sujet',
'subtitle': u'Encore ces lombards en plein ete',
'text': u'C\'est tout simplement l\'histoire de la ville de Paris que je voudrais vous conter ',
'tags': u'Linux'
}, follow=False)

notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all()
self.assertEqual(1, len(notifications))

def test_remove_subscribed_tag(self):
"""
When the topic is edited and a tag is added to which the user has subscribed
"""
NewTopicSubscription.objects.toggle_follow(self.tag1, self.user2)

topic = TopicFactory(forum=self.forum11, author=self.user1)
topic.add_tags(['Linux'])
PostFactory(topic=topic, author=self.user1, position=1)

notifications = Notification.objects.filter(object_id=topic.pk, is_read=False).all()
self.assertEqual(1, len(notifications))

self.client.post(
reverse('topic-edit') + '?topic={0}'.format(topic.pk),
{
'title': u'Un autre sujet',
'subtitle': u'Encore ces lombards en plein été',
'text': u'C\'est tout simplement l\'histoire de la ville de Paris que je voudrais vous conter ',
'tags': u'Windows'
},
follow=False)

self.assertEqual(1, len(Notification.objects.filter(object_id=topic.pk, is_read=False, is_dead=True).all()))


class NotificationPublishableContentTest(TestCase):
def setUp(self):
Expand Down
12 changes: 6 additions & 6 deletions zds/utils/templatetags/interventions.py
Expand Up @@ -35,16 +35,16 @@ def is_email_followed(topic):
return TopicAnswerSubscription.objects.does_exist(user, topic, is_active=True, by_email=True)


@register.filter('is_forum_followed')
def is_forum_followed(forum):
@register.filter('is_followed_for_new_topic')
def is_followed_for_new_topic(forum_or_tag):
user = get_current_user()
return NewTopicSubscription.objects.does_exist(user, forum, is_active=True)
return NewTopicSubscription.objects.does_exist(user, forum_or_tag, is_active=True)


@register.filter('is_forum_email_followed')
def is_forum_email_followed(forum):
@register.filter('is_email_followed_for_new_topic')
def is_email_followed_for_new_topic(forum_or_tag):
user = get_current_user()
return NewTopicSubscription.objects.does_exist(user, forum, is_active=True, by_email=True)
return NewTopicSubscription.objects.does_exist(user, forum_or_tag, is_active=True, by_email=True)


@register.filter('is_content_followed')
Expand Down

0 comments on commit 4e30796

Please sign in to comment.