mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-05 00:43:53 +00:00
Add quota and quota usage information.
Changed pages: * myhome * user info admin * org personal page * org admin page
This commit is contained in:
8
forms.py
8
forms.py
@@ -215,3 +215,11 @@ class RepoPassowrdForm(forms.Form):
|
|||||||
else:
|
else:
|
||||||
raise forms.ValidationError(u'未知错误')
|
raise forms.ValidationError(u'未知错误')
|
||||||
|
|
||||||
|
class SetUserQuotaForm(forms.Form):
|
||||||
|
"""
|
||||||
|
Form for setting user quota.
|
||||||
|
"""
|
||||||
|
email = forms.CharField(error_messages={'required': '参数错误'})
|
||||||
|
quota = forms.IntegerField(min_value=0,
|
||||||
|
error_messages={'required': '容量不能为空',
|
||||||
|
'min_value': '容量不能小于0'})
|
||||||
|
@@ -3,18 +3,33 @@
|
|||||||
|
|
||||||
{% block nav_useradmin_class %}class="cur"{% endblock %}
|
{% block nav_useradmin_class %}class="cur"{% endblock %}
|
||||||
|
|
||||||
|
{% block left_panel %}
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<h3 class="info-item-top">团体已用总空间</h3>
|
||||||
|
<p class="info-item-bottom">{{ org_quota_usage|filesizeformat }} {% if org_quota > 0 %} / {{ org_quota|filesizeformat }} {% endif %}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block right_panel %}
|
{% block right_panel %}
|
||||||
<h3>所有用户</h3>
|
<h3>所有成员</h3>
|
||||||
<button id="org-user-add">添加用户</button>
|
<button id="org-user-add">添加成员</button>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="80%">邮箱</th>
|
<th width="60%">邮箱</th>
|
||||||
|
<th width="20%">已用空间</th>
|
||||||
<th width="20%">操作</th>
|
<th width="20%">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{% url 'user_profile' user.email %}" target="_blank">{{ user.props.email }}</a></td>
|
<td><a href="{% url 'user_profile' user.email %}" target="_blank">{{ user.props.email }}</a></td>
|
||||||
|
<td>
|
||||||
|
{% if user.quota_usage >= 0 %}
|
||||||
|
{{ user.quota_usage|filesizeformat }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if not user.is_self %}
|
{% if not user.is_self %}
|
||||||
<a href="#" class="remove-user-btn op" data="{% url 'org_user_remove' request.user.org.url_prefix user.email %}">删除</a>
|
<a href="#" class="remove-user-btn op" data="{% url 'org_user_remove' request.user.org.url_prefix user.email %}">删除</a>
|
@@ -21,6 +21,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="info-item">
|
||||||
|
<h3 class="info-item-top">我已用的团体空间</h3>
|
||||||
|
<p class="info-item-bottom">{{ quota_usage|filesizeformat }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 我的群组 -->
|
<!-- 我的群组 -->
|
||||||
{% include "snippets/my_groups.html" %}
|
{% include "snippets/my_groups.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -27,7 +27,7 @@ urlpatterns = patterns('',
|
|||||||
|
|
||||||
### Org admin ###
|
### Org admin ###
|
||||||
url(r'^(?P<url_prefix>[^/]+)/seafadmin/$', org_seafadmin, name='org_seafadmin'),
|
url(r'^(?P<url_prefix>[^/]+)/seafadmin/$', org_seafadmin, name='org_seafadmin'),
|
||||||
url(r'^(?P<url_prefix>[^/]+)/useradmin/$', org_useradmin, name='org_useradmin'),
|
url(r'^(?P<url_prefix>[^/]+)/orgadmin/$', org_admin, name='org_admin'),
|
||||||
url(r'^(?P<url_prefix>[^/]+)/useradmin/remove/(?P<user>[^/]+)/$', org_user_remove, name='org_user_remove'),
|
url(r'^(?P<url_prefix>[^/]+)/useradmin/remove/(?P<user>[^/]+)/$', org_user_remove, name='org_user_remove'),
|
||||||
url(r'^(?P<url_prefix>[^/]+)/groupadmin/$', org_group_admin, name='org_groupadmin'),
|
url(r'^(?P<url_prefix>[^/]+)/groupadmin/$', org_group_admin, name='org_groupadmin'),
|
||||||
url(r'^(?P<url_prefix>[^/]+)/group/remove/(?P<group_id>[\d]+)/$', org_group_remove, name='org_group_remove'),
|
url(r'^(?P<url_prefix>[^/]+)/group/remove/(?P<group_id>[\d]+)/$', org_group_remove, name='org_group_remove'),
|
||||||
|
@@ -139,6 +139,8 @@ def org_personal(request, url_prefix):
|
|||||||
events = get_org_user_events(org.org_id, user)
|
events = get_org_user_events(org.org_id, user)
|
||||||
else:
|
else:
|
||||||
events = None
|
events = None
|
||||||
|
|
||||||
|
quota_usage = seafserv_threaded_rpc.get_org_user_quota_usage(org.org_id, user)
|
||||||
|
|
||||||
return render_to_response('organizations/personal.html', {
|
return render_to_response('organizations/personal.html', {
|
||||||
'owned_repos': owned_repos,
|
'owned_repos': owned_repos,
|
||||||
@@ -151,6 +153,7 @@ def org_personal(request, url_prefix):
|
|||||||
'allow_public_share': True,
|
'allow_public_share': True,
|
||||||
'nickname': nickname,
|
'nickname': nickname,
|
||||||
'events': events,
|
'events': events,
|
||||||
|
'quota_usage': quota_usage,
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -281,7 +284,7 @@ def send_org_user_add_mail(request, email, password, org_name):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@org_staff_required
|
@org_staff_required
|
||||||
def org_useradmin(request, url_prefix):
|
def org_admin(request, url_prefix):
|
||||||
"""
|
"""
|
||||||
List and add org users.
|
List and add org users.
|
||||||
"""
|
"""
|
||||||
@@ -333,17 +336,28 @@ def org_useradmin(request, url_prefix):
|
|||||||
page_next = True
|
page_next = True
|
||||||
else:
|
else:
|
||||||
page_next = False
|
page_next = False
|
||||||
|
|
||||||
|
org = get_user_current_org(request.user.username, url_prefix)
|
||||||
|
if not org:
|
||||||
|
return HttpResponseRedirect(reverse(myhome))
|
||||||
|
|
||||||
users = users_plus_one[:per_page]
|
users = users_plus_one[:per_page]
|
||||||
for user in users:
|
for user in users:
|
||||||
if user.props.id == request.user.id:
|
if user.props.id == request.user.id:
|
||||||
user.is_self = True
|
user.is_self = True
|
||||||
|
try:
|
||||||
|
user.quota_usage = seafserv_threaded_rpc.get_org_user_quota_usage(org.org_id, user.email)
|
||||||
|
except:
|
||||||
|
user.quota_usage = -1
|
||||||
|
|
||||||
# My contacts
|
# My contacts
|
||||||
contacts = Contact.objects.filter(user_email=request.user.username)
|
contacts = Contact.objects.filter(user_email=request.user.username)
|
||||||
|
|
||||||
|
org_quota_usage = seafserv_threaded_rpc.get_org_quota_usage(org.org_id)
|
||||||
|
org_quota = seafserv_threaded_rpc.get_org_quota(org.org_id)
|
||||||
|
|
||||||
return render_to_response(
|
return render_to_response(
|
||||||
'organizations/org_useradmin.html', {
|
'organizations/org_admin.html', {
|
||||||
'users': users,
|
'users': users,
|
||||||
'contacts': contacts,
|
'contacts': contacts,
|
||||||
'current_page': current_page,
|
'current_page': current_page,
|
||||||
@@ -351,6 +365,8 @@ def org_useradmin(request, url_prefix):
|
|||||||
'next_page': current_page+1,
|
'next_page': current_page+1,
|
||||||
'per_page': per_page,
|
'per_page': per_page,
|
||||||
'page_next': page_next,
|
'page_next': page_next,
|
||||||
|
'org_quota_usage': org_quota_usage,
|
||||||
|
'org_quota': org_quota,
|
||||||
},
|
},
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if org.is_staff %}
|
{% if org.is_staff %}
|
||||||
<a href="{% url 'org_useradmin' org.url_prefix %}"{% block top_bar_org_manager_class %}{% endblock %}>管理员工作台</a>
|
<a href="{% url 'org_admin' org.url_prefix %}"{% block top_bar_org_manager_class %}{% endblock %}>管理员工作台</a>
|
||||||
<a href="{% url 'org_personal' org.url_prefix %}"{% block top_bar_org_myaccount_class %}{% endblock %}>个人工作台</a>
|
<a href="{% url 'org_personal' org.url_prefix %}"{% block top_bar_org_myaccount_class %}{% endblock %}>个人工作台</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<h3 class="info-item-top">已用空间</h3>
|
<h3 class="info-item-top">已用空间</h3>
|
||||||
<p class="info-item-bottom">{{ quota_usage|filesizeformat }} {% if cloud_mode %}/ 2 GB {% endif %}</p>
|
<p class="info-item-bottom">{{ quota_usage|filesizeformat }} {% if quota > 0 %}/ {{ quota|filesizeformat }} {% endif %}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 我的群组 -->
|
<!-- 我的群组 -->
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
{% if request.user.org.is_staff %}
|
{% if request.user.org.is_staff %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url org_useradmin request.user.org.url_prefix %}" {% block nav_useradmin_class %}{% endblock %}>用户管理</a>
|
<a href="{% url org_admin request.user.org.url_prefix %}" {% block nav_useradmin_class %}{% endblock %}>团体概况</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url org_seafadmin request.user.org.url_prefix %}" {% block nav_seafadmin_class %}{% endblock %}>资料库管理</a>
|
<a href="{% url org_seafadmin request.user.org.url_prefix %}" {% block nav_seafadmin_class %}{% endblock %}>资料库管理</a>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
{% block nav_orgadmin_class %}class="cur"{% endblock %}
|
{% block nav_orgadmin_class %}class="cur"{% endblock %}
|
||||||
|
|
||||||
{% block right_panel %}
|
{% block right_panel %}
|
||||||
<h3>所有企业</h3>
|
<h3>所有团体</h3>
|
||||||
{% if orgs %}
|
{% if orgs %}
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
addConfirmTo($('.org-remove-btn'), '确定要删除该企业?');
|
addConfirmTo($('.org-remove-btn'), '确定要删除该团体?');
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
{% extends "admin_base.html" %}
|
{% extends "admin_base.html" %}
|
||||||
|
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
{% block nav_useradmin_class %}class="cur"{% endblock %}
|
{% block nav_useradmin_class %}class="cur"{% endblock %}
|
||||||
{% block left_panel %}
|
{% block left_panel %}
|
||||||
<!--
|
<!--
|
||||||
@@ -7,8 +9,13 @@
|
|||||||
<li><a href="{{ SITE_ROOT }}useradmin/add/">添加用户</a></li>
|
<li><a href="{{ SITE_ROOT }}useradmin/add/">添加用户</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
-->
|
-->
|
||||||
<h3>已用空间</h3>
|
<div class="info-item">
|
||||||
<p>{{ quota_usage|filesizeformat }} / 2 GB</p>
|
<div class="info-item-top">
|
||||||
|
<h3 class="inbl">已用空间</h3>
|
||||||
|
<a href="#" class="set-quota op">设置容量</a>
|
||||||
|
</div>
|
||||||
|
<p class="info-item-bottom">{{ quota_usage|filesizeformat }} {% if quota > 0 %} / {{ quota|filesizeformat }} {% endif %}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -29,7 +36,7 @@
|
|||||||
<td><a href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/">{{ repo.props.name }}</a></td>
|
<td><a href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/">{{ repo.props.name }}</a></td>
|
||||||
<td>{{ repo.props.desc }}</td>
|
<td>{{ repo.props.desc }}</td>
|
||||||
<td>
|
<td>
|
||||||
<button data="{{ SITE_ROOT }}repo/remove/{{ repo.props.id }}/?next={{ request.path }}" class="repo-delete-btn">删除</button>
|
<a href="#" data="{{ SITE_ROOT }}repo/remove/{{ repo.props.id }}/?next={{ request.path }}" class="remove-user-repo op">删除</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -61,33 +68,59 @@
|
|||||||
<p>暂无</p>
|
<p>暂无</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!--
|
<form id="set-quota-form" method="post" class="hide">{% csrf_token %}
|
||||||
<h3>{{ email }} 的计算机</h3>
|
<label>设置该用户的存储容量上限</label><br />
|
||||||
<table class="user-list">
|
<input type="hidden" name="email" value="{{ email }}" />
|
||||||
<tr>
|
<input type="text" name="quota" /> MB <br />
|
||||||
<th width="60%">计算机名</th>
|
<p class="tip">Tip: 设置为0表示重置为默认上限</p>
|
||||||
<th width="20%">角色</th>
|
<p class="error hide"></p>
|
||||||
<th width="20%">状态</th>
|
<input type="submit" value="提交" class="submit" />
|
||||||
</tr>
|
</form>
|
||||||
|
|
||||||
{% for username, roles in user_dict.items %}
|
{% endblock %}
|
||||||
<tr>
|
|
||||||
{% if username %}
|
|
||||||
<td>{{ username }}</td>
|
{% block extra_script %}
|
||||||
{% else %}
|
<script type="text/javascript">
|
||||||
<td>未知</td>
|
|
||||||
{% endif %}
|
$('.set-quota').click(function() {
|
||||||
|
$("#set-quota-form").modal({appendTo: "#main"});
|
||||||
{% if roles %}
|
return false;
|
||||||
<td>{{ roles }}</td>
|
});
|
||||||
<td>已验证</td>
|
|
||||||
{% else %}
|
$('#set-quota-form .submit').click(function() {
|
||||||
<td>无</td>
|
var self = $(this);
|
||||||
<td>未验证</td>
|
self.attr('disabled', 'disabled');
|
||||||
{% endif %}
|
$.ajax({
|
||||||
|
url: '{% url 'views.user_info' email %}',
|
||||||
</tr>
|
type: 'POST',
|
||||||
{% endfor %}
|
dataType: 'json',
|
||||||
</table>
|
cache: 'false',
|
||||||
-->
|
beforeSend: prepareCSRFToken,
|
||||||
|
data: {
|
||||||
|
'email': $('#set-quota-form input[name="email"]').val(),
|
||||||
|
'quota': $('#set-quota-form input[name="quota"]').val()
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
if (data['success']) {
|
||||||
|
location.reload(true);
|
||||||
|
} else {
|
||||||
|
apply_form_error('set-quota-form', data['error']);
|
||||||
|
self.removeAttr('disabled');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(data, textStatus, jqXHR) {
|
||||||
|
var errors = $.parseJSON(data.responseText);
|
||||||
|
$.each(errors, function(index, value) {
|
||||||
|
apply_form_error('set-quota-form', value[0]);
|
||||||
|
});
|
||||||
|
self.removeAttr('disabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
addConfirmTo($('.remove-user-repo'), '确定要删除该资料库?');
|
||||||
|
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
29
views.py
29
views.py
@@ -60,7 +60,7 @@ from notifications.models import UserNotification
|
|||||||
from profile.models import Profile
|
from profile.models import Profile
|
||||||
from forms import AddUserForm, FileLinkShareForm, RepoCreateForm, \
|
from forms import AddUserForm, FileLinkShareForm, RepoCreateForm, \
|
||||||
RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm, \
|
RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm, \
|
||||||
RepoPassowrdForm, SharedRepoCreateForm
|
RepoPassowrdForm, SharedRepoCreateForm, SetUserQuotaForm
|
||||||
from utils import render_permission_error, render_error, list_to_string, \
|
from utils import render_permission_error, render_error, list_to_string, \
|
||||||
get_httpserver_root, get_ccnetapplet_root, gen_token, \
|
get_httpserver_root, get_ccnetapplet_root, gen_token, \
|
||||||
calculate_repo_last_modify, valid_previewed_file, \
|
calculate_repo_last_modify, valid_previewed_file, \
|
||||||
@@ -858,6 +858,7 @@ def myhome(request):
|
|||||||
quota_usage = 0
|
quota_usage = 0
|
||||||
|
|
||||||
email = request.user.username
|
email = request.user.username
|
||||||
|
quota = seafserv_threaded_rpc.get_user_quota(email)
|
||||||
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
|
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
|
||||||
|
|
||||||
# Personal repos that I own
|
# Personal repos that I own
|
||||||
@@ -921,6 +922,7 @@ def myhome(request):
|
|||||||
return render_to_response('myhome.html', {
|
return render_to_response('myhome.html', {
|
||||||
"nickname": nickname,
|
"nickname": nickname,
|
||||||
"owned_repos": owned_repos,
|
"owned_repos": owned_repos,
|
||||||
|
"quota": quota,
|
||||||
"quota_usage": quota_usage,
|
"quota_usage": quota_usage,
|
||||||
"in_repos": in_repos,
|
"in_repos": in_repos,
|
||||||
"contacts": contacts,
|
"contacts": contacts,
|
||||||
@@ -1825,10 +1827,32 @@ def sys_useradmin(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@sys_staff_required
|
@sys_staff_required
|
||||||
def user_info(request, email):
|
def user_info(request, email):
|
||||||
|
if request.method == 'POST':
|
||||||
|
result = {}
|
||||||
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
f = SetUserQuotaForm(request.POST)
|
||||||
|
if f.is_valid():
|
||||||
|
email = f.cleaned_data['email']
|
||||||
|
quota_mb = f.cleaned_data['quota']
|
||||||
|
quota = quota_mb * (1 << 20)
|
||||||
|
|
||||||
|
try:
|
||||||
|
seafserv_threaded_rpc.set_user_quota(email, quota)
|
||||||
|
except:
|
||||||
|
result['error'] = u'内部错误,设置失败'
|
||||||
|
return HttpResponse(json.dumps(result), content_type=content_type)
|
||||||
|
|
||||||
|
result['success'] = True
|
||||||
|
return HttpResponse(json.dumps(result), content_type=content_type)
|
||||||
|
else:
|
||||||
|
result['error'] = str(f.errors.values()[0])
|
||||||
|
return HttpResponse(json.dumps(result), content_type=content_type)
|
||||||
|
|
||||||
owned_repos = []
|
owned_repos = []
|
||||||
quota_usage = 0
|
|
||||||
|
|
||||||
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
|
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
|
||||||
|
quota = seafserv_threaded_rpc.get_user_quota(email)
|
||||||
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
|
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
|
||||||
|
|
||||||
# Repos that are share to user
|
# Repos that are share to user
|
||||||
@@ -1838,6 +1862,7 @@ def user_info(request, email):
|
|||||||
return render_to_response(
|
return render_to_response(
|
||||||
'userinfo.html', {
|
'userinfo.html', {
|
||||||
'owned_repos': owned_repos,
|
'owned_repos': owned_repos,
|
||||||
|
'quota': quota,
|
||||||
'quota_usage': quota_usage,
|
'quota_usage': quota_usage,
|
||||||
"in_repos": in_repos,
|
"in_repos": in_repos,
|
||||||
'email': email
|
'email': email
|
||||||
|
Reference in New Issue
Block a user