From 4cca52b4d73b9a97bbcc97cee38ac63b5975422c Mon Sep 17 00:00:00 2001 From: zhengxie Date: Mon, 25 Nov 2013 18:32:58 +0800 Subject: [PATCH] Add user to group message and reply notification --- seahub/group/__init__.py | 6 - seahub/group/handlers.py | 34 --- seahub/group/models.py | 3 +- seahub/group/views.py | 12 +- seahub/notifications/models.py | 200 ++++++++++++++++-- .../notifications/user_notification_list.html | 8 +- seahub/notifications/views.py | 7 - seahub/views/__init__.py | 23 +- 8 files changed, 213 insertions(+), 80 deletions(-) delete mode 100644 seahub/group/handlers.py diff --git a/seahub/group/__init__.py b/seahub/group/__init__.py index 9bceb11b38..e69de29bb2 100644 --- a/seahub/group/__init__.py +++ b/seahub/group/__init__.py @@ -1,6 +0,0 @@ -from signals import * -from handlers import * -from models import GroupMessage, MessageReply - -grpmsg_added.connect(grpmsg_added_cb, sender=GroupMessage) -grpmsg_reply_added.connect(grpmsg_reply_added_cb, sender=MessageReply) diff --git a/seahub/group/handlers.py b/seahub/group/handlers.py deleted file mode 100644 index a8cd6c68ca..0000000000 --- a/seahub/group/handlers.py +++ /dev/null @@ -1,34 +0,0 @@ -from seahub.group.signals import grpmsg_added -from seahub.group.models import GroupMessage, MessageReply -from seahub.notifications.models import UserNotification - -from seaserv import get_group_members - -def grpmsg_added_cb(sender, **kwargs): - group_id = kwargs['group_id'] - from_email = kwargs['from_email'] - group_members = get_group_members(int(group_id)) - - notify_members = [ x.user_name for x in group_members if x.user_name != from_email ] - UserNotification.objects.bulk_add_group_msg_notices(notify_members, group_id) - -def grpmsg_reply_added_cb(sender, **kwargs): - msg_id = kwargs['msg_id'] - reply_from_email = kwargs['from_email'] - try: - group_msg = GroupMessage.objects.get(id=msg_id) - except GroupMessage.DoesNotExist: - group_msg = None - - if group_msg is None: - return - - msg_replies = MessageReply.objects.filter(reply_to=group_msg) - notice_users = set([ x.from_email for x in msg_replies \ - if x.from_email != reply_from_email]) - notice_users.add(group_msg.from_email) - - for user in notice_users: - UserNotification.objects.add_group_msg_reply_notice(to_user=user, - msg_id=msg_id) - diff --git a/seahub/group/models.py b/seahub/group/models.py index ebb6fd585f..cc1470d110 100644 --- a/seahub/group/models.py +++ b/seahub/group/models.py @@ -9,7 +9,6 @@ from seaserv import get_group_members from seahub.base.fields import LowerCaseCharField from seahub.shortcuts import get_first_object_or_none -from seahub.notifications.models import UserNotification from seahub.profile.models import Profile class GroupMessage(models.Model): @@ -41,6 +40,8 @@ class PublicGroup(models.Model): group_id = models.IntegerField(db_index=True) ########## '@' feature need to be redesigned, comment out temporarily. +# from seahub.notifications.models import UserNotification + # @receiver(post_save, sender=MessageReply) # def msgreply_save_handler(sender, instance, **kwargs): # """ diff --git a/seahub/group/views.py b/seahub/group/views.py index 2e59f74ca7..5e0577c19f 100644 --- a/seahub/group/views.py +++ b/seahub/group/views.py @@ -403,10 +403,18 @@ def msg_reply(request, msg_id): @login_required def msg_reply_new(request): username = request.user.username - grpmsg_reply_list = [ x.detail for x in UserNotification.objects.get_group_msg_reply_notices(username, seen=False) ] + grpmsg_reply_list = [ x for x in UserNotification.objects.get_group_msg_reply_notices(username, seen=False) ] + + msg_ids = [] + for e in grpmsg_reply_list: + try: + msg_id = e.grpmsg_reply_detail_to_dict().get('msg_id') + except UserNotification.InvalidDetailError: + continue + msg_ids.append(msg_id) group_msgs = [] - for msg_id in grpmsg_reply_list: + for msg_id in msg_ids: try: m = GroupMessage.objects.get(id=msg_id) except GroupMessage.DoesNotExist: diff --git a/seahub/notifications/models.py b/seahub/notifications/models.py index 477f5d295d..0fe29e25b8 100644 --- a/seahub/notifications/models.py +++ b/seahub/notifications/models.py @@ -9,6 +9,7 @@ from django.forms import ModelForm, Textarea from django.utils.http import urlquote from django.utils.translation import ugettext as _ +import seaserv from seaserv import seafile_api from seahub.base.fields import LowerCaseCharField @@ -44,16 +45,18 @@ def file_uploaded_msg_to_json(file_name, repo_id, uploaded_to): 'uploaded_to': uploaded_to}) def repo_share_msg_to_json(share_from, repo_id): - """ - """ return json.dumps({'share_from': share_from, 'repo_id': repo_id}) def priv_file_share_msg_to_json(share_from, file_name, priv_share_token): - """ - """ return json.dumps({'share_from': share_from, 'file_name': file_name, 'priv_share_token': priv_share_token}) +def group_msg_to_json(group_id, msg_from): + return json.dumps({'group_id': group_id, 'msg_from': msg_from}) + +def grpmsg_reply_to_json(msg_id, reply_from): + return json.dumps({'msg_id': msg_id, 'reply_from': reply_from}) + class UserNotificationManager(models.Manager): def _add_user_notification(self, to_user, msg_type, detail): """Add generic user notification. @@ -105,7 +108,7 @@ class UserNotificationManager(models.Manager): return super(UserNotificationManager, self).filter( to_user=username, seen=False).count() - def bulk_add_group_msg_notices(self, to_users, group_id): + def bulk_add_group_msg_notices(self, to_users, detail): """Efficiently add group message notices. NOTE: ``pre_save`` and ``post_save`` signals will not be sent. @@ -113,12 +116,11 @@ class UserNotificationManager(models.Manager): Arguments: - `self`: - `to_users`: - - `msg_type`: - `detail`: """ user_notices = [ UserNotification(to_user=m, msg_type=MSG_TYPE_GROUP_MSG, - detail=group_id + detail=detail ) for m in to_users ] UserNotification.objects.bulk_create(user_notices) @@ -126,10 +128,18 @@ class UserNotificationManager(models.Manager): def seen_group_msg_notices(self, to_user, group_id): """Mark group message notices of a user as seen. """ - super(UserNotificationManager, self).filter( - to_user=to_user, msg_type=MSG_TYPE_GROUP_MSG, - detail=str(group_id)).update(seen=True) - + user_notices = super(UserNotificationManager, self).filter( + to_user=to_user, msg_type=MSG_TYPE_GROUP_MSG) + for notice in user_notices: + try: + gid = notice.group_message_detail_to_dict().get('group_id') + if gid == group_id: + if notice.seen is False: + notice.seen = True + notice.save() + except UserNotification.InvalidDetailError: + continue + def remove_group_msg_notices(self, to_user, group_id): """Remove group message notices of a user. """ @@ -137,7 +147,7 @@ class UserNotificationManager(models.Manager): to_user=to_user, msg_type=MSG_TYPE_GROUP_MSG, detail=str(group_id)).delete() - def add_group_msg_reply_notice(self, to_user, msg_id): + def add_group_msg_reply_notice(self, to_user, detail): """Added group message reply notice for user. Arguments: @@ -146,7 +156,7 @@ class UserNotificationManager(models.Manager): - `msg_id`: """ return self._add_user_notification(to_user, - MSG_TYPE_GRPMSG_REPLY, msg_id) + MSG_TYPE_GRPMSG_REPLY, detail) def get_group_msg_reply_notices(self, to_user, seen=None): """Get all group message replies of a user. @@ -171,7 +181,8 @@ class UserNotificationManager(models.Manager): - `msg_id`: """ super(UserNotificationManager, self).filter( - to_user=to_user, msg_type=MSG_TYPE_GRPMSG_REPLY).update(seen=True) + to_user=to_user, msg_type=MSG_TYPE_GRPMSG_REPLY, + seen=False).update(seen=True) def remove_group_msg_reply_notice(self, to_user): """Mark all group message replies of a user as seen. @@ -237,6 +248,9 @@ class UserNotification(models.Model): seen = models.BooleanField('seen', default=False) objects = UserNotificationManager() + class InvalidDetailError(Exception): + pass + class Meta: ordering = ["-timestamp"] @@ -305,6 +319,62 @@ class UserNotification(models.Model): - `self`: """ return self.msg_type == MSG_TYPE_USER_MESSAGE + + def group_message_detail_to_dict(self): + """Parse group message detail, returns dict contains ``group_id`` and + ``msg_from``. + + NOTE: ``msg_from`` may be ``None``. + + Arguments: + - `self`: + + Raises ``InvalidDetailError`` if detail field can not be parsed. + """ + assert self.is_group_msg() + + try: + detail = json.loads(self.detail) + except json.JSONDecodeError: + raise self.InvalidDetailError, 'Wrong detail format of group message' + else: + if isinstance(detail, int): # Compatible with existing records + group_id = detail + msg_from = None + elif isinstance(detail, dict): + group_id = detail['group_id'] + msg_from = detail['msg_from'] + else: + raise self.InvalidDetailError, 'Wrong detail format of group message' + return {'group_id': group_id, 'msg_from': msg_from} + + def grpmsg_reply_detail_to_dict(self): + """Parse group message reply detail, returns dict contains + ``msg_id`` and ``reply_from``. + + NOTE: ``reply_from`` may be ``None``. + + Arguments: + - `self`: + + Raises ``InvalidDetailError`` if detail field can not be parsed. + """ + assert self.is_grpmsg_reply() + + try: + detail = json.loads(self.detail) + except json.JSONDecodeError: + raise self.InvalidDetailError, 'Wrong detail format of group message reply' + else: + if isinstance(detail, int): # Compatible with existing records + msg_id = detail + reply_from = None + elif isinstance(detail, dict): + msg_id = detail['msg_id'] + reply_from = detail['reply_from'] + else: + raise self.InvalidDetailError, 'Wrong detail format of group message reply' + return {'msg_id': msg_id, 'reply_from': reply_from} def format_file_uploaded_msg(self): """ @@ -381,21 +451,71 @@ class UserNotification(models.Model): } return msg + def format_group_message(self): + """ + + Arguments: + - `self`: + """ + try: + d = self.group_message_detail_to_dict() + except self.InvalidDetailError as e: + return _(u"Internal error") + + group_id = d.get('group_id') + group = seaserv.get_group(group_id) + msg_from = d.get('msg_from') + + if msg_from is None: + msg = _(u"%(group_name)s has new discussion") % { + 'href': reverse('group_discuss', args=[group.id]), + 'group_name': group.group_name} + else: + msg = _(u"%(user)s posted a new discussion in %(group_name)s") % { + 'href': reverse('group_discuss', args=[group.id]), + 'user': msg_from, + 'group_name': group.group_name} + + return msg + + def format_grpmsg_reply(self): + """ + + Arguments: + - `self`: + """ + try: + d = self.grpmsg_reply_detail_to_dict() + except self.InvalidDetailError as e: + return _(u"Internal error") + + msg_id = d.get('msg_id') + reply_from = d.get('reply_from') + + if reply_from is None: + msg = _(u"One group discussion has new reply") % { + 'href': reverse('msg_reply_new'), + } + else: + msg = _(u"%(user)s replied your group discussion") % { + 'user': reply_from, + 'href': reverse('msg_reply_new') + } + return msg + ########## handle signals from django.core.urlresolvers import reverse from django.dispatch import receiver from seahub.signals import share_file_to_user_successful, upload_file_successful +from seahub.group.models import GroupMessage, MessageReply +from seahub.group.signals import grpmsg_added, grpmsg_reply_added from seahub.share.signals import share_repo_to_user_successful from seahub.message.models import UserMessage @receiver(upload_file_successful) def add_upload_file_msg_cb(sender, **kwargs): """Notify repo owner when others upload files to his/her share folder. - - Arguments: - - `sender`: - - `**kwargs)`: """ repo_id = kwargs.get('repo_id', None) file_path = kwargs.get('file_path', None) @@ -412,6 +532,8 @@ def add_upload_file_msg_cb(sender, **kwargs): @receiver(share_repo_to_user_successful) def add_share_repo_msg_cb(sender, **kwargs): + """Notify user when others share repos to him/her. + """ from_user = kwargs.get('from_user', None) to_user = kwargs.get('to_user', None) repo = kwargs.get('repo', None) @@ -426,6 +548,8 @@ def add_share_repo_msg_cb(sender, **kwargs): @receiver(share_file_to_user_successful) def add_share_file_msg_cb(sender, **kwargs): + """Notify user when others share files to him/her. + """ priv_share = kwargs.get('priv_share_obj', None) file_name = os.path.basename(priv_share.path) @@ -439,7 +563,7 @@ def add_share_file_msg_cb(sender, **kwargs): @receiver(post_save, sender=UserMessage) def add_user_message_cb(sender, instance, **kwargs): - """ + """Notify user when he/she got a new mesaage. """ msg_from = instance.from_email msg_to = instance.to_email @@ -447,4 +571,40 @@ def add_user_message_cb(sender, instance, **kwargs): from seahub.base.templatetags.seahub_tags import email2nickname nickname = email2nickname(msg_from) UserNotification.objects.add_user_message(msg_to, detail=nickname) - + +@receiver(grpmsg_added) +def grpmsg_added_cb(sender, **kwargs): + group_id = kwargs['group_id'] + from_email = kwargs['from_email'] + group_members = seaserv.get_group_members(int(group_id)) + + notify_members = [ x.user_name for x in group_members if x.user_name != from_email ] + + from seahub.base.templatetags.seahub_tags import email2nickname + detail = group_msg_to_json(group_id, email2nickname(from_email)) + UserNotification.objects.bulk_add_group_msg_notices(notify_members, detail) + +@receiver(grpmsg_reply_added) +def grpmsg_reply_added_cb(sender, **kwargs): + msg_id = kwargs['msg_id'] + reply_from_email = kwargs['from_email'] + try: + group_msg = GroupMessage.objects.get(id=msg_id) + except GroupMessage.DoesNotExist: + group_msg = None + + if group_msg is None: + return + + msg_replies = MessageReply.objects.filter(reply_to=group_msg) + notice_users = set([ x.from_email for x in msg_replies \ + if x.from_email != reply_from_email]) + notice_users.add(group_msg.from_email) + + from seahub.base.templatetags.seahub_tags import email2nickname + detail = grpmsg_reply_to_json(msg_id, email2nickname(reply_from_email)) + + for user in notice_users: + UserNotification.objects.add_group_msg_reply_notice(to_user=user, + detail=detail) + diff --git a/seahub/notifications/templates/notifications/user_notification_list.html b/seahub/notifications/templates/notifications/user_notification_list.html index d007a33e5e..b05f84bdcc 100644 --- a/seahub/notifications/templates/notifications/user_notification_list.html +++ b/seahub/notifications/templates/notifications/user_notification_list.html @@ -26,13 +26,13 @@ {% for notice in notices %} {% if notice.is_group_msg %} - - {{ notice.group.group_name }} has new discussion + + {{ notice.format_group_message|safe }} {{ notice.timestamp|translate_seahub_time }} {% elif notice.is_grpmsg_reply %} - - One group discussion has new reply + + {{ notice.format_grpmsg_reply|safe }} {{ notice.timestamp|translate_seahub_time }} {% elif notice.is_file_uploaded_msg %} diff --git a/seahub/notifications/views.py b/seahub/notifications/views.py index 4769d82220..6673f10564 100644 --- a/seahub/notifications/views.py +++ b/seahub/notifications/views.py @@ -67,14 +67,7 @@ def user_notification_list(request): - `request`: """ username = request.user.username - grpmsg_list = [] - grpmsg_reply_list = [] - notices = UserNotification.objects.get_user_notifications(username) - for n in notices: - if n.is_group_msg(): - grp = seaserv.get_group(int(n.detail)) - n.group = grp return render_to_response("notifications/user_notification_list.html", { 'notices': notices, diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index b4a545d491..7dc10e2056 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -35,7 +35,7 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_repos, get_emailusers, \ seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, is_repo_owner, \ get_personal_groups_by_user, is_inner_pub_repo, \ del_org_group_repo, get_personal_groups, web_get_access_token, remove_repo, \ - get_group, get_shared_groups_by_repo, is_group_user, check_permission, \ + get_shared_groups_by_repo, is_group_user, check_permission, \ list_personal_shared_repos, is_org_group, get_org_id_by_group, is_org_repo,\ list_inner_pub_repos, get_org_groups_by_repo, is_org_repo_owner, \ get_org_repo_owner, is_passwd_set, get_file_size, check_quota, edit_repo,\ @@ -998,19 +998,30 @@ def myhome(request): notes = UserNotification.objects.get_user_notifications(username, seen=False) for n in notes: if n.is_group_msg(): - if int(n.detail) not in joined_group_ids: + try: + group_id = n.group_message_detail_to_dict().get('group_id') + except UserNotification.InvalidDetailError: continue + + if group_id not in joined_group_ids: + continue + dup = False for grpmsg in grpmsg_list: - if grpmsg.id == int(n.detail): + if grpmsg.id == group_id: dup = True break if not dup: - grp = get_group(int(n.detail)) + grp = seaserv.get_group(group_id) grpmsg_list.append(grp) elif n.is_grpmsg_reply(): - if n.detail not in grpmsg_reply_list: - grpmsg_reply_list.append(n.detail) + try: + msg_id = n.grpmsg_reply_detail_to_dict().get('msg_id') + except UserNotification.InvalidDetailError: + continue + + if msg_id not in grpmsg_reply_list: + grpmsg_reply_list.append(msg_id) # get nickname profiles = Profile.objects.filter(user=username)