1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-12 21:30:39 +00:00

Add notification when comment a file

This commit is contained in:
zhengxie
2016-06-04 17:25:27 +08:00
parent bf0493ad0f
commit 00661b9be1
13 changed files with 233 additions and 5 deletions

View File

@@ -14,6 +14,8 @@ from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error, user_to_dict
from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
from seahub.base.models import FileComment
from seahub.utils.repo import get_repo_owner, get_repo_shared_users
from seahub.signals import comment_file_successful
logger = logging.getLogger(__name__)
@@ -77,6 +79,19 @@ class FileCommentsView(APIView):
username = request.user.username
o = FileComment.objects.add_by_file_path(
repo_id=repo_id, file_path=path, author=username, comment=comment)
repo = seafile_api.get_repo(repo_id)
repo_owner = get_repo_owner(request, repo.id)
notify_users = get_repo_shared_users(repo.id, repo_owner)
notify_users.append(repo_owner)
notify_users = [x for x in notify_users if x != username]
comment_file_successful.send(sender=None,
repo=repo,
file_path=path,
comment=comment,
author=username,
notify_users=notify_users)
comment = o.to_dict()
comment.update(user_to_dict(request.user.username, request=request,
avatar_size=avatar_size))

View File

@@ -171,6 +171,17 @@ class Command(BaseCommand):
notice.group_name = group.group_name
return notice
def format_file_comment_msg(self, notice):
d = json.loads(notice.detail)
repo_id = d['repo_id']
file_path = d['file_path']
author = d['author']
notice.file_url = reverse('view_lib_file', args=[repo_id, file_path])
notice.file_name = os.path.basename(file_path)
notice.author = author
return notice
def get_user_language(self, username):
return Profile.objects.get_user_language(username)
@@ -257,6 +268,9 @@ class Command(BaseCommand):
elif notice.is_add_user_to_group():
notice = self.format_add_user_to_group(notice)
elif notice.is_file_comment_msg():
notice = self.format_file_comment_msg(notice)
notices.append(notice)
if not notices:

View File

@@ -42,6 +42,7 @@ MSG_TYPE_FILE_UPLOADED = 'file_uploaded'
MSG_TYPE_REPO_SHARE = 'repo_share'
MSG_TYPE_REPO_SHARE_TO_GROUP = 'repo_share_to_group'
MSG_TYPE_USER_MESSAGE = 'user_message'
MSG_TYPE_FILE_COMMENT = 'file_comment'
def file_uploaded_msg_to_json(file_name, repo_id, uploaded_to):
"""Encode file uploaded message to json string.
@@ -70,6 +71,12 @@ def add_user_to_group_to_json(group_staff, group_id):
return json.dumps({'group_staff': group_staff,
'group_id': group_id})
def file_comment_msg_to_json(repo_id, file_path, author, comment):
return json.dumps({'repo_id': repo_id,
'file_path': file_path,
'author': author,
'comment': comment})
class UserNotificationManager(models.Manager):
def _add_user_notification(self, to_user, msg_type, detail):
@@ -162,7 +169,6 @@ class UserNotificationManager(models.Manager):
except UserNotification.InvalidDetailError:
continue
def seen_user_msg_notices(self, to_user, from_user):
"""Mark priv message notices of a user as seen.
"""
@@ -250,6 +256,11 @@ class UserNotificationManager(models.Manager):
return self._add_user_notification(to_user,
MSG_TYPE_USER_MESSAGE, detail)
def add_file_comment_msg(self, to_user, detail):
"""Notify ``to_user`` that others comment a file he can access.
"""
return self._add_user_notification(to_user, MSG_TYPE_FILE_COMMENT, detail)
class UserNotification(models.Model):
to_user = LowerCaseCharField(db_index=True, max_length=255)
msg_type = models.CharField(db_index=True, max_length=30)
@@ -338,6 +349,9 @@ class UserNotification(models.Model):
"""
return self.msg_type == MSG_TYPE_ADD_USER_TO_GROUP
def is_file_comment_msg(self):
return self.msg_type == MSG_TYPE_FILE_COMMENT
def group_message_detail_to_dict(self):
"""Parse group message detail, returns dict contains ``group_id`` and
``msg_from``.
@@ -646,11 +660,37 @@ class UserNotification(models.Model):
}
return msg
def format_file_comment_msg(self):
try:
d = json.loads(self.detail)
except Exception as e:
logger.error(e)
return _(u"Internal error")
repo_id = d['repo_id']
file_path = d['file_path']
author = d['author']
comment = d['comment']
repo = seafile_api.get_repo(repo_id)
if repo is None or not seafile_api.get_file_id_by_path(repo.id,
file_path):
self.delete()
return None
file_name = os.path.basename(file_path)
msg = _("File <a href='%(file_url)s'>%(file_name)s</a> has a new comment from user %(author)s") % {
'file_url': reverse('view_lib_file', args=[repo_id, file_path]),
'file_name': file_name,
'author': escape(email2nickname(author)),
}
return msg
########## handle signals
from django.core.urlresolvers import reverse
from django.dispatch import receiver
from seahub.signals import upload_file_successful
from seahub.signals import upload_file_successful, comment_file_successful
from seahub.group.signals import grpmsg_added, group_join_request, add_user_to_group
from seahub.share.signals import share_repo_to_user_successful, \
share_repo_to_group_successful
@@ -751,3 +791,15 @@ def add_user_to_group_cb(sender, **kwargs):
UserNotification.objects.set_add_user_to_group_notice(to_user=added_user,
detail=detail)
@receiver(comment_file_successful)
def comment_file_successful_cb(sender, **kwargs):
repo = kwargs['repo']
file_path = kwargs['file_path']
comment = kwargs['comment']
author = kwargs['author']
notify_users = kwargs['notify_users']
for u in notify_users:
detail = file_comment_msg_to_json(repo.id, file_path, author, comment)
UserNotification.objects.add_file_comment_msg(u, detail)

View File

@@ -50,7 +50,10 @@ You've got {{num}} new notices on {{ site_name }}:
{% elif notice.is_add_user_to_group %}
<p style="line-height:1.5; margin:.2em 10px .2em 0;">{% blocktrans with user_url=notice.group_staff_profile_url user=notice.notice_from grp_url=notice.group_url grp_name=notice.group_name %}User <a href="{{url_base}}{{user_url}}">{{user}}</a> has added you to group <a href="{{url_base}}{{grp_url}}">{{grp_name}}</a>{% endblocktrans %}</p>
{% endif %}
{% elif notice.is_file_comment_msg %}
<p style="line-height:1.5; margin:.2em 10px .2em 0;">{% blocktrans with file_url=notice.file_url file_name=notice.file_name author=notice.author %}File <a href="{{url_base}}{{file_url}}">{{file_name}}</a> has a new comment from user {{author}}{% endblocktrans %}</p>
{% endif %}
</td>
<td style="padding: 5px 3px; border-bottom: 1px solid #eee; font-size: 13px; color: #333; word-wrap: break-word;">{{ notice.timestamp|date:"Y-m-d G:i:s"}}</td>
</tr>

View File

@@ -37,6 +37,9 @@
{% elif notice.is_group_join_request %}
<p class="brief">{{ notice.format_group_join_request|safe }}</p>
{% elif notice.is_file_comment_msg %}
<p class="brief">{{ notice.format_file_comment_msg|safe }}</p>
{% endif %}
</td>
<td>{{ notice.timestamp|translate_seahub_time }}</td>

View File

@@ -187,6 +187,14 @@ def add_notice_from_info(notices):
logger.error(e)
notice.default_avatar_url = default_avatar_url
elif notice.is_file_comment_msg():
try:
d = json.loads(notice.detail)
notice.msg_from = d['author']
except Exception as e:
logger.error(e)
notice.default_avatar_url = default_avatar_url
else:
pass

View File

@@ -4,3 +4,4 @@ import django.dispatch
repo_created = django.dispatch.Signal(providing_args=["org_id", "creator", "repo_id", "repo_name"])
repo_deleted = django.dispatch.Signal(providing_args=["org_id", "usernames", "repo_owner", "repo_id", "repo_name"])
upload_file_successful = django.dispatch.Signal(providing_args=["repo_id", "file_path", "owner"])
comment_file_successful = django.dispatch.Signal(providing_args=["repo", "file_path", "comment", "author", "notify_users"])

View File

@@ -39,6 +39,9 @@
{% elif notice.is_add_user_to_group %}
<p class="brief">{{ notice.format_add_user_to_group|safe }}</p>
{% elif notice.is_file_comment_msg %}
<p class="brief">{{ notice.format_file_comment_msg|safe }}</p>
{% endif %}
<p class="time">{{ notice.timestamp|translate_seahub_time }}</p>

View File

@@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _
import seaserv
from seaserv import seafile_api
from seahub.utils import EMPTY_SHA1
from seahub.utils import EMPTY_SHA1, is_org_context
from seahub.base.accounts import User
logger = logging.getLogger(__name__)
@@ -29,3 +29,22 @@ def get_sub_repo_abbrev_origin_path(repo_name, origin_path):
return repo_name + '/...' + abbrev_path
else:
return repo_name + origin_path
def get_repo_owner(request, repo_id):
if is_org_context(request):
return seafile_api.get_org_repo_owner(repo_id)
else:
return seafile_api.get_repo_owner(repo_id)
def get_repo_shared_users(repo_id, repo_owner, include_groups=True):
"""Return a list contains users and group users. Repo owner is ommited.
"""
ret = []
users = seafile_api.list_repo_shared_to(repo_owner, repo_id)
ret += [x.user for x in users]
if include_groups:
for e in seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id):
g_members = seaserv.get_group_members(e.group_id)
ret += [x.user_name for x in g_members if x.user_name != repo_owner]
return list(set(ret))

View File

@@ -1,8 +1,11 @@
import json
from django.core.urlresolvers import reverse
import seaserv
from seaserv import seafile_api, ccnet_api
from seahub.base.models import FileComment
from seahub.notifications.models import UserNotification
from seahub.test_utils import BaseTestCase
class FileCommentsTest(BaseTestCase):
@@ -75,3 +78,43 @@ class FileCommentsTest(BaseTestCase):
'comment': 'new comment'
})
self.assertEqual(403, resp.status_code)
def test_can_notify_others(self):
assert len(UserNotification.objects.all()) == 0
username = self.user.username
seafile_api.share_repo(self.repo.id, username,
self.admin.username, 'rw')
resp = self.client.post(self.endpoint, {
'comment': 'new comment'
})
self.assertEqual(201, resp.status_code)
assert len(UserNotification.objects.all()) == 1
assert UserNotification.objects.all()[0].to_user == self.admin.username
def test_can_notify_others_including_group(self):
self.logout()
self.login_as(self.tmp_user)
assert len(UserNotification.objects.all()) == 0
# share repo to tmp_user
username = self.user.username
seafile_api.share_repo(self.repo.id, username,
self.tmp_user.username, 'rw')
# share repo to group(owner, admin)
ccnet_api.group_add_member(self.group.id, username,
self.admin.username)
seafile_api.set_group_repo(self.repo.id, self.group.id,
username, 'rw')
# tmp_user comment a file
resp = self.client.post(self.endpoint, {
'comment': 'new comment'
})
self.assertEqual(201, resp.status_code)
assert len(UserNotification.objects.all()) == 2

View File

@@ -1,7 +1,8 @@
from django.core import mail
from django.core.management import call_command
from seahub.notifications.models import UserNotification, repo_share_msg_to_json
from seahub.notifications.models import (
UserNotification, repo_share_msg_to_json, file_comment_msg_to_json)
from seahub.profile.models import Profile
from seahub.test_utils import BaseTestCase
@@ -29,3 +30,16 @@ class CommandTest(BaseTestCase):
call_command('send_notices')
self.assertEqual(len(mail.outbox), 1)
assert mail.outbox[0].to[0] == 'contact@foo.com'
def test_send_file_comment_notice(self):
self.assertEqual(len(mail.outbox), 0)
detail = file_comment_msg_to_json(self.repo.id, '/foo',
self.user.username, 'test comment')
UserNotification.objects.add_file_comment_msg('a@a.com', detail)
call_command('send_notices')
self.assertEqual(len(mail.outbox), 1)
assert mail.outbox[0].to[0] == 'a@a.com'
assert 'new comment from user %s' % self.user.username in mail.outbox[0].body
assert '/foo' in mail.outbox[0].body

View File

@@ -0,0 +1,14 @@
from seahub.notifications.models import (
UserNotification, repo_share_msg_to_json, file_comment_msg_to_json)
from seahub.test_utils import BaseTestCase
class UserNotificationTest(BaseTestCase):
def test_format_file_comment_msg(self):
detail = file_comment_msg_to_json(self.repo.id, self.file,
self.user.username, 'test comment')
notice = UserNotification.objects.add_file_comment_msg('a@a.com', detail)
msg = notice.format_file_comment_msg()
assert msg is not None
assert 'new comment from user' in msg

View File

@@ -0,0 +1,39 @@
from seahub.utils.repo import get_repo_shared_users, get_repo_owner
from seahub.test_utils import BaseTestCase
import seaserv
from seaserv import seafile_api, ccnet_api
class GetRepoOwnerTest(BaseTestCase):
def test_can_get(self):
assert get_repo_owner(self.fake_request, self.repo.id) == self.user.username
class GetRepoSharedUsersTest(BaseTestCase):
def setUp(self):
self.user2 = self.create_user()
ccnet_api.group_add_member(self.group.id, self.user.username,
self.user2.username)
g_members = [x.user_name for x in seaserv.get_group_members(self.group.id)]
assert self.user2.username in g_members
def tearDown(self):
self.remove_user(self.user2.username)
self.remove_group()
def test_can_get(self):
username = self.user.username
owner = get_repo_owner(self.fake_request, self.repo.id)
assert owner == username
assert get_repo_shared_users(self.repo.id, owner) == []
# user share a repo to admin
seafile_api.share_repo(self.repo.id, username,
self.admin.username, 'rw')
assert get_repo_shared_users(self.repo.id, owner) == [self.admin.username]
# user share a repo to group
seafile_api.set_group_repo(self.repo.id, self.group.id,
username, 'rw')
assert get_repo_shared_users(self.repo.id, owner) == [self.admin.username, self.user2.username]