feature: implements user profile quotas update
This commit is contained in:
parent
a960c9f99c
commit
0e08a98987
8 changed files with 139 additions and 4 deletions
|
|
@ -961,6 +961,27 @@ def admin_routes(config):
|
|||
request_method="POST",
|
||||
)
|
||||
|
||||
# user quotas
|
||||
config.add_route(name="edit_user_quotas", pattern=r"/users/{user_id:\d+}/edit/quotas", user_route=True)
|
||||
config.add_view(
|
||||
UsersView,
|
||||
attr="user_quotas",
|
||||
route_name="edit_user_quotas",
|
||||
request_method="GET",
|
||||
renderer="rhodecode:templates/admin/users/user_edit.mako",
|
||||
)
|
||||
|
||||
config.add_route(
|
||||
name="edit_user_quotas_update", pattern=r"/users/{user_id:\d+}/edit/quotas/update", user_route=True
|
||||
)
|
||||
config.add_view(
|
||||
UsersView,
|
||||
attr="user_quotas_update",
|
||||
route_name="edit_user_quotas_update",
|
||||
request_method="POST",
|
||||
renderer="rhodecode:templates/admin/users/user_edit.mako",
|
||||
)
|
||||
|
||||
# user audit logs
|
||||
config.add_route(name="edit_user_audit_logs", pattern=r"/users/{user_id:\d+}/edit/audit", user_route=True)
|
||||
config.add_view(
|
||||
|
|
|
|||
|
|
@ -55,8 +55,10 @@ from rhodecode.model.forms import (
|
|||
UserPermissionsForm,
|
||||
UserExtraEmailForm,
|
||||
UserExtraIpForm,
|
||||
UserQuotasUpdateForm,
|
||||
)
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.quota_model import UserQuotaModel
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.ssh_key import SshKeyModel
|
||||
from rhodecode.model.user import UserModel
|
||||
|
|
@ -283,6 +285,9 @@ class UsersView(UserAppView):
|
|||
("zh", "Chinese (zh)"),
|
||||
]
|
||||
|
||||
app_settings = c.rc_config
|
||||
c.quotas_enabled = app_settings.get("rhodecode_user_quotas_enabled", UserQuotaModel.DEFAULT_QUOTAS_ENABLED)
|
||||
|
||||
c.allowed_extern_types = [(x.uid, x.get_display_name()) for x in self.get_auth_plugins()]
|
||||
perms = req.registry.settings.get("available_permissions")
|
||||
if not perms:
|
||||
|
|
@ -1122,6 +1127,43 @@ class UsersView(UserAppView):
|
|||
|
||||
return HTTPFound(h.route_path("edit_user_groups_management", user_id=user_id))
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator("hg.admin")
|
||||
def user_quotas(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
c.user = self.db_user
|
||||
|
||||
quota_model = UserQuotaModel(c.user)
|
||||
|
||||
c.active = "user_quotas"
|
||||
c.user_repo_quotas = quota_model.formatted_user_max_repository_count_allowance()
|
||||
c.user_repo_count = quota_model.user_repositories_count
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator("hg.admin")
|
||||
def user_quotas_update(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
c.user = self.db_user
|
||||
|
||||
c.active = "user_quotas"
|
||||
|
||||
user_form = UserQuotasUpdateForm()()
|
||||
try:
|
||||
quota_model = UserQuotaModel(c.user)
|
||||
form_result = user_form.to_python(dict(self.request.POST))
|
||||
quota_model.user_max_repository_count_allowance = form_result["user_repo_quotas"]
|
||||
h.flash(_("Updated user '%s' repository quota") % c.user.username, category="success")
|
||||
except Exception as e:
|
||||
log.exception("Exception updating user quotas, %s", e)
|
||||
h.flash(
|
||||
_("Exception updating user quotas of user %s") % self.request.POST.get("username"), category="error"
|
||||
)
|
||||
raise HTTPFound(h.route_path("edit_user_quotas", user_id=c.user.user_id))
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator("hg.admin")
|
||||
def user_audit_logs(self):
|
||||
|
|
|
|||
|
|
@ -715,3 +715,11 @@ def UserQuotasSettingsForm():
|
|||
rhodecode_global_user_repo_quotas = v.Int(strip=True, required=True)
|
||||
|
||||
return _UserQuotasSettingsForm
|
||||
|
||||
|
||||
def UserQuotasUpdateForm():
|
||||
class _UserQuotasUpdateForm(formencode.Schema):
|
||||
allow_extra_fields = True
|
||||
user_repo_quotas = v.Int(strip=True, required=True)
|
||||
|
||||
return _UserQuotasUpdateForm
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ log = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class UserQuotaModel:
|
||||
UNLIMITED = float("inf")
|
||||
UNLIMITED = -1
|
||||
DEFAULT_REPO_QUOTA = 5
|
||||
DEFAULT_QUOTAS_ENABLED = False
|
||||
|
||||
|
|
@ -44,18 +44,37 @@ class UserQuotaModel:
|
|||
max_repository_count_allowance=repo_count_allowance,
|
||||
)
|
||||
|
||||
def user_repositories_count(self):
|
||||
@property
|
||||
def user_repositories_count(self) -> int:
|
||||
return Session().scalar(
|
||||
select(func.count()).select_from(Repository).where(Repository.user_id == self.user.user_id)
|
||||
)
|
||||
|
||||
@property
|
||||
def user_max_repository_count_allowance(self) -> int:
|
||||
quotas = self.user.get_quotas()
|
||||
return quotas.get("max_repository_count_allowance")
|
||||
|
||||
@user_max_repository_count_allowance.setter
|
||||
def user_max_repository_count_allowance(self, new_value: int):
|
||||
self.user.update_quotas(max_repository_count_allowance=new_value)
|
||||
|
||||
def formatted_user_max_repository_count_allowance(self) -> str:
|
||||
max_repos = self.user_max_repository_count_allowance
|
||||
if max_repos is self.UNLIMITED:
|
||||
return "Unlimited"
|
||||
return str(max_repos)
|
||||
|
||||
def is_repo_creation_allowed(self):
|
||||
if not self.enabled:
|
||||
return True
|
||||
|
||||
if self._user_quotas_valid():
|
||||
u_quotas = self.user.get_quotas()
|
||||
return u_quotas.get("max_repository_count_allowance") > self.user_repositories_count()
|
||||
if self.user_max_repository_count_allowance is self.UNLIMITED:
|
||||
# since DB can't save float('inf'), we need to use a special case
|
||||
return True
|
||||
|
||||
return self.user_max_repository_count_allowance > self.user_repositories_count
|
||||
|
||||
log.warning("User quotas not present, re-initialize quotas.")
|
||||
self.init_quotas()
|
||||
|
|
|
|||
|
|
@ -412,6 +412,13 @@ class UserModel(BaseModel):
|
|||
|
||||
self.sa.add(new_user)
|
||||
|
||||
# TODO: fix tests and uncomment this, because tests launching pyramid app, this part fails during
|
||||
# fixture setup, in normal app this works as intended
|
||||
# user quotas will be lazily initialized anyway, but this is workaround
|
||||
# if new_user.is_new_user:
|
||||
# qm = UserQuotaModel(new_user)
|
||||
# qm.init_quotas()
|
||||
|
||||
if not edit and create_repo_group:
|
||||
RepoGroupModel().create_personal_repo_group(new_user, commit_early=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
</div>
|
||||
<div class="input">
|
||||
${h.text('rhodecode_global_user_repo_quotas', c.global_user_repo_quotas)}
|
||||
<p class="help-block pre-formatting">${_('If you want to set an unlimited quota, enter -1.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@
|
|||
<li class="${h.is_active('groups', c.active)}"><a href="${h.route_path('edit_user_groups_management', user_id=c.user.user_id)}">${_('User Groups Management')}</a></li>
|
||||
<li class="${h.is_active('audit', c.active)}"><a href="${h.route_path('edit_user_audit_logs', user_id=c.user.user_id)}">${_('Audit logs')}</a></li>
|
||||
<li class="${h.is_active('caches', c.active)}"><a href="${h.route_path('edit_user_caches', user_id=c.user.user_id)}">${_('Caches')}</a></li>
|
||||
%if c.quotas_enabled:
|
||||
<li class="${h.is_active('user_quotas', c.active)}"><a href="${h.route_path('edit_user_quotas', user_id=c.user.user_id)}">${_('User Quotas')}</a></li>
|
||||
%endif
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
34
rhodecode/templates/admin/users/user_edit_user_quotas.mako
Normal file
34
rhodecode/templates/admin/users/user_edit_user_quotas.mako
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('User Quotas')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${h.secure_form(h.route_path('edit_user_quotas_update', user_id=c.user.user_id), id='user_quotas_form', request=request)}
|
||||
<div class="fields">
|
||||
|
||||
<div class="field" id="user_repo_count">
|
||||
<div class="label label">
|
||||
<label for="user_repo_count">${_('Current Repository Count')}</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
${h.text('user_repo_count', c.user_repo_count, readonly=True, class_='no-border')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" id="user_repo_quotas">
|
||||
<div class="label label">
|
||||
<label for="user_repo_quotas">${_('Maximum repositories')}</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
${h.text('user_repo_quotas', c.user_repo_quotas)}
|
||||
<p class="help-block pre-formatting">${_('If you want to set an unlimited quota, enter -1.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
${h.submit('save',_('Save'),class_="btn")}
|
||||
</div>
|
||||
${h.end_form()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue