diff --git a/seahub/templates/sysadmin/sys_list_orphan.html b/seahub/templates/sysadmin/sys_list_orphan.html
index e6590ef788..5229a9f00d 100644
--- a/seahub/templates/sysadmin/sys_list_orphan.html
+++ b/seahub/templates/sysadmin/sys_list_orphan.html
@@ -14,6 +14,7 @@
{% trans "All" %}
{% trans "Orphan" %}
{% trans "System" %}
+ {% trans "Trash" %}
diff --git a/seahub/templates/sysadmin/sys_list_system.html b/seahub/templates/sysadmin/sys_list_system.html
index e980fb7bad..751688981f 100644
--- a/seahub/templates/sysadmin/sys_list_system.html
+++ b/seahub/templates/sysadmin/sys_list_system.html
@@ -14,6 +14,7 @@
{% trans "All" %}
{% trans "Orphan" %}
{% trans "System" %}
+ {% trans "Trash" %}
diff --git a/seahub/templates/sysadmin/sys_repo_admin.html b/seahub/templates/sysadmin/sys_repo_admin.html
index 197922f640..a15d509910 100644
--- a/seahub/templates/sysadmin/sys_repo_admin.html
+++ b/seahub/templates/sysadmin/sys_repo_admin.html
@@ -14,6 +14,7 @@
{% trans "All" %}
{% trans "Orphan" %}
{% trans "System" %}
+ {% trans "Trash" %}
diff --git a/seahub/templates/sysadmin/sys_repo_trash.html b/seahub/templates/sysadmin/sys_repo_trash.html
new file mode 100644
index 0000000000..ecda852229
--- /dev/null
+++ b/seahub/templates/sysadmin/sys_repo_trash.html
@@ -0,0 +1,76 @@
+{% extends "sysadmin/base.html" %}
+{% load i18n %}
+{% block cur_repo %}tab-cur{% endblock %}
+
+{% block left_panel %}{{block.super}}
+
+{% endblock %}
+
+{% block right_panel %}
+
+
+
+
+
+
+
+{% if repos %}
+
+{% if not search_owner %}
+{% include "snippets/admin_paginator.html" %}
+{% endif %}
+
+{% else %}
+
+
{% trans "No library deleted yet" %}
+
+{% endif %}
+
+{% endblock %}
+
+{% block extra_script %}
+
+{% endblock %}
diff --git a/seahub/urls.py b/seahub/urls.py
index 3126d74618..b55505d54f 100644
--- a/seahub/urls.py
+++ b/seahub/urls.py
@@ -192,6 +192,10 @@ urlpatterns = patterns('',
url(r'^sys/seafadmin/$', sys_repo_admin, name='sys_repo_admin'),
url(r'^sys/seafadmin/orphan/$', sys_list_orphan, name='sys_list_orphan'),
url(r'^sys/seafadmin/system/$', sys_list_system, name='sys_list_system'),
+ url(r'^sys/seafadmin/repo-trash/$', sys_repo_trash, name='sys_repo_trash'),
+ url(r'^sys/seafadmin/repo-trash/clear/$', sys_repo_trash_clear, name="sys_repo_trash_clear"),
+ url(r'^sys/seafadmin/repo-trash/(?P[-0-9a-f]{36})/remove/$', sys_repo_trash_remove, name="sys_repo_trash_remove"),
+ url(r'^sys/seafadmin/repo-trash/(?P[-0-9a-f]{36})/restore/$', sys_repo_trash_restore, name="sys_repo_trash_restore"),
url(r'^sys/seafadmin/search/$', sys_repo_search, name='sys_repo_search'),
url(r'^sys/seafadmin/transfer/$', sys_repo_transfer, name='sys_repo_transfer'),
url(r'^sys/useradmin/$', sys_user_admin, name='sys_useradmin'),
diff --git a/seahub/views/sysadmin.py b/seahub/views/sysadmin.py
index 79d9476b0f..fb49bc150d 100644
--- a/seahub/views/sysadmin.py
+++ b/seahub/views/sysadmin.py
@@ -108,6 +108,106 @@ def sys_list_system(request):
'repos': repos,
}, context_instance=RequestContext(request))
+@login_required
+@sys_staff_required
+def sys_repo_trash(request):
+ """ List deleted repos (by owner) """
+
+ search_owner = request.GET.get('name', '')
+ if search_owner:
+ if is_valid_username(search_owner):
+ repos = seafserv_threaded_rpc.get_trash_repos_by_owner(search_owner)
+ return render_to_response(
+ 'sysadmin/sys_repo_trash.html', {
+ 'repos': repos,
+ 'search_owner': search_owner,
+ }, context_instance=RequestContext(request))
+ else:
+ messages.error(request, _(u'Invalid username'))
+ return HttpResponseRedirect(reverse('sys_repo_trash'))
+
+ try:
+ current_page = int(request.GET.get('page', '1'))
+ per_page = int(request.GET.get('per_page', '25'))
+ except ValueError:
+ current_page = 1
+ per_page = 25
+
+ repos_all = seafserv_threaded_rpc.get_trash_repo_list(per_page * (current_page -1),
+ per_page + 1)
+ repos = repos_all[:per_page]
+ if len(repos_all) == per_page + 1:
+ page_next = True
+ else:
+ page_next = False
+
+ return render_to_response(
+ 'sysadmin/sys_repo_trash.html', {
+ 'repos': repos,
+ 'current_page': current_page,
+ 'prev_page': current_page-1,
+ 'next_page': current_page+1,
+ 'per_page': per_page,
+ 'page_next': page_next,
+ }, context_instance=RequestContext(request))
+
+@login_required
+@sys_staff_required
+def sys_repo_trash_restore(request, repo_id):
+ """Restore deleted repo by id"""
+
+ referer = request.META.get('HTTP_REFERER', None)
+ next = reverse('sys_repo_trash') if referer is None else referer
+
+ try:
+ seafserv_threaded_rpc.restore_repo_from_trash(repo_id)
+ messages.success(request, _(u'Success'))
+ except SearpcError, e:
+ logger.error(e)
+ messages.error(request, _(u'Failed'))
+
+ return HttpResponseRedirect(next)
+
+@login_required
+@sys_staff_required
+def sys_repo_trash_remove(request, repo_id):
+ """Remove deleted repo by id"""
+
+ referer = request.META.get('HTTP_REFERER', None)
+ next = reverse('sys_repo_trash') if referer is None else referer
+
+ try:
+ seafserv_threaded_rpc.del_repo_from_trash(repo_id)
+ messages.success(request, _(u'Success'))
+ except SearpcError, e:
+ logger.error(e)
+ messages.error(request, _(u'Failed'))
+
+ return HttpResponseRedirect(next)
+
+@login_required
+@sys_staff_required
+def sys_repo_trash_clear(request):
+ """Clear repo trash (by owner)"""
+
+ next = reverse('sys_repo_trash')
+ owner = request.GET.get('owner', '')
+ try:
+ if owner:
+ if is_valid_username(owner):
+ seafserv_threaded_rpc.empty_repo_trash_by_owner(owner)
+ else:
+ messages.error(request, _(u'Invalid username'))
+ return HttpResponseRedirect(next)
+ else:
+ seafserv_threaded_rpc.empty_repo_trash()
+ except SearpcError, e:
+ logger.error(e)
+ messages.error(request, _(u'Failed'))
+
+ messages.success(request, _(u'Success'))
+ return HttpResponseRedirect(next)
+
def list_repos_by_name_and_owner(repo_name, owner):
repos = []
owned_repos = seafile_api.get_owned_repo_list(owner)