diff --git a/apps/assets/views.py b/apps/assets/views.py index 92d6b53f1..e9cf23763 100644 --- a/apps/assets/views.py +++ b/apps/assets/views.py @@ -358,7 +358,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi self.object.name, )) - return self.success_message + return success_message class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): diff --git a/apps/perms/models.py b/apps/perms/models.py index ac0257af4..c875dfe73 100644 --- a/apps/perms/models.py +++ b/apps/perms/models.py @@ -11,12 +11,18 @@ from common.utils import date_expired_default, combine_seq class AssetPermission(models.Model): - name = models.CharField(max_length=128, verbose_name=_('Name')) + PRIVATE_FOR_CHOICE = ( + ('N', 'None'), + ('U', 'user'), + ('G', 'user group'), + ) + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) users = models.ManyToManyField(User, related_name='asset_permissions', blank=True) user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True) assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True) asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True) system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions') + private_for = models.CharField(choices=PRIVATE_FOR_CHOICE, max_length=1, default='N', verbose_name=_('Private for')) is_active = models.BooleanField(default=True, verbose_name=_('Active')) date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired')) created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by')) diff --git a/apps/static/css/style.css b/apps/static/css/style.css index fb30bde06..df14bf9aa 100644 --- a/apps/static/css/style.css +++ b/apps/static/css/style.css @@ -1,5 +1,5 @@ -@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700"); -@import url("https://fonts.googleapis.com/css?family=Roboto:400,300,500,700"); +@import url("https://fonts.useso.com/css?family=Open+Sans:300,400,600,700"); +@import url("https://fonts.useso.com/css?family=Roboto:400,300,500,700"); /* * * INSPINIA - Responsive Admin Theme diff --git a/apps/users/forms.py b/apps/users/forms.py index a24565f89..d7e6c9bd4 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -3,10 +3,10 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm from django.utils.translation import gettext_lazy as _ - from captcha.fields import CaptchaField from .models import User, UserGroup +from .hands import AssetPermission class UserLoginForm(AuthenticationForm): @@ -25,12 +25,10 @@ class UserCreateForm(forms.ModelForm): 'username', 'name', 'email', 'groups', 'wechat', 'phone', 'enable_otp', 'role', 'date_expired', 'comment', ] - help_texts = { 'username': '* required', 'email': '* required', } - widgets = { 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}), } @@ -44,13 +42,11 @@ class UserUpdateForm(forms.ModelForm): 'name', 'email', 'groups', 'wechat', 'phone', 'enable_otp', 'role', 'date_expired', 'comment', ] - help_texts = { 'username': '* required', 'email': '* required', 'groups': '* required' } - widgets = { 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}), } @@ -60,11 +56,9 @@ class UserGroupForm(forms.ModelForm): class Meta: model = UserGroup - fields = [ 'name', 'comment', ] - help_texts = { 'name': '* required' } @@ -88,3 +82,33 @@ class UserKeyForm(forms.Form): if not checked: raise forms.ValidationError(_('Not a valid ssh private key.')) return ssh_pk + + +class UserPrivateAssetPermissionForm(forms.ModelForm): + + def save(self, commit=True): + self.instance = super(UserPrivateAssetPermissionForm, self).save(commit=commit) + self.instance.users = [self.user] + self.instance.name = '_Private for %s %s' % (self.user.username, ) + self.instance.save() + return self.instance + + def clean_private_for(self): + return 'U' + + class Meta: + model = AssetPermission + fields = [ + 'assets', 'asset_groups', 'system_users', 'private_for', 'name', + ] + widgets = { + 'assets': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select assets')}), + 'asset_groups': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset groups')}), + 'system_users': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select system users')}), + } + + + diff --git a/apps/users/hands.py b/apps/users/hands.py index e87060ecd..38d211df4 100644 --- a/apps/users/hands.py +++ b/apps/users/hands.py @@ -10,5 +10,7 @@ :license: GPL v2, see LICENSE for more details. """ +from perms.models import AssetPermission + diff --git a/apps/users/templates/users/user_asset_permission.html b/apps/users/templates/users/user_asset_permission.html new file mode 100644 index 000000000..747b63c7f --- /dev/null +++ b/apps/users/templates/users/user_asset_permission.html @@ -0,0 +1,179 @@ +{% extends 'base.html' %} +{% load common_tags %} +{% load users_tags %} +{% load bootstrap %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'Asset permission of ' %} {{ user.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + {% for asset_permission in object_list %} + + + + + + + + + + + + {% endfor %} + +
{% trans 'Name' %}{% trans 'User ' %}{% trans 'User group ' %}{% trans 'Asset ' %}{% trans 'Asset group ' %}{% trans 'System user ' %} + {% trans 'Is valid' %} +
+ + {{ asset_permission.name }} + + {{ asset_permission.users.count}}{{ asset_permission.user_groups.count}}{{ asset_permission.assets.count }}{{ asset_permission.asset_groups.count }}{{ asset_permission.system_users.count }} + {% if asset_permission.is_valid %} + + {% else %} + + {% endif %} + + +
+
+ {% include '_pagination.html' %} +
+
+
+
+
+
+
+ {% trans 'Quick create permission for user' %} +
+
+
+ + + {% csrf_token %} + + + + + + + + + + + + + +
+ {{ form.assets|bootstrap }} +
+ {{ form.asset_groups|bootstrap }} +
+ {{ form.system_users|bootstrap }} +
+ +
+
+
+
+
+
+
+
+
+
+ +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html index 5137fd17f..b4f265802 100644 --- a/apps/users/templates/users/user_detail.html +++ b/apps/users/templates/users/user_detail.html @@ -18,11 +18,13 @@
diff --git a/apps/users/urls.py b/apps/users/urls.py index 5a83c64b1..7a66afabc 100644 --- a/apps/users/urls.py +++ b/apps/users/urls.py @@ -16,6 +16,10 @@ urlpatterns = [ name='reset-password-success'), url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user/(?P[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'), + url(r'^user/(?P[0-9]+)/asset-permission$', views.UserAssetPermissionView.as_view(), + name='user-asset-permission'), + url(r'^user/(?P[0-9]+)/asset-granted', views.UserDetailView.as_view(), name='user-granted-asset'), + url(r'^user/(?P[0-9]+)/login-history', views.UserDetailView.as_view(), name='user-login-history'), url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'), url(r'^user/(?P[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'), diff --git a/apps/users/views.py b/apps/users/views.py index c752bc2eb..bfb3ccf5e 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -2,8 +2,6 @@ from __future__ import unicode_literals -import logging - from django.conf import settings from django.contrib.auth import login as auth_login, logout as auth_logout from django.contrib.auth.mixins import LoginRequiredMixin @@ -20,7 +18,7 @@ from django.views.decorators.csrf import csrf_protect from django.views.decorators.debug import sensitive_post_parameters from django.views.generic.base import TemplateView from django.views.generic.list import ListView -from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView +from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView, SingleObjectMixin, FormMixin from django.views.generic.detail import DetailView from formtools.wizard.views import SessionWizardView @@ -28,10 +26,12 @@ from formtools.wizard.views import SessionWizardView from common.utils import get_object_or_none, get_logger from .models import User, UserGroup -from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm +from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm, \ + UserPrivateAssetPermissionForm from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail + logger = get_logger(__name__) @@ -355,3 +355,43 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): 'phone': user.phone or '' } return super(UserFirstLoginView, self).get_form_initial(step) + + +class UserAssetPermissionView(AdminUserRequiredMixin, FormMixin, SingleObjectMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + template_name = 'users/user_asset_permission.html' + context_object_name = 'user_object' + form_class = UserPrivateAssetPermissionForm + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=User.objects.all()) + return super(UserAssetPermissionView, self).get(request, *args, **kwargs) + + def get_asset_permission_inherit_from_user_group(self): + asset_permissions = set() + user_groups = self.object.groups.all() + + for user_group in user_groups: + for asset_permission in user_group.asset_permissions.all(): + setattr(asset_permission, 'is_inherit_from_user_groups', True) + setattr(asset_permission, 'inherit_from_user_groups', + getattr(asset_permission, b'inherit_from_user_groups', set()).add(user_group)) + asset_permissions.add(asset_permission) + return asset_permissions + + def get_queryset(self): + asset_permissions = set(self.object.asset_permissions.all()) \ + | self.get_asset_permission_inherit_from_user_group() + return list(asset_permissions) + + def get_context_data(self, **kwargs): + context = { + 'app': 'Users', + 'action': 'User asset permissions', + } + kwargs.update(context) + return super(UserAssetPermissionView, self).get_context_data(**kwargs) + + +class UserAssetPermissionCreateView(AdminUserRequiredMixin, CreateView): + pass