diff --git a/frontend/src/components/common/notice-item.js b/frontend/src/components/common/notice-item.js index f4f2fb44ef..088b4ad1fa 100644 --- a/frontend/src/components/common/notice-item.js +++ b/frontend/src/components/common/notice-item.js @@ -20,6 +20,8 @@ const MSG_TYPE_DRAFT_REVIEWER = 'draft_reviewer'; const MSG_TYPE_REPO_MONITOR = 'repo_monitor'; const MSG_TYPE_DELETED_FILES = 'deleted_files'; const MSG_TYPE_SAML_SSO_FAILED = 'saml_sso_failed'; +const MSG_TYPE_REPO_SHARE_PERM_CHANGE = 'repo_share_perm_change'; +const MSG_TYPE_REPO_SHARE_PERM_DELETE = 'repo_share_perm_delete'; class NoticeItem extends React.Component { @@ -79,6 +81,56 @@ class NoticeItem extends React.Component { return {avatar_url, notice}; } + if (noticeType === MSG_TYPE_REPO_SHARE_PERM_CHANGE) { + + let avatar_url = detail.share_from_user_avatar_url; + let shareFrom = detail.share_from_user_name; + let permission = detail.permission; + let repoName = detail.repo_name; + let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/'; + let path = detail.path; + let notice = ''; + // 1. handle translate + if (path === '/') { // share repo + notice = gettext('{share_from} has changed the permission of library {repo_link} to {permission}.'); + } else { // share folder + notice = gettext('{share_from} has changed the permission of folder {repo_link} to {permission}.'); + } + + // 2. handle xss(cross-site scripting) + notice = notice.replace('{share_from}', shareFrom); + notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`); + notice = notice.replace('{permission}', permission); + notice = Utils.HTMLescape(notice); + + // 3. add jump link + notice = notice.replace('{tagA}', ``); + notice = notice.replace('{/tagA}', ''); + + return {avatar_url, notice}; + } + + if (noticeType === MSG_TYPE_REPO_SHARE_PERM_DELETE) { + + let avatar_url = detail.share_from_user_avatar_url; + let shareFrom = detail.share_from_user_name; + let repoName = detail.repo_name; + let path = detail.path; + let notice = ''; + // 1. handle translate + if (path === '/') { // share repo + notice = gettext('{share_from} has cancelled the sharing of library {repo_name}.'); + } else { // share folder + notice = gettext('{share_from} has cancelled the sharing of folder {repo_name}.'); + } + + // 2. handle xss(cross-site scripting) + notice = notice.replace('{share_from}', shareFrom); + notice = notice.replace('{repo_name}', repoName); + notice = Utils.HTMLescape(notice); + return {avatar_url, notice}; + } + if (noticeType === MSG_TYPE_REPO_SHARE_TO_GROUP) { let avatar_url = detail.share_from_user_avatar_url; diff --git a/seahub/api2/endpoints/dir_shared_items.py b/seahub/api2/endpoints/dir_shared_items.py index c33e49404c..dd85799e72 100644 --- a/seahub/api2/endpoints/dir_shared_items.py +++ b/seahub/api2/endpoints/dir_shared_items.py @@ -32,7 +32,8 @@ from seahub.share.utils import is_repo_admin, share_dir_to_user, \ check_group_share_out_permission, normalize_custom_permission_name from seahub.utils import (is_org_context, is_valid_username, send_perm_audit_msg) -from seahub.share.signals import share_repo_to_user_successful, share_repo_to_group_successful +from seahub.share.signals import share_repo_to_user_successful, share_repo_to_group_successful, \ + change_repo_perm_successful, delete_repo_perm_successful from seahub.constants import PERMISSION_READ, PERMISSION_READ_WRITE, \ PERMISSION_ADMIN from seahub.utils.repo import get_available_repo_perms @@ -260,6 +261,19 @@ class DirSharedItemsEndpoint(APIView): update_user_dir_permission(repo_id, path, repo_owner, shared_to, permission) + org_id = None + if is_org_context(request): + org_id = request.user.org.org_id + change_repo_perm_successful.send( + sender=None, + from_user=username, + to_user=shared_to, + repo=repo, + path=path, + permission=permission, + org_id=org_id + ) + send_perm_audit_msg('modify-repo-perm', username, shared_to, repo_id, path, permission) @@ -544,6 +558,18 @@ class DirSharedItemsEndpoint(APIView): if path == '/': ExtraSharePermission.objects.delete_share_permission(repo_id, shared_to) + + org_id = None + if is_org_context(request): + org_id = request.user.org.org_id + delete_repo_perm_successful.send( + sender=None, + from_user=username, + to_user=shared_to, + repo=repo, + path=path, + org_id=org_id + ) send_perm_audit_msg('delete-repo-perm', username, shared_to, repo_id, path, permission) diff --git a/seahub/notifications/models.py b/seahub/notifications/models.py index ca5a3548c9..e505149f08 100644 --- a/seahub/notifications/models.py +++ b/seahub/notifications/models.py @@ -67,6 +67,8 @@ MSG_TYPE_GROUP_JOIN_REQUEST = 'group_join_request' MSG_TYPE_ADD_USER_TO_GROUP = 'add_user_to_group' MSG_TYPE_FILE_UPLOADED = 'file_uploaded' MSG_TYPE_REPO_SHARE = 'repo_share' +MSG_TYPE_REPO_SHARE_PERM_CHANGE = 'repo_share_perm_change' +MSG_TYPE_REPO_SHARE_PERM_DELETE = 'repo_share_perm_delete' MSG_TYPE_REPO_SHARE_TO_GROUP = 'repo_share_to_group' MSG_TYPE_USER_MESSAGE = 'user_message' MSG_TYPE_FILE_COMMENT = 'file_comment' @@ -90,6 +92,14 @@ def repo_share_msg_to_json(share_from, repo_id, path, org_id): return json.dumps({'share_from': share_from, 'repo_id': repo_id, 'path': path, 'org_id': org_id}) +def repo_share_perm_change_msg_to_json(share_from, repo_id, path, org_id, perm): + return json.dumps({'share_from': share_from, 'repo_id': repo_id, + 'path': path, 'org_id': org_id, 'permission': perm}) + +def repo_share_perm_delete_msg_to_json(share_from, repo_id, path, org_id): + return json.dumps({'share_from': share_from, 'repo_id': repo_id, + 'path': path, 'org_id': org_id}) + def repo_share_to_group_msg_to_json(share_from, repo_id, group_id, path, org_id): return json.dumps({'share_from': share_from, 'repo_id': repo_id, 'group_id': group_id, 'path': path, 'org_id': org_id}) @@ -266,6 +276,13 @@ class UserNotificationManager(models.Manager): return self._add_user_notification(to_user, MSG_TYPE_REPO_SHARE, detail) + def add_repo_share_perm_change_msg(self, to_user, detail): + return self._add_user_notification(to_user, MSG_TYPE_REPO_SHARE_PERM_CHANGE, detail) + + def add_repo_share_perm_delete_msg(self, to_user, detail): + return self._add_user_notification(to_user, MSG_TYPE_REPO_SHARE_PERM_DELETE, detail) + + def add_repo_share_to_group_msg(self, to_user, detail): """Notify ``to_user`` that others shared a repo to group. @@ -369,6 +386,12 @@ class UserNotification(models.Model): """ return self.msg_type == MSG_TYPE_REPO_SHARE + def is_repo_share_perm_change_msg(self): + return self.msg_type == MSG_TYPE_REPO_SHARE_PERM_CHANGE + + def is_repo_share_perm_delete_msg(self): + return self.msg_type == MSG_TYPE_REPO_SHARE_PERM_DELETE + def is_repo_share_to_group_msg(self): """ @@ -790,7 +813,7 @@ from django.dispatch import receiver from seahub.signals import upload_file_successful, comment_file_successful, repo_transfer from seahub.group.signals import group_join_request, add_user_to_group from seahub.share.signals import share_repo_to_user_successful, \ - share_repo_to_group_successful + share_repo_to_group_successful, change_repo_perm_successful, delete_repo_perm_successful from seahub.invitations.signals import accept_guest_invitation_successful from seahub.drafts.signals import comment_draft_successful, \ request_reviewer_successful @@ -828,6 +851,34 @@ def add_share_repo_msg_cb(sender, **kwargs): detail = repo_share_msg_to_json(from_user, repo.id, path, org_id) UserNotification.objects.add_repo_share_msg(to_user, detail) +@receiver(change_repo_perm_successful) +def add_modify_share_repo_msg_cb(sender, **kwargs): + from_user = kwargs.get('from_user', None) + to_user = kwargs.get('to_user', None) + repo = kwargs.get('repo', None) + path = kwargs.get('path', None) + org_id = kwargs.get('org_id', None) + permission = kwargs.get('permission', None) + + assert from_user and to_user and repo and path and permission is not None, 'Arguments error' + + detail = repo_share_perm_change_msg_to_json(from_user, repo.id, path, org_id, permission) + UserNotification.objects.add_repo_share_perm_change_msg(to_user, detail) + +@receiver(delete_repo_perm_successful) +def add_delete_share_repo_msg_cb(sender, **kwargs): + from_user = kwargs.get('from_user', None) + to_user = kwargs.get('to_user', None) + repo = kwargs.get('repo', None) + path = kwargs.get('path', None) + org_id = kwargs.get('org_id', None) + + assert from_user and to_user and repo and path is not None, 'Arguments error' + + detail = repo_share_perm_delete_msg_to_json(from_user, repo.id, path, org_id) + UserNotification.objects.add_repo_share_perm_delete_msg(to_user, detail) + + @receiver(share_repo_to_group_successful) def add_share_repo_to_group_msg_cb(sender, **kwargs): """Notify group member when others share repos to group. diff --git a/seahub/notifications/utils.py b/seahub/notifications/utils.py index ba415d6c30..9c9cf183f8 100644 --- a/seahub/notifications/utils.py +++ b/seahub/notifications/utils.py @@ -7,10 +7,13 @@ from django.utils.html import escape from django.utils.translation import gettext as _ from seaserv import ccnet_api, seafile_api + +from seahub.constants import CUSTOM_PERMISSION_PREFIX from seahub.notifications.models import Notification from seahub.notifications.settings import NOTIFICATION_CACHE_TIMEOUT from seahub.avatar.templatetags.avatar_tags import api_avatar_url from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email +from seahub.share.models import CustomSharePermissions from seahub.utils import get_service_url logger = logging.getLogger(__name__) @@ -61,6 +64,87 @@ def update_notice_detail(request, notices): except Exception as e: logger.error(e) + elif notice.is_repo_share_perm_change_msg(): + try: + d = json.loads(notice.detail) + repo_id = d['repo_id'] + path = d.get('path', '/') + org_id = d.get('org_id', None) + permission = d.get('permission', None) + if CUSTOM_PERMISSION_PREFIX in permission: + custom_permission_id = permission.split('-')[1] + try: + csp = CustomSharePermissions.objects.get(id=int(custom_permission_id)) + permission = csp.name + except Exception as e: + logger.error(e) + permission = '' + if path == '/': + repo = seafile_api.get_repo(repo_id) + else: + if org_id: + owner = seafile_api.get_org_repo_owner(repo_id) + repo = seafile_api.get_org_virtual_repo( + org_id, repo_id, path, owner) + else: + owner = seafile_api.get_repo_owner(repo_id) + repo = seafile_api.get_virtual_repo(repo_id, path, owner) + + if repo is None: + notice.detail = None + else: + d.pop('org_id', None) + share_from_user_email = d.pop('share_from') + url, is_default, date_uploaded = api_avatar_url(share_from_user_email, 32) + + d['repo_name'] = repo.name + d['repo_id'] = repo.id + d['share_from_user_name'] = email2nickname(share_from_user_email) + d['share_from_user_email'] = share_from_user_email + d['share_from_user_contact_email'] = email2contact_email(share_from_user_email) + d['share_from_user_avatar_url'] = url + d['permission'] = permission + notice.detail = d + + except Exception as e: + logger.error(e) + + elif notice.is_repo_share_perm_delete_msg(): + try: + d = json.loads(notice.detail) + repo_id = d['repo_id'] + path = d.get('path', '/') + org_id = d.get('org_id', None) + if path == '/': + repo = seafile_api.get_repo(repo_id) + else: + if org_id: + owner = seafile_api.get_org_repo_owner(repo_id) + repo = seafile_api.get_org_virtual_repo( + org_id, repo_id, path, owner) + else: + owner = seafile_api.get_repo_owner(repo_id) + repo = seafile_api.get_virtual_repo(repo_id, path, owner) + + if repo is None: + notice.detail = None + else: + d.pop('org_id', None) + share_from_user_email = d.pop('share_from') + url, is_default, date_uploaded = api_avatar_url(share_from_user_email, 32) + + d['repo_name'] = repo.name + d['repo_id'] = repo.id + d['share_from_user_name'] = email2nickname(share_from_user_email) + d['share_from_user_email'] = share_from_user_email + d['share_from_user_contact_email'] = email2contact_email(share_from_user_email) + d['share_from_user_avatar_url'] = url + notice.detail = d + + except Exception as e: + logger.error(e) + + elif notice.is_repo_share_to_group_msg(): try: d = json.loads(notice.detail) diff --git a/seahub/share/signals.py b/seahub/share/signals.py index 6aa9a3644e..6a3638d60e 100644 --- a/seahub/share/signals.py +++ b/seahub/share/signals.py @@ -3,3 +3,5 @@ from django.dispatch import Signal share_repo_to_user_successful = Signal() share_repo_to_group_successful = Signal() +change_repo_perm_successful = Signal() +delete_repo_perm_successful = Signal()