diff --git a/media/css/seahub.css b/media/css/seahub.css index 7efda9e8de..6ebd3694a0 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -748,6 +748,9 @@ ul.with-bg li { height:25px; background:#f5f5f5 scroll no-repeat 3px 48%; } +#recycle-btn { + background:#f5f5f5 scroll no-repeat 3px 40%; +} #upload-file { padding-left:19px; background-image:url('../img/upload.png'); @@ -839,12 +842,18 @@ ul.with-bg li { .icon-container { text-align:center; } -#repo-download-btn { +#repo-download-btn, #recycle-btn { font-size:14px; height:26px; padding:0 5px 0 20px; +} +#repo-download-btn { background-image: url('../img/download-16.png'); } +#recycle-btn { + background-image: url('../img/delete-16.png'); + margin-right:10px; +} #repo-latest-commit, #file-commit-info { word-wrap:break-word; diff --git a/media/img/delete-16.png b/media/img/delete-16.png new file mode 100644 index 0000000000..9330d9aa42 Binary files /dev/null and b/media/img/delete-16.png differ diff --git a/templates/repo.html b/templates/repo.html index 5930ea9f9a..11455befd6 100644 --- a/templates/repo.html +++ b/templates/repo.html @@ -18,6 +18,7 @@

{{repo.props.name}}

{% if user_perm == 'rw' %} + {% endif %} {% if user_perm != 'rw' %} @@ -513,7 +514,7 @@ $('#add-new-file').click(function () { $('#add-new-file-form').modal({appendTo:'#main'}); }); -$('#upload-file, #add-new-dir, #add-new-file,#repo-download-btn').hover( +$('#upload-file, #add-new-dir, #add-new-file, #repo-download-btn, #recycle-btn').hover( function() { $(this).css({'background-color': '#fff', 'cursor': 'pointer'}); }, @@ -525,6 +526,11 @@ $('#upload-file, #add-new-dir, #add-new-file,#repo-download-btn').hover( $('#repo-download-btn').click(function() { window.open('{{ SITE_ROOT }}seafile_access_check/?repo_id={{repo.props.id}}'); }); + +$('#recycle-btn').click(function() { + location.href = $(this).attr('data'); +}); + {% include "snippets/list_commit_detail.html" %} {% include "snippets/bottom_bar.html" %} diff --git a/templates/repo_recycle_view.html b/templates/repo_recycle_view.html new file mode 100644 index 0000000000..db46580281 --- /dev/null +++ b/templates/repo_recycle_view.html @@ -0,0 +1,81 @@ +{% extends base_template %} + +{% load seahub_tags avatar_tags %} +{% load url from future %} + +{% block main_panel %} +
+

{{repo.props.name}} 的文件回收站

+ +
+ +
+
+
+

+ 当前路径: + {{repo.props.name}} 的文件回收站 + {% if not show_recycle_root %} + {% for name, link in zipped %} + {% if not forloop.last %} + / {{ name }} + {% else %} + / {{ name }} + {% endif %} + {% endfor %} + {% endif %} +

+
+ + + + + + + + + + + {% for dirent in dir_list %} + + + {% if show_recycle_root %} + + + {% else %} + + + {% endif %} + + + + {% endfor %} + + {% for dirent in file_list %} + + + {% if show_recycle_root %} + + + + + {% else %} + + + + + {% endif %} + + {% endfor %} +
名字删除时间大小操作
目录{{ dirent.obj_name }}{{ dirent.delete_time|translate_commit_time }}{{ dirent.obj_name }}
文件{{ dirent.obj_name }}{{ dirent.delete_time|translate_commit_time }}{{ dirent.file_size|filesizeformat }}还原{{ dirent.props.obj_name }}{{ dirent.file_size|filesizeformat }}
+
+
+ {% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/templates/repo_view_file.html b/templates/repo_view_file.html index 51d41c4b53..3c53d527d8 100644 --- a/templates/repo_view_file.html +++ b/templates/repo_view_file.html @@ -25,10 +25,31 @@ {% endif %} + {% if page_from == 'recycle' %} +
+

+ {{repo.props.name}} 的文件回收站 +

+ +
+ {% endif %} {% endif %}

当前路径: + {% if page_from == 'recycle' %} + + {{repo.props.name}} 的文件回收站 + {% for name, link in zipped %} + {% if not forloop.last %} + / {{ name }} + {% else %} + / {{ name }} + {% endif %} + {% endfor %} + + {% else %} + {% for name, link in zipped %} {% if not forloop.last %} {% if view_history %} @@ -44,6 +65,8 @@ {{ name }} {% endif %} {% endfor %} + + {% endif %}

{% if not view_history %} @@ -422,10 +445,12 @@ $('#open-local').click(function () { //'not view_history' ends here {% endif %} -{% if view_history and page_from == 'file_history' %} +{% if view_history %} + {% if page_from == 'file_history' or page_from == 'recycle' %} $('#back').click(function() { location.href = $(this).attr('data'); }); + {% endif %} {% endif %} {% endblock %} diff --git a/urls.py b/urls.py index be7d2312d8..192e4d0aca 100644 --- a/urls.py +++ b/urls.py @@ -58,6 +58,7 @@ urlpatterns = patterns('', (r'^repo/history/(?P[^/]+)/$', repo_history), (r'^repo/history/revert/(?P[^/]+)/$', repo_history_revert), url(r'^repo/history/view/(?P[^/]+)/$', RepoHistoryView.as_view(), name='repo_history_view'), + url(r'^repo/recycle/(?P[^/]+)/$', repo_recycle_view, name='repo_recycle_view'), url(r'^repo/snapshot/view/(?P[^/]+)/$', repo_view_snapshot, name='repo_view_snapshot'), # (r'^repo/token/modify/(?P[^/]+)/$', modify_token), (r'^repo/history/changes/(?P[^/]+)/$', repo_history_changes), diff --git a/views.py b/views.py index 6cb90d3e97..58d2ecd6ef 100644 --- a/views.py +++ b/views.py @@ -144,13 +144,38 @@ def gen_path_link(path, repo_name): link = '/' + '/'.join(paths[:i]) i = i + 1 links.append(link) - paths.insert(0, repo_name) - links.insert(0, '/') + if repo_name: + paths.insert(0, repo_name) + links.insert(0, '/') zipped = zip(paths, links) return zipped +def get_repo_dirents(commit, path): + dir_list = [] + file_list = [] + if commit.root_id == EMPTY_SHA1: + return ([], []) + else: + try: + dirs = seafserv_threaded_rpc.list_dir_by_path(commit.id, path.encode('utf-8')) + except SearpcError, e: + raise Http404 + # return render_error(self.request, e.msg) + for dirent in dirs: + if stat.S_ISDIR(dirent.props.mode): + dir_list.append(dirent) + else: + file_list.append(dirent) + dirent.file_size = get_file_size(dirent.obj_id) + + dir_list.sort(lambda x, y : cmp(x.obj_name.lower(), + y.obj_name.lower())) + file_list.sort(lambda x, y : cmp(x.obj_name.lower(), + y.obj_name.lower())) + return (file_list, dir_list) + class RepoMixin(object): def get_repo_id(self): return self.kwargs.get('repo_id', '') @@ -179,32 +204,6 @@ class RepoMixin(object): return is_passwd_set(self.repo.id, self.user.username) return False - def get_repo_dirents(self): - dir_list = [] - file_list = [] - if self.current_commit.root_id == EMPTY_SHA1: - return ([], []) - else: - try: - dirs = seafserv_threaded_rpc.list_dir_by_path( - self.current_commit.id, - self.path.encode('utf-8')) - except SearpcError, e: - raise Http404 - # return render_error(self.request, e.msg) - for dirent in dirs: - if stat.S_ISDIR(dirent.props.mode): - dir_list.append(dirent) - else: - file_list.append(dirent) - dirent.file_size = get_file_size(dirent.obj_id) - - dir_list.sort(lambda x, y : cmp(x.obj_name.lower(), - y.obj_name.lower())) - file_list.sort(lambda x, y : cmp(x.obj_name.lower(), - y.obj_name.lower())) - return (file_list, dir_list) - def get_nav_path(self): zipped = gen_path_link(self.path, self.repo.name) return zipped @@ -242,7 +241,7 @@ class RepoMixin(object): self.zipped = None self.applet_root = None else: - self.file_list, self.dir_list = self.get_repo_dirents() + self.file_list, self.dir_list = get_repo_dirents(self.current_commit, self.path) self.zipped = self.get_nav_path() self.applet_root = self.get_applet_root() @@ -337,6 +336,81 @@ class RepoHistoryView(LoginRequiredMixin, CtxSwitchRequiredMixin, RepoMixin, kwargs['zipped'] = self.zipped return kwargs +def render_recycle_root(request, repo_id): + repo = get_repo(repo_id) + if not repo: + raise Http404 + + try: + deleted_entries = seafserv_threaded_rpc.get_deleted(repo_id) + except: + deleted_entries = [] + + dir_list = [] + file_list = [] + for dirent in deleted_entries: + if stat.S_ISDIR(dirent.mode): + dir_list.append(dirent) + else: + file_list.append(dirent) + + dir_list.sort(lambda x, y : cmp(x.obj_name.lower(), + y.obj_name.lower())) + file_list.sort(lambda x, y : cmp(x.obj_name.lower(), + y.obj_name.lower())) + + return render_to_response('repo_recycle_view.html', { + 'show_recycle_root': True, + 'repo': repo, + 'dir_list': dir_list, + 'file_list': file_list, + }, context_instance=RequestContext(request)) + +def render_recycle_dir(request, repo_id, commit_id): + basedir = request.GET.get('base', '') + path = request.GET.get('p', '') + if not basedir or not path: + return render_recycle_root(request, repo_id) + + if basedir[0] != '/': + basedir = '/' + basedir + if path[-1] != '/': + path += '/' + + repo = get_repo(repo_id) + if not repo: + raise Http404 + + commit = seafserv_threaded_rpc.get_commit(commit_id) + if not commit: + raise Http404 + + zipped = gen_path_link(path, '') + file_list, dir_list = get_repo_dirents(commit, basedir + path) + + return render_to_response('repo_recycle_view.html', { + 'show_recycle_root': False, + 'repo': repo, + 'zipped': zipped, + 'dir_list': dir_list, + 'file_list': file_list, + 'commit_id': commit_id, + 'basedir': basedir, + 'path': path, + }, context_instance=RequestContext(request)) + +@login_required +@ctx_switch_required +def repo_recycle_view(request, repo_id): + if get_user_permission(request, repo_id) != 'rw': + return render_permission_error(request, '无法查看文件回收站') + + commit_id = request.GET.get('commit_id', '') + if not commit_id: + return render_recycle_root(request, repo_id) + else: + return render_recycle_dir(request, repo_id, commit_id) + @login_required @ctx_switch_required def repo_upload_file(request, repo_id): @@ -1086,6 +1160,12 @@ def repo_view_file(request, repo_id): if not current_commit: current_commit = get_commits(repo_id, 0, 1)[0] + basedir = '' + if page_from == 'recycle': + basedir = request.GET.get('base', '') + if not basedir: + raise Http404 + if view_history: obj_id = request.GET.get('obj_id', '') else: @@ -1120,7 +1200,10 @@ def repo_view_file(request, repo_id): read_only = True if permission == 'r' else False # generate path and link - zipped = gen_path_link(path, repo.name) + if page_from == 'recycle': + zipped = gen_path_link(path, '') + else: + zipped = gen_path_link(path, repo.name) # determin whether file can preview on web filetype, fileext = valid_previewed_file(filename) @@ -1141,6 +1224,29 @@ def repo_view_file(request, repo_id): pdf_use_flash = use_flash_for_pdf(request) if pdf_use_flash: err, swf_exists = flash_prepare(raw_path, obj_id, 'pdf') + + if view_history: + return render_to_response('repo_view_file.html', { + 'repo': repo, + 'obj_id': obj_id, + 'u_filename': u_filename, + 'file_name': filename, + 'path': path, + 'zipped': zipped, + 'view_history': view_history, + 'current_commit': current_commit, + 'token': token, + 'filetype': filetype, + 'fileext': fileext, + 'raw_path': raw_path, + 'err': err, + 'file_content': file_content, + 'swf_exists': swf_exists, + 'pdf_use_flash': pdf_use_flash, + 'DOCUMENT_CONVERTOR_ROOT': DOCUMENT_CONVERTOR_ROOT, + 'page_from': page_from, + 'basedir': basedir, + }, context_instance=RequestContext(request)) # file share link l = FileShare.objects.filter(repo_id=repo_id).filter(\ @@ -2162,6 +2268,9 @@ def repo_revert_file (request, repo_id): if from_page == 'repo_history': # When revert file from repo history, we redirect to repo history url = reverse('repo', args=[repo_id]) + u'?commit_id=%s&history=y' % commit_id + elif from_page == 'recycle': + # When revert from recycle page, redirect to recycle page. + url = reverse('repo_recycle_view', args=[repo_id]) else: # When revert file from file history, we redirect to parent dir of this file parent_dir = os.path.dirname(path)