- {{ inst.name }} |
+ {{ inst.name }} |
{{ inst.create_time|translate_seahub_time }} |
{% trans "Remove" %}
diff --git a/seahub/templates/sysadmin/sys_inst_info_admins.html b/seahub/templates/sysadmin/sys_inst_info_admins.html
new file mode 100644
index 0000000000..d5c7bc4547
--- /dev/null
+++ b/seahub/templates/sysadmin/sys_inst_info_admins.html
@@ -0,0 +1,62 @@
+{% extends "sysadmin/sys_inst_info_base.html" %}
+{% load i18n seahub_tags %}
+
+{% block right_panel %}
+
+
+{% if admins %}
+
+
+ {% trans "Email" %} |
+ {% trans "Status" %} |
+ {% trans "Space Used" %} |
+ {% trans "Create At / Last Login" %} |
+ {% trans "Operations" %} |
+
+
+ {% for user in admins %}
+
+ {{ user.email }} |
+
+
+ {% if user.is_active %}
+ {% trans "Active" %}
+ {% else %}
+ {% trans "Inactive" %}
+ {% endif %}
+
+ |
+
+ {{ user.space_usage|seahub_filesizeformat }} {% if user.space_quota > 0 %} / {{ user.space_quota|seahub_filesizeformat }} {% endif %}
+ |
+
+ {{ user.ctime|tsstr_sec }} / {% if user.last_login %}{{user.last_login|translate_seahub_time}} {% else %} -- {% endif %}
+ |
+
+ {% trans "Revoke Admin" %}
+ |
+
+ {% endfor %}
+
+{% else %}
+{% trans "Empty" %}
+{% endif %}
+
+{% endblock %}
+
+{% block extra_script %}
+
+{% endblock %}
diff --git a/seahub/templates/sysadmin/sys_inst_info_base.html b/seahub/templates/sysadmin/sys_inst_info_base.html
index 471b3db6ba..0200a06479 100644
--- a/seahub/templates/sysadmin/sys_inst_info_base.html
+++ b/seahub/templates/sysadmin/sys_inst_info_base.html
@@ -15,10 +15,15 @@
{% block left_panel %}
- {{ inst.name }}
+
- {% trans "Number of members" %}
- {{ users_count }}
+
+
+
{% endblock %}
diff --git a/seahub/templates/sysadmin/sys_inst_info_user.html b/seahub/templates/sysadmin/sys_inst_info_user.html
index 4e8e246fc7..25d86c1ca6 100644
--- a/seahub/templates/sysadmin/sys_inst_info_user.html
+++ b/seahub/templates/sysadmin/sys_inst_info_user.html
@@ -4,7 +4,8 @@
{% block right_panel %}
diff --git a/seahub/templates/sysadmin/sys_inst_search_user.html b/seahub/templates/sysadmin/sys_inst_search_user.html
new file mode 100644
index 0000000000..1c84c423de
--- /dev/null
+++ b/seahub/templates/sysadmin/sys_inst_search_user.html
@@ -0,0 +1,61 @@
+{% extends "sysadmin/sys_inst_info_base.html" %}
+{% load i18n seahub_tags %}
+
+{% block right_panel %}
+{% trans "Search User"%}
+
+
+{% trans "Result"%}
+
+{% if users %}
+
+
+ {% trans "Email" %} |
+ {% trans "Status" %} |
+ {% trans "Space Used" %} |
+ {% trans "Create At / Last Login" %} |
+ {% trans "Operations" %} |
+
+
+ {% for user in users %}
+
+ {{ user.email }} |
+
+
+ {% if user.is_active %}
+ {% trans "Active" %}
+ {% else %}
+ {% trans "Inactive" %}
+ {% endif %}
+
+ |
+
+ {{ user.space_usage|seahub_filesizeformat }} {% if user.space_quota > 0 %} / {{ user.space_quota|seahub_filesizeformat }} {% endif %}
+ |
+
+ {{ user.ctime|tsstr_sec }} / {% if user.last_login %}{{user.last_login|translate_seahub_time}} {% else %} -- {% endif %}
+ |
+
+ {% if user.inst_admin %}{% trans "Revoke Admin" %}{% else %}{% trans "Set Admin" %}{% endif %}
+ |
+
+ {% endfor %}
+
+{% else %}
+{% trans "No result" %}
+{% endif %}
+
+{% endblock %}
+
+{% block extra_script %}
+
+{% endblock %}
diff --git a/seahub/urls.py b/seahub/urls.py
index 340ca5a316..5a06f4f0ef 100644
--- a/seahub/urls.py
+++ b/seahub/urls.py
@@ -246,7 +246,9 @@ urlpatterns = patterns(
url(r'^sys/orgadmin/(?P\d+)/setting/$', sys_org_info_setting, name='sys_org_info_setting'),
url(r'^sys/instadmin/$', sys_inst_admin, name='sys_inst_admin'),
url(r'^sys/instadmin/(?P\d+)/remove/$', sys_inst_remove, name='sys_inst_remove'),
- url(r'^sys/instadmin/(?P\d+)/user/$', sys_inst_info_user, name='sys_inst_info_user'),
+ url(r'^sys/instadmin/(?P\d+)/users/$', sys_inst_info_user, name='sys_inst_info_users'),
+ url(r'^sys/instadmin/(?P\d+)/users/search/$', sys_inst_search_user, name='sys_inst_search_user'),
+ url(r'^sys/instadmin/(?P\d+)/admins/$', sys_inst_info_admins, name='sys_inst_info_admins'),
url(r'^sys/instadmin/(?P\d+)/toggleadmin/(?P[^/]+)/$', sys_inst_toggle_admin, name='sys_inst_toggle_admin'),
url(r'^sys/publinkadmin/$', sys_publink_admin, name='sys_publink_admin'),
url(r'^sys/publink/remove/$', sys_publink_remove, name='sys_publink_remove'),
diff --git a/seahub/views/sysadmin.py b/seahub/views/sysadmin.py
index d9004558d7..79228c3c14 100644
--- a/seahub/views/sysadmin.py
+++ b/seahub/views/sysadmin.py
@@ -2339,7 +2339,7 @@ def sys_inst_remove(request, inst_id):
@login_required
@sys_staff_required
def sys_inst_info_user(request, inst_id):
- """List institution members.
+ """List institution members including admins.
"""
try:
inst = Institution.objects.get(pk=inst_id)
@@ -2378,7 +2378,7 @@ def sys_inst_info_user(request, inst_id):
if last_login.username == u.email:
u.last_login = last_login.last_login
- users_count = len(users)
+ users_count = Profile.objects.filter(institution=inst.name).count()
return render_to_response('sysadmin/sys_inst_info_user.html', {
'inst': inst,
@@ -2391,6 +2391,80 @@ def sys_inst_info_user(request, inst_id):
'page_next': page_next,
}, context_instance=RequestContext(request))
+@login_required
+@sys_staff_required
+def sys_inst_search_user(request, inst_id):
+ """Search institution members.
+ """
+ try:
+ inst = Institution.objects.get(pk=inst_id)
+ except Institution.DoesNotExist:
+ raise Http404
+
+ q = request.GET.get('q', '').lower()
+ if not q:
+ return HttpResponseRedirect(reverse('sys_inst_info_users', args=[inst_id]))
+
+ profiles = Profile.objects.filter(institution=inst.name)
+ usernames = [x.user for x in profiles if q in x.user]
+ users = [User.objects.get(x) for x in usernames]
+
+ inst_admins = [x.user for x in InstitutionAdmin.objects.filter(institution=inst)]
+ last_logins = UserLastLogin.objects.filter(username__in=[x for x in users])
+ for u in users:
+ _populate_user_quota_usage(u)
+
+ if u.username in inst_admins:
+ u.inst_admin = True
+ else:
+ u.inst_admin = False
+
+ # populate user last login time
+ u.last_login = None
+ for last_login in last_logins:
+ if last_login.username == u.email:
+ u.last_login = last_login.last_login
+
+ users_count = Profile.objects.filter(institution=inst.name).count()
+
+ return render_to_response('sysadmin/sys_inst_search_user.html', {
+ 'q': q,
+ 'inst': inst,
+ 'users': users,
+ 'users_count': users_count,
+ }, context_instance=RequestContext(request))
+
+@login_required
+@sys_staff_required
+def sys_inst_info_admins(request, inst_id):
+ """List institution admins.
+ """
+ try:
+ inst = Institution.objects.get(pk=inst_id)
+ except Institution.DoesNotExist:
+ raise Http404
+
+ inst_admins = [x.user for x in InstitutionAdmin.objects.filter(institution=inst)]
+ admins = [User.objects.get(x) for x in inst_admins]
+
+ last_logins = UserLastLogin.objects.filter(username__in=[x.email for x in admins])
+ for u in admins:
+ _populate_user_quota_usage(u)
+
+ # populate user last login time
+ u.last_login = None
+ for last_login in last_logins:
+ if last_login.username == u.email:
+ u.last_login = last_login.last_login
+
+ users_count = Profile.objects.filter(institution=inst.name).count()
+
+ return render_to_response('sysadmin/sys_inst_info_admins.html', {
+ 'inst': inst,
+ 'admins': admins,
+ 'users_count': users_count,
+ }, context_instance=RequestContext(request))
+
@login_required
@sys_staff_required
@require_POST
@@ -2402,13 +2476,19 @@ def sys_inst_toggle_admin(request, inst_id, email):
except Institution.DoesNotExist:
raise Http404
+ next = request.META.get('HTTP_REFERER', None)
+ if not next:
+ next = reverse('sys_inst_info_users', args=[inst.pk])
+
try:
u = User.objects.get(email=email)
except User.DoesNotExist:
assert False, 'TODO'
if u.is_staff:
- assert False
+ messages.error(
+ request, 'Can not assign institutional administration roles to global administrators')
+ return HttpResponseRedirect(next)
res = InstitutionAdmin.objects.filter(institution=inst, user=email)
if len(res) == 0:
@@ -2420,4 +2500,4 @@ def sys_inst_toggle_admin(request, inst_id, email):
assert False
messages.success(request, _('Success'))
- return HttpResponseRedirect(reverse('sys_inst_info_user', args=[inst.pk]))
+ return HttpResponseRedirect(next)
diff --git a/tests/seahub/institutions/test_views.py b/tests/seahub/institutions/test_views.py
new file mode 100644
index 0000000000..e58a25cfdb
--- /dev/null
+++ b/tests/seahub/institutions/test_views.py
@@ -0,0 +1,69 @@
+from django.conf import settings
+from django.core.urlresolvers import reverse
+from django.http.cookie import parse_cookie
+from django.test import override_settings
+
+from seahub.institutions.models import Institution, InstitutionAdmin
+from seahub.profile.models import Profile
+from seahub.test_utils import BaseTestCase
+
+settings.MIDDLEWARE_CLASSES += (
+ 'seahub.institutions.middleware.InstitutionMiddleware',
+)
+
+
+class InstTestBase(BaseTestCase):
+ def setUp(self):
+ self.inst = Institution.objects.create(name='inst_test')
+
+ assert len(Profile.objects.all()) == 0
+ p = Profile.objects.add_or_update(self.user.username, '')
+ p.institution = self.inst.name
+ p.save()
+
+ p = Profile.objects.add_or_update(self.admin.username, '')
+ p.institution = self.inst.name
+ p.save()
+ assert len(Profile.objects.all()) == 2
+
+ InstitutionAdmin.objects.create(institution=self.inst,
+ user=self.user.username)
+
+class InfoTest(InstTestBase):
+ @override_settings(
+ MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES,
+ MULTI_INSTITUTION=True
+ )
+ def test_can_render(self):
+ self.login_as(self.user)
+
+ resp = self.client.get(reverse('institutions:info'))
+ self.assertEqual(200, resp.status_code)
+ assert resp.context['inst'] == self.inst
+
+
+class UseradminTest(InstTestBase):
+ @override_settings(
+ MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES,
+ MULTI_INSTITUTION=True
+ )
+ def test_can_list(self):
+ self.login_as(self.user)
+ resp = self.client.get(reverse('institutions:useradmin'))
+ self.assertEqual(200, resp.status_code)
+ assert resp.context['inst'] == self.inst
+ assert len(resp.context['users']) == 2
+
+
+class UseradminSearchTest(InstTestBase):
+ @override_settings(
+ MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES,
+ MULTI_INSTITUTION=True
+ )
+ def test_can_search(self):
+ self.login_as(self.user)
+ resp = self.client.get(reverse('institutions:useradmin_search') + '?q=@')
+ self.assertEqual(200, resp.status_code)
+ assert resp.context['inst'] == self.inst
+ assert len(resp.context['users']) == 2
+ assert resp.context['q'] == '@'
diff --git a/tests/seahub/views/sysadmin/test_sys_inst_info_admins.py b/tests/seahub/views/sysadmin/test_sys_inst_info_admins.py
new file mode 100644
index 0000000000..ee109b2179
--- /dev/null
+++ b/tests/seahub/views/sysadmin/test_sys_inst_info_admins.py
@@ -0,0 +1,34 @@
+from django.core.urlresolvers import reverse
+
+from seahub.institutions.models import Institution, InstitutionAdmin
+from seahub.profile.models import Profile
+from seahub.test_utils import BaseTestCase
+
+class SysInstInfoAdminsTest(BaseTestCase):
+ def setUp(self):
+ self.login_as(self.admin)
+
+ self.inst = Institution.objects.create(name='inst_test')
+ self.url = reverse('sys_inst_info_users', args=[self.inst.pk])
+
+ assert len(Profile.objects.all()) == 0
+ p = Profile.objects.add_or_update(self.user.username, '')
+ p.institution = self.inst.name
+ p.save()
+
+ p = Profile.objects.add_or_update(self.admin.username, '')
+ p.institution = self.inst.name
+ p.save()
+ assert len(Profile.objects.all()) == 2
+
+ InstitutionAdmin.objects.create(institution=self.inst,
+ user=self.user.username)
+ InstitutionAdmin.objects.create(institution=self.inst,
+ user=self.admin.username)
+
+ def test_can_list(self):
+ resp = self.client.get(self.url)
+
+ self.assertTemplateUsed('sysadmin/sys_inst_info_admins.html')
+ assert resp.context['inst'] == self.inst
+ assert len(resp.context['users']) == 2
diff --git a/tests/seahub/views/sysadmin/test_sys_inst_info_user.py b/tests/seahub/views/sysadmin/test_sys_inst_info_user.py
new file mode 100644
index 0000000000..2260323185
--- /dev/null
+++ b/tests/seahub/views/sysadmin/test_sys_inst_info_user.py
@@ -0,0 +1,29 @@
+from django.core.urlresolvers import reverse
+
+from seahub.institutions.models import Institution
+from seahub.profile.models import Profile
+from seahub.test_utils import BaseTestCase
+
+class SysInstInfoUserTest(BaseTestCase):
+ def setUp(self):
+ self.login_as(self.admin)
+
+ self.inst = Institution.objects.create(name='inst_test')
+ self.url = reverse('sys_inst_info_users', args=[self.inst.pk])
+
+ assert len(Profile.objects.all()) == 0
+ p = Profile.objects.add_or_update(self.user.username, '')
+ p.institution = self.inst.name
+ p.save()
+
+ p = Profile.objects.add_or_update(self.admin.username, '')
+ p.institution = self.inst.name
+ p.save()
+ assert len(Profile.objects.all()) == 2
+
+ def test_can_list(self):
+ resp = self.client.get(self.url)
+
+ self.assertTemplateUsed('sysadmin/sys_inst_info_users.html')
+ assert resp.context['inst'] == self.inst
+ assert len(resp.context['users']) == 2
diff --git a/tests/seahub/views/sysadmin/test_sys_inst_search_user.py b/tests/seahub/views/sysadmin/test_sys_inst_search_user.py
new file mode 100644
index 0000000000..47e4d5c111
--- /dev/null
+++ b/tests/seahub/views/sysadmin/test_sys_inst_search_user.py
@@ -0,0 +1,31 @@
+from django.core.urlresolvers import reverse
+
+from seahub.institutions.models import Institution
+from seahub.profile.models import Profile
+from seahub.test_utils import BaseTestCase
+
+
+class SysInstSearchUser(BaseTestCase):
+ def setUp(self):
+ self.inst = Institution.objects.create(name='test_inst')
+
+ assert len(Profile.objects.all()) == 0
+ p = Profile.objects.add_or_update(self.user.username, '')
+ p.institution = self.inst.name
+ p.save()
+
+ p = Profile.objects.add_or_update(self.admin.username, '')
+ p.institution = self.inst.name
+ p.save()
+ assert len(Profile.objects.all()) == 2
+
+ self.url = reverse('sys_inst_search_user', args=[self.inst.id])
+
+ def test_can_search(self):
+ self.login_as(self.admin)
+
+ resp = self.client.get(self.url + '?q=@')
+ self.assertEqual(200, resp.status_code)
+
+ assert len(resp.context['users']) == 2
+ assert resp.context['q'] == '@'
diff --git a/tests/seahub/views/sysadmin/test_sys_inst_toggle_admin.py b/tests/seahub/views/sysadmin/test_sys_inst_toggle_admin.py
new file mode 100644
index 0000000000..01ae01800b
--- /dev/null
+++ b/tests/seahub/views/sysadmin/test_sys_inst_toggle_admin.py
@@ -0,0 +1,35 @@
+from django.core.urlresolvers import reverse
+from django.http.cookie import parse_cookie
+
+from seahub.institutions.models import Institution, InstitutionAdmin
+from seahub.profile.models import Profile
+from seahub.test_utils import BaseTestCase
+
+class SysInstInfoUserTest(BaseTestCase):
+ def setUp(self):
+ self.login_as(self.admin)
+
+ self.inst = Institution.objects.create(name='inst_test')
+
+ assert len(Profile.objects.all()) == 0
+ p = Profile.objects.add_or_update(self.user.username, '')
+ p.institution = self.inst.name
+ p.save()
+ assert len(Profile.objects.all()) == 1
+
+ self.url = reverse('sys_inst_toggle_admin', args=[self.inst.pk,
+ self.user.username])
+
+ def test_can_set_and_revoke_admin(self):
+ assert len(InstitutionAdmin.objects.filter(institution=self.inst)) == 0
+ resp = self.client.post(self.url)
+ self.assertEqual(302, resp.status_code)
+ assert 'Success' in parse_cookie(resp.cookies)['messages']
+
+ assert len(InstitutionAdmin.objects.filter(institution=self.inst)) == 1
+
+ resp = self.client.post(self.url)
+ self.assertEqual(302, resp.status_code)
+ assert 'Success' in parse_cookie(resp.cookies)['messages']
+
+ assert len(InstitutionAdmin.objects.filter(institution=self.inst)) == 0
|