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 %}
+ {{ dirent.obj_name }} |
+ {{ dirent.delete_time|translate_commit_time }} |
+ {% else %}
+ {{ dirent.obj_name }} |
+ |
+ {% endif %}
+ |
+ |
+
+ {% endfor %}
+
+ {% for dirent in file_list %}
+
+  |
+ {% if show_recycle_root %}
+ {{ dirent.obj_name }} |
+ {{ dirent.delete_time|translate_commit_time }} |
+ {{ dirent.file_size|filesizeformat }} |
+ 还原 |
+ {% else %}
+ {{ dirent.props.obj_name }} |
+ |
+ {{ dirent.file_size|filesizeformat }} |
+ |
+ {% endif %}
+
+ {% endfor %}
+
+
+
+ {% 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)