mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 19:01:42 +00:00
Upload folder notification (#6013)
* upload folder user notification * update
This commit is contained in:
@@ -15,6 +15,7 @@ const MSG_TYPE_REPO_SHARE = 'repo_share';
|
||||
const MSG_TYPE_REPO_SHARE_TO_GROUP = 'repo_share_to_group';
|
||||
const MSG_TYPE_REPO_TRANSFER = 'repo_transfer';
|
||||
const MSG_TYPE_FILE_UPLOADED = 'file_uploaded';
|
||||
const MSG_TYPE_FOLDER_UPLOADED = 'folder_uploaded';
|
||||
// const MSG_TYPE_GUEST_INVITATION_ACCEPTED = 'guest_invitation_accepted';
|
||||
const MSG_TYPE_REPO_MONITOR = 'repo_monitor';
|
||||
const MSG_TYPE_DELETED_FILES = 'deleted_files';
|
||||
@@ -221,6 +222,40 @@ class NoticeItem extends React.Component {
|
||||
return {avatar_url, notice};
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_FOLDER_UPLOADED) {
|
||||
let avatar_url = detail.uploaded_user_avatar_url;
|
||||
let folderName = detail.folder_name;
|
||||
let folderLink = siteRoot + 'library/' + detail.repo_id + '/' + detail.repo_name + detail.folder_path;
|
||||
|
||||
let parentDirName = detail.parent_dir_name;
|
||||
let parentDirLink = siteRoot + 'library/' + detail.repo_id + '/' + detail.repo_name + detail.parent_dir_path;
|
||||
let notice = '';
|
||||
if (detail.repo_id) { // todo is repo exist ?
|
||||
// 1. handle translate
|
||||
notice = gettext('A folder named {upload_folder_link} is uploaded to {uploaded_link}.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_folder_link}', `{tagA}${folderName}{/tagA}`);
|
||||
notice = notice.replace('{uploaded_link}', `{tagB}${parentDirName}{/tagB}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(folderLink)}>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
notice = notice.replace('{tagB}', `<a href=${Utils.encodePath(parentDirLink)}>`);
|
||||
notice = notice.replace('{/tagB}', '</a>');
|
||||
} else {
|
||||
// 1. handle translate
|
||||
notice = gettext('A folder named {upload_folder_link} is uploaded to {uploaded_link}.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_folder_link}', `${folderName}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
notice = notice.replace('{uploaded_link}', '<strong>Deleted Library</strong>');
|
||||
}
|
||||
return {avatar_url, notice};
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_MONITOR) {
|
||||
const {
|
||||
op_user_avatar_url: avatar_url,
|
||||
|
@@ -25,7 +25,8 @@ class SharedUploadLink extends React.Component {
|
||||
|
||||
onFileUploadSuccess = (direntObject) => {
|
||||
const { name } = direntObject;
|
||||
seafileAPI.shareLinksUploadDone(token, Utils.joinPath(path, name));
|
||||
const isDir = direntObject.type === 'dir';
|
||||
seafileAPI.shareLinksUploadDone(token, Utils.joinPath(path, name), isDir);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@@ -51,7 +51,7 @@ from seahub.settings import SHARE_LINK_EXPIRE_DAYS_MAX, \
|
||||
from seahub.wiki.models import Wiki
|
||||
from seahub.views.file import can_edit_file
|
||||
from seahub.views import check_folder_permission
|
||||
from seahub.signals import upload_file_successful
|
||||
from seahub.signals import upload_file_successful, upload_folder_successful
|
||||
from seahub.repo_tags.models import RepoTags
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -1129,33 +1129,17 @@ class ShareLinkUploadDone(APIView):
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
parent_dir = share_link.path
|
||||
if seafile_api.check_permission_by_path(repo_id, parent_dir, share_link.username) != 'rw':
|
||||
link_owner = share_link.username
|
||||
if seafile_api.check_permission_by_path(repo_id,
|
||||
parent_dir,
|
||||
link_owner) != 'rw':
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
file_path = request.data.get('file_path')
|
||||
if not file_path:
|
||||
error_msg = 'file_path invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, file_path)
|
||||
if not file_id:
|
||||
error_msg = 'File %s not found.' % file_path
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
# send singal
|
||||
upload_file_successful.send(sender=None,
|
||||
repo_id=repo_id,
|
||||
file_path=file_path,
|
||||
owner=share_link.username)
|
||||
|
||||
return Response({'success': True})
|
||||
|
||||
if upload_link:
|
||||
|
||||
if upload_link.is_encrypted() and not check_share_link_access(request,
|
||||
token,
|
||||
is_upload_link=True):
|
||||
if upload_link.is_encrypted() and not \
|
||||
check_share_link_access(request, token, is_upload_link=True):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
@@ -1170,24 +1154,42 @@ class ShareLinkUploadDone(APIView):
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
parent_dir = upload_link.path
|
||||
if seafile_api.check_permission_by_path(repo_id, parent_dir, upload_link.username) != 'rw':
|
||||
link_owner = upload_link.username
|
||||
if seafile_api.check_permission_by_path(repo_id,
|
||||
parent_dir,
|
||||
link_owner) != 'rw':
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
file_path = request.data.get('file_path')
|
||||
if not file_path:
|
||||
# send signal
|
||||
dirent_path = request.data.get('file_path')
|
||||
if not dirent_path:
|
||||
error_msg = 'file_path invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, file_path)
|
||||
if not file_id:
|
||||
error_msg = 'File %s not found.' % file_path
|
||||
is_dir = request.data.get('is_dir', 'false')
|
||||
if is_dir.lower() == 'true':
|
||||
dir_id = seafile_api.get_dir_id_by_path(repo_id, dirent_path)
|
||||
if not dir_id:
|
||||
error_msg = 'Folder %s not found.' % dirent_path
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
# send singal
|
||||
upload_folder_successful.send(sender=None,
|
||||
repo_id=repo_id,
|
||||
folder_path=dirent_path,
|
||||
owner=link_owner)
|
||||
else:
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, dirent_path)
|
||||
if not file_id:
|
||||
error_msg = 'File %s not found.' % dirent_path
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
# send singal
|
||||
upload_file_successful.send(sender=None,
|
||||
repo_id=repo_id,
|
||||
file_path=file_path,
|
||||
owner=upload_link.username)
|
||||
file_path=dirent_path,
|
||||
owner=link_owner)
|
||||
|
||||
return Response({'success': True})
|
||||
|
||||
|
@@ -153,6 +153,32 @@ class Command(BaseCommand):
|
||||
notice.avatar_src = self.get_default_avatar_src()
|
||||
return notice
|
||||
|
||||
def format_folder_uploaded_msg(self, notice):
|
||||
d = json.loads(notice.detail)
|
||||
|
||||
folder_name = d['folder_name']
|
||||
repo_id = d['repo_id']
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
|
||||
uploaded_to = d['uploaded_to']
|
||||
if uploaded_to != '/':
|
||||
uploaded_to = d['uploaded_to'].rstrip('/')
|
||||
folder_path = uploaded_to + '/' + folder_name
|
||||
parent_dir_link = reverse('lib_view', args=[repo_id, repo.name, uploaded_to.strip('/')])
|
||||
parent_dir_name = os.path.basename(uploaded_to)
|
||||
else:
|
||||
folder_path = '/' + folder_name
|
||||
parent_dir_link = reverse('lib_view', args=[repo_id, repo.name, ''])
|
||||
parent_dir_name = repo.name
|
||||
|
||||
folder_link = reverse('lib_view', args=[repo_id, repo.name, folder_path.strip('/')])
|
||||
notice.folder_link = folder_link
|
||||
notice.folder_name = folder_name
|
||||
notice.parent_dir_link = parent_dir_link
|
||||
notice.parent_dir_name = parent_dir_name
|
||||
notice.avatar_src = self.get_default_avatar_src()
|
||||
return notice
|
||||
|
||||
def format_group_join_request(self, notice):
|
||||
d = json.loads(notice.detail)
|
||||
username = d['username']
|
||||
@@ -299,13 +325,17 @@ class Command(BaseCommand):
|
||||
results = {}
|
||||
for notice in all_unseen_notices:
|
||||
if notice.to_user not in results:
|
||||
results[notice.to_user] = {'notices': [notice], 'sdoc_notices': [] , 'interval': DEFAULT_COLLABORATE_EMAIL_INTERVAL}
|
||||
results[notice.to_user] = {'notices': [notice],
|
||||
'sdoc_notices': [],
|
||||
'interval': DEFAULT_COLLABORATE_EMAIL_INTERVAL}
|
||||
else:
|
||||
results[notice.to_user]['notices'].append(notice)
|
||||
|
||||
for sdoc_notice in all_unseen_sdoc_notices:
|
||||
if sdoc_notice.username not in results:
|
||||
results[sdoc_notice.username] = {'notices': [], 'sdoc_notices': [sdoc_notice], 'interval': DEFAULT_COLLABORATE_EMAIL_INTERVAL}
|
||||
results[sdoc_notice.username] = {'notices': [],
|
||||
'sdoc_notices': [sdoc_notice],
|
||||
'interval': DEFAULT_COLLABORATE_EMAIL_INTERVAL}
|
||||
else:
|
||||
results[sdoc_notice.username]['sdoc_notices'].append(sdoc_notice)
|
||||
|
||||
@@ -323,7 +353,9 @@ class Command(BaseCommand):
|
||||
else:
|
||||
results[email]['interval'] = interval
|
||||
|
||||
return [(key, value['interval'], value['notices'], value['sdoc_notices'], sdoc_queryset) for key, value in results.items()]
|
||||
return [(key, value['interval'],
|
||||
value['notices'], value['sdoc_notices'],
|
||||
sdoc_queryset) for key, value in results.items()]
|
||||
|
||||
def do_action(self):
|
||||
|
||||
@@ -408,6 +440,9 @@ class Command(BaseCommand):
|
||||
elif notice.is_file_uploaded_msg():
|
||||
notice = self.format_file_uploaded_msg(notice)
|
||||
|
||||
elif notice.is_folder_uploaded_msg():
|
||||
notice = self.format_folder_uploaded_msg(notice)
|
||||
|
||||
elif notice.is_group_join_request():
|
||||
notice = self.format_group_join_request(notice)
|
||||
|
||||
|
@@ -66,6 +66,7 @@ class NotificationForm(ModelForm):
|
||||
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_FOLDER_UPLOADED = 'folder_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'
|
||||
@@ -88,6 +89,12 @@ def file_uploaded_msg_to_json(file_name, repo_id, uploaded_to):
|
||||
return json.dumps({'file_name': file_name, 'repo_id': repo_id,
|
||||
'uploaded_to': uploaded_to})
|
||||
|
||||
def folder_uploaded_msg_to_json(folder_name, repo_id, uploaded_to):
|
||||
"""Encode folder uploaded message to json string.
|
||||
"""
|
||||
return json.dumps({'folder_name': folder_name, 'repo_id': repo_id,
|
||||
'uploaded_to': uploaded_to})
|
||||
|
||||
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})
|
||||
@@ -265,6 +272,18 @@ class UserNotificationManager(models.Manager):
|
||||
return self._add_user_notification(to_user,
|
||||
MSG_TYPE_FILE_UPLOADED, detail)
|
||||
|
||||
def add_folder_uploaded_msg(self, to_user, detail):
|
||||
"""
|
||||
|
||||
Arguments:
|
||||
- `self`:
|
||||
- `to_user`:
|
||||
- `folder_name`:
|
||||
- `upload_to`:
|
||||
"""
|
||||
return self._add_user_notification(to_user,
|
||||
MSG_TYPE_FOLDER_UPLOADED, detail)
|
||||
|
||||
def add_repo_share_msg(self, to_user, detail):
|
||||
"""Notify ``to_user`` that others shared a repo to him/her.
|
||||
|
||||
@@ -378,6 +397,14 @@ class UserNotification(models.Model):
|
||||
"""
|
||||
return self.msg_type == MSG_TYPE_FILE_UPLOADED
|
||||
|
||||
def is_folder_uploaded_msg(self):
|
||||
"""
|
||||
|
||||
Arguments:
|
||||
- `self`:
|
||||
"""
|
||||
return self.msg_type == MSG_TYPE_FOLDER_UPLOADED
|
||||
|
||||
def is_repo_share_msg(self):
|
||||
"""
|
||||
|
||||
@@ -473,6 +500,8 @@ class UserNotification(models.Model):
|
||||
def format_msg(self):
|
||||
if self.is_file_uploaded_msg():
|
||||
return self.format_file_uploaded_msg()
|
||||
if self.is_folder_uploaded_msg():
|
||||
return self.format_folder_uploaded_msg()
|
||||
elif self.is_repo_share_msg():
|
||||
return self.format_repo_share_msg()
|
||||
elif self.is_repo_share_to_group_msg():
|
||||
@@ -535,6 +564,48 @@ class UserNotification(models.Model):
|
||||
|
||||
return msg
|
||||
|
||||
def format_folder_uploaded_msg(self):
|
||||
"""
|
||||
|
||||
Arguments:
|
||||
- `self`:
|
||||
"""
|
||||
try:
|
||||
d = json.loads(self.detail)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return _("Internal Server Error")
|
||||
|
||||
foldername = d['folder_name']
|
||||
repo_id = d['repo_id']
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if repo:
|
||||
if d['uploaded_to'] == '/':
|
||||
# current upload path is '/'
|
||||
folder_path = '/' + foldername
|
||||
link = reverse('lib_view', args=[repo_id, repo.name, ''])
|
||||
name = repo.name
|
||||
else:
|
||||
uploaded_to = d['uploaded_to'].rstrip('/')
|
||||
folder_path = uploaded_to + '/' + foldername
|
||||
link = reverse('lib_view', args=[repo_id, repo.name, uploaded_to.lstrip('/')])
|
||||
name = os.path.basename(uploaded_to)
|
||||
|
||||
folder_link = reverse('lib_view', args=[repo_id, repo.name, folder_path])
|
||||
|
||||
msg = _("A folder named <a href='%(folder_link)s'>%(folder_name)s</a> is uploaded to <a href='%(link)s'>%(name)s</a>") % {
|
||||
'folder_link': folder_link,
|
||||
'folder_name': escape(foldername),
|
||||
'link': link,
|
||||
'name': escape(name),
|
||||
}
|
||||
else:
|
||||
msg = _("A folder named <strong>%(folder_name)s</strong> is uploaded to <strong>Deleted Library</strong>") % {
|
||||
'folder_name': escape(foldername),
|
||||
}
|
||||
|
||||
return msg
|
||||
|
||||
def format_repo_share_msg(self):
|
||||
"""
|
||||
|
||||
@@ -810,7 +881,8 @@ class UserNotification(models.Model):
|
||||
########## handle signals
|
||||
from django.dispatch import receiver
|
||||
|
||||
from seahub.signals import upload_file_successful, comment_file_successful, repo_transfer
|
||||
from seahub.signals import upload_file_successful, upload_folder_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, change_repo_perm_successful, delete_repo_perm_successful
|
||||
@@ -836,6 +908,23 @@ def add_upload_file_msg_cb(sender, **kwargs):
|
||||
detail = file_uploaded_msg_to_json(filename, repo_id, folder_path)
|
||||
UserNotification.objects.add_file_uploaded_msg(owner, detail)
|
||||
|
||||
|
||||
@receiver(upload_folder_successful)
|
||||
def add_upload_folder_msg_cb(sender, **kwargs):
|
||||
"""Notify repo owner when others upload folder to his/her folder from shared link.
|
||||
"""
|
||||
repo_id = kwargs.get('repo_id', None)
|
||||
folder_path = kwargs.get('folder_path', None)
|
||||
owner = kwargs.get('owner', None)
|
||||
|
||||
assert repo_id and folder_path and owner is not None, 'Arguments error'
|
||||
|
||||
folder_name = os.path.basename(folder_path.rstrip('/'))
|
||||
parent_dir = os.path.dirname(folder_path.rstrip('/'))
|
||||
detail = folder_uploaded_msg_to_json(folder_name, repo_id, parent_dir)
|
||||
UserNotification.objects.add_folder_uploaded_msg(owner, detail)
|
||||
|
||||
|
||||
@receiver(share_repo_to_user_successful)
|
||||
def add_share_repo_msg_cb(sender, **kwargs):
|
||||
"""Notify user when others share repos to him/her.
|
||||
|
@@ -50,6 +50,9 @@ You've got {{num}} new notices on {{ site_name }}:
|
||||
{% elif notice.is_file_uploaded_msg %}
|
||||
<p style="line-height:1.5; margin:.2em 10px .2em 0;">{% blocktrans with file_url=notice.file_link file_name=notice.file_name folder_url=notice.folder_link folder_name=notice.folder_name %}A file named <a href="{{url_base}}{{file_url}}">{{file_name}}</a> is uploaded to your folder <a href="{{url_base}}{{folder_url}}">{{folder_name}}</a>.{% endblocktrans %}</p>
|
||||
|
||||
{% elif notice.is_folder_uploaded_msg %}
|
||||
<p style="line-height:1.5; margin:.2em 10px .2em 0;">{% blocktrans with folder_url=notice.folder_link folder_name=notice.folder_name parent_dir_url=notice.parent_dir_link parent_dir_name=notice.parent_dir_name %}A folder named <a href="{{url_base}}{{folder_url}}">{{folder_name}}</a> is uploaded to your folder <a href="{{url_base}}{{parent_dir_url}}">{{parent_dir_name}}</a>.{% endblocktrans %}</p>
|
||||
|
||||
{% elif notice.is_group_join_request %}
|
||||
<p style="line-height:1.5; margin:.2em 10px .2em 0;">{% blocktrans with user_url=notice.grpjoin_user_profile_url user=notice.notice_from grp_url=notice.grpjoin_group_url grp_name=notice.grpjoin_group_name msg=notice.grpjoin_request_msg %}User <a href="{{url_base}}{{user_url}}">{{user}}</a> has asked to join group <a href="{{url_base}}{{grp_url}}">{{grp_name}}</a>, verification message: {{msg}}{% endblocktrans %}</p>
|
||||
|
||||
|
@@ -144,7 +144,6 @@ def update_notice_detail(request, notices):
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
elif notice.is_repo_share_to_group_msg():
|
||||
try:
|
||||
d = json.loads(notice.detail)
|
||||
@@ -285,6 +284,41 @@ def update_notice_detail(request, notices):
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
elif notice.is_folder_uploaded_msg():
|
||||
try:
|
||||
d = json.loads(notice.detail)
|
||||
foldername = d['folder_name']
|
||||
repo_id = d['repo_id']
|
||||
|
||||
if repo_id in repo_dict:
|
||||
repo = repo_dict[repo_id]
|
||||
else:
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
repo_dict[repo_id] = repo
|
||||
|
||||
if repo:
|
||||
if d['uploaded_to'] == '/':
|
||||
# current upload path is '/'
|
||||
folder_path = '/' + foldername
|
||||
name = repo.name
|
||||
else:
|
||||
uploaded_to = d['uploaded_to'].rstrip('/')
|
||||
folder_path = uploaded_to + '/' + foldername
|
||||
name = os.path.basename(uploaded_to)
|
||||
|
||||
d['repo_name'] = repo.name
|
||||
d['parent_dir_path'] = d.pop('uploaded_to')
|
||||
d['parent_dir_name'] = name
|
||||
d['folder_path'] = folder_path
|
||||
url, is_default, date_uploaded = api_avatar_url('', 32)
|
||||
d['uploaded_user_avatar_url'] = url
|
||||
notice.detail = d
|
||||
else:
|
||||
notice.detail = None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
elif notice.is_file_comment_msg():
|
||||
try:
|
||||
d = json.loads(notice.detail)
|
||||
|
@@ -8,5 +8,6 @@ repo_transfer = Signal()
|
||||
clean_up_repo_trash = Signal()
|
||||
repo_restored = Signal()
|
||||
upload_file_successful = Signal()
|
||||
upload_folder_successful = Signal()
|
||||
comment_file_successful = Signal()
|
||||
institution_deleted = Signal()
|
||||
|
Reference in New Issue
Block a user