Commit a2376d3a authored by 八千流's avatar 八千流 Committed by 老广

超级管理员可创建超级审计员并可设置审计员为组织审计员 (#3141)

* [Update] 超级管理员可创建超级审计员并可设置审计员为组织审计员

* [Update] 修改小问题

* [Update] 修改普通用户角色可以是组织审计员

* [Update] 更改组织审计员切换组织问题

* [Update] 修改小问题

* [Update] 普通用户是组织审计员的页面左侧栏显示

* [Update] 修改删除权限问题和组织显示问题

* [Update] 优化逻辑

* [Update] 优化类名

* [Update] 修改小问题

* [Update] 优化逻辑

* [Update] 优化切换到某一个组织逻辑

* [Update] 修改用户详情页的 删除/更新 按钮是否可点击

* [Update] 优化代码

* [Update] 组织管理列表增加审计员显示

* [Update] 优化代码细节

* [Update] 优化权限类逻辑

* [Update] 优化导航菜单控制

* [Update] 优化页面控制逻辑

* [Update] 修改变量名错误问题

* [Update] 修改页面上的小问题

* [Update] 审计员或组织审计员能够更新个人部分信息

* [Update] 用户名为admin的用户不能被删除

* [Update] 不同用户在不同组织下扮演不同角色的权限不同,为了避免切换组织时出现403,重定向到index

* [Update] 一个用户在同一个组织既是管理员又是审计员,隐藏个人信息模块,仅当是审计员,在当前组织显示个人信息模块

* [Update] 修改方法命名

* [Update] 优化代码细节

* [Update] 修改命令执行列表方法

* [Update] 优化用户之间操作的权限逻辑;添加 UserModel 的 property 属性;修改 Organization 的 related name 名称;

* [Update] 修改OrgProcessor Anonymous问题

* [Update] 修改用户序列类校验组织和转换raw密码的逻辑
parent 5f23c358
......@@ -3,7 +3,7 @@
from rest_framework import viewsets
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
from .models import FTPLog
from .serializers import FTPLogSerializer
......@@ -11,4 +11,4 @@ from .serializers import FTPLogSerializer
class FTPLogViewSet(viewsets.ModelViewSet):
queryset = FTPLog.objects.all()
serializer_class = FTPLogSerializer
permission_classes = (IsOrgAdminOrAppUser | IsAuditor,)
permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor,)
......@@ -18,8 +18,9 @@ from django.db.models import Q
from audits.utils import get_excel_response, write_content_to_excel
from common.mixins import DatetimeSearchMixin
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor, IsValidUser
from common.permissions import (
PermissionsMixin, IsOrgAdmin, IsValidUser, IsOrgAuditor
)
from orgs.utils import current_org
from ops.views import CommandExecutionListView as UserCommandExecutionListView
from .models import FTPLog, OperateLog, PasswordChangeLog, UserLoginLog
......@@ -47,7 +48,7 @@ class FTPLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
paginate_by = settings.DISPLAY_PER_PAGE
user = asset = system_user = filename = ''
date_from = date_to = None
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get_queryset(self):
self.queryset = super().get_queryset()
......@@ -96,7 +97,7 @@ class OperateLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
user = action = resource_type = ''
date_from = date_to = None
actions_dict = dict(OperateLog.ACTION_CHOICES)
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get_queryset(self):
self.queryset = super().get_queryset()
......@@ -119,7 +120,7 @@ class OperateLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
def get_context_data(self, **kwargs):
context = {
'user_list': current_org.get_org_users(),
'user_list': current_org.get_org_members(),
'actions': self.actions_dict,
'resource_type_list': get_resource_type_list(),
'date_from': self.date_from,
......@@ -139,10 +140,10 @@ class PasswordChangeLogList(PermissionsMixin, DatetimeSearchMixin, ListView):
paginate_by = settings.DISPLAY_PER_PAGE
user = ''
date_from = date_to = None
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get_queryset(self):
users = current_org.get_org_users()
users = current_org.get_org_members()
self.queryset = super().get_queryset().filter(
user__in=[user.__str__() for user in users]
)
......@@ -159,7 +160,7 @@ class PasswordChangeLogList(PermissionsMixin, DatetimeSearchMixin, ListView):
def get_context_data(self, **kwargs):
context = {
'user_list': current_org.get_org_users(),
'user_list': current_org.get_org_members(),
'date_from': self.date_from,
'date_to': self.date_to,
'user': self.user,
......@@ -176,18 +177,18 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
paginate_by = settings.DISPLAY_PER_PAGE
user = keyword = ""
date_to = date_from = None
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
@staticmethod
def get_org_users():
users = current_org.get_org_users().values_list('username', flat=True)
def get_org_members():
users = current_org.get_org_members().values_list('username', flat=True)
return users
def get_queryset(self):
if current_org.is_default():
queryset = super().get_queryset()
else:
users = self.get_org_users()
users = self.get_org_members()
queryset = super().get_queryset().filter(username__in=users)
self.user = self.request.GET.get('user', '')
......@@ -214,7 +215,7 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
'date_to': self.date_to,
'user': self.user,
'keyword': self.keyword,
'user_list': self.get_org_users(),
'user_list': self.get_org_members(),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
......@@ -223,6 +224,10 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
class CommandExecutionListView(UserCommandExecutionListView):
user_id = None
def get_user_list(self):
users = current_org.get_org_members(exclude=('Auditor',))
return users
def get_queryset(self):
queryset = self._get_queryset()
self.user_id = self.request.GET.get('user')
......@@ -233,10 +238,6 @@ class CommandExecutionListView(UserCommandExecutionListView):
queryset = queryset.filter(user__in=org_users)
return queryset
def get_user_list(self):
users = current_org.get_org_users()
return users
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
......
......@@ -4,8 +4,6 @@ import time
from rest_framework import permissions
from django.contrib.auth.mixins import UserPassesTestMixin
from django.shortcuts import redirect
from django.http.response import HttpResponseForbidden
from django.conf import settings
from orgs.utils import current_org
......@@ -27,12 +25,6 @@ class IsAppUser(IsValidUser):
and request.user.is_app
class IsAuditor(IsValidUser):
def has_permission(self, request, view):
return super(IsAuditor, self).has_permission(request, view) \
and request.user.is_auditor
class IsSuperUser(IsValidUser):
def has_permission(self, request, view):
return super(IsSuperUser, self).has_permission(request, view) \
......@@ -45,6 +37,20 @@ class IsSuperUserOrAppUser(IsSuperUser):
or request.user.is_app
class IsSuperAuditor(IsValidUser):
def has_permission(self, request, view):
return super(IsSuperAuditor, self).has_permission(request, view) \
and request.user.is_super_auditor
class IsOrgAuditor(IsValidUser):
def has_permission(self, request, view):
if not current_org:
return False
return super(IsOrgAuditor, self).has_permission(request, view) \
and current_org.can_audit_by(request.user)
class IsOrgAdmin(IsValidUser):
"""Allows access only to superuser"""
......@@ -81,43 +87,6 @@ class IsCurrentUserOrReadOnly(permissions.BasePermission):
return obj == request.user
class LoginRequiredMixin(UserPassesTestMixin):
def test_func(self):
if self.request.user.is_authenticated:
return True
else:
return False
class AdminUserRequiredMixin(UserPassesTestMixin):
def test_func(self):
if not self.request.user.is_authenticated:
return False
elif not current_org.can_admin_by(self.request.user):
self.raise_exception = True
return False
return True
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return super().dispatch(request, *args, **kwargs)
if not current_org:
return redirect('orgs:switch-a-org')
if not current_org.can_admin_by(request.user):
if request.user.is_org_admin:
return redirect('orgs:switch-a-org')
return HttpResponseForbidden()
return super().dispatch(request, *args, **kwargs)
class SuperUserRequiredMixin(UserPassesTestMixin):
def test_func(self):
if self.request.user.is_authenticated and self.request.user.is_superuser:
return True
class WithBootstrapToken(permissions.BasePermission):
def has_permission(self, request, view):
authorization = request.META.get('HTTP_AUTHORIZATION', '')
......@@ -159,14 +128,61 @@ class NeedMFAVerify(permissions.BasePermission):
return False
class CanUpdateDeleteSuperUser(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in ['GET', 'OPTIONS']:
class CanUpdateDeleteUser(permissions.BasePermission):
@staticmethod
def has_delete_object_permission(request, view, obj):
if not request.user.can_admin_current_org:
return False
# 超级管理员 / 组织管理员
if str(request.user.id) == str(obj.id):
return False
# 超级管理员
if request.user.is_superuser:
if obj.is_superuser and obj.username in ['admin']:
return False
return True
# 组织管理员
if obj.is_superuser:
return False
if obj.is_super_auditor:
return False
if obj.is_org_admin:
return False
if len(obj.audit_orgs) > 1:
return False
if len(obj.user_orgs) > 1:
return False
return True
elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
@staticmethod
def has_update_object_permission(request, view, obj):
if not request.user.can_admin_current_org:
return False
elif request.user.is_superuser:
# 超级管理员 / 组织管理员
if str(request.user.id) == str(obj.id):
return True
if hasattr(obj, 'is_superuser') and obj.is_superuser:
# 超级管理员
if request.user.is_superuser:
return True
# 组织管理员
if obj.is_superuser:
return False
if obj.is_super_auditor:
return False
if obj.is_org_admin:
return False
if len(obj.audit_orgs) > 1:
return False
if len(obj.user_orgs) > 1:
return False
return True
def has_object_permission(self, request, view, obj):
if not request.user.can_admin_current_org:
return False
if request.method in ['DELETE']:
return self.has_delete_object_permission(request, view, obj)
if request.method in ['PUT', 'PATCH']:
return self.has_update_object_permission(request, view, obj)
return True
......@@ -34,17 +34,13 @@ class IndexView(PermissionsMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
if request.user.is_auditor:
return super(IndexView, self).dispatch(request, *args, **kwargs)
if not request.user.is_org_admin:
if request.user.is_common_user:
return redirect('assets:user-asset-list')
if not current_org or not current_org.can_admin_by(request.user):
return redirect('orgs:switch-a-org')
return super(IndexView, self).dispatch(request, *args, **kwargs)
@staticmethod
def get_user_count():
return current_org.get_org_users().count()
return current_org.get_org_members().count()
@staticmethod
def get_asset_count():
......@@ -99,7 +95,7 @@ class IndexView(PermissionsMixin, TemplateView):
return self.session_month.values('user').distinct().count()
def get_month_inactive_user_total(self):
count = current_org.get_org_users().count() - self.get_month_active_user_total()
count = current_org.get_org_members().count() - self.get_month_active_user_total()
if count < 0:
count = 0
return count
......@@ -115,7 +111,7 @@ class IndexView(PermissionsMixin, TemplateView):
@staticmethod
def get_user_disabled_total():
return current_org.get_org_users().filter(is_active=False).count()
return current_org.get_org_members().filter(is_active=False).count()
@staticmethod
def get_asset_disabled_total():
......
......@@ -2,7 +2,7 @@
#
from django.views.generic import TemplateView
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
__all__ = ['CeleryTaskLogView']
......@@ -10,7 +10,7 @@ __all__ = ['CeleryTaskLogView']
class CeleryTaskLogView(PermissionsMixin, TemplateView):
template_name = 'ops/celery_task_log.html'
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
......
......@@ -6,7 +6,7 @@ from django.conf import settings
from django.views.generic import ListView, TemplateView
from common.permissions import (
PermissionsMixin, IsOrgAdmin, IsAuditor, IsValidUser
PermissionsMixin, IsOrgAdmin, IsValidUser, IsOrgAuditor
)
from common.mixins import DatetimeSearchMixin
from ..models import CommandExecution
......@@ -25,7 +25,7 @@ class CommandExecutionListView(PermissionsMixin, DatetimeSearchMixin, ListView):
ordering = ('-date_created',)
context_object_name = 'task_list'
keyword = ''
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def _get_queryset(self):
self.keyword = self.request.GET.get('keyword', '')
......
......@@ -33,7 +33,7 @@ class OrgViewSet(BulkModelViewSet):
def get_data_from_model(self, model):
if model == User:
data = model.objects.filter(orgs__id=self.org.id)
data = model.objects.filter(related_user_orgs__id=self.org.id)
else:
data = model.objects.filter(org_id=self.org.id)
return data
......
......@@ -7,9 +7,11 @@ from .models import Organization
def org_processor(request):
context = {
'ADMIN_ORGS': Organization.get_user_admin_orgs(request.user),
# 'ADMIN_ORGS': request.user.admin_orgs,
# 'AUDIT_ORGS': request.user.audit_orgs,
'ADMIN_OR_AUDIT_ORGS': Organization.get_user_admin_or_audit_orgs(request.user),
'CURRENT_ORG': get_org_from_request(request),
'HAS_ORG_PERM': current_org.can_admin_by(request.user),
# 'HAS_ORG_PERM': current_org.can_admin_by(request.user),
}
return context
......@@ -13,14 +13,23 @@ class OrgMiddleware:
def set_permed_org_if_need(request):
if request.path.startswith('/api'):
return
if not (request.user.is_authenticated and request.user.is_org_admin):
if not request.user.is_authenticated:
return
if request.user.is_common_user:
return
org = get_org_from_request(request)
if org.can_admin_by(request.user):
return
admin_orgs = Organization.get_user_admin_orgs(request.user)
if org.can_audit_by(request.user):
return
admin_orgs = request.user.admin_orgs
if admin_orgs:
request.session['oid'] = str(admin_orgs[0].id)
return
audit_orgs = request.user.audit_orgs
if audit_orgs:
request.session['oid'] = str(audit_orgs[0].id)
return
def __call__(self, request):
self.set_permed_org_if_need(request)
......
......@@ -9,8 +9,9 @@ from common.utils import is_uuid
class Organization(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
users = models.ManyToManyField('users.User', related_name='orgs', blank=True)
admins = models.ManyToManyField('users.User', related_name='admin_orgs', blank=True)
users = models.ManyToManyField('users.User', related_name='related_user_orgs', blank=True)
admins = models.ManyToManyField('users.User', related_name='related_admin_orgs', blank=True)
auditors = models.ManyToManyField('users.User', related_name='related_audit_orgs', blank=True)
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
......@@ -70,25 +71,46 @@ class Organization(models.Model):
org = cls.default() if default else None
return org
def get_org_users(self, include_app=False):
def get_org_users(self):
from users.models import User
if self.is_real():
users = self.users.all()
else:
users = User.objects.all()
if not include_app:
users = users.exclude(role=User.ROLE_APP)
return users
return self.users.all()
return User.objects.filter(role=User.ROLE_USER)
def get_org_admins(self):
from users.models import User
if self.is_real():
return self.admins.all()
return []
return User.objects.filter(role=User.ROLE_ADMIN)
def get_org_auditors(self):
from users.models import User
if self.is_real():
return self.auditors.all()
return User.objects.filter(role=User.ROLE_AUDITOR)
def get_org_members(self, exclude=()):
from users.models import User
members = User.objects.none()
if 'Admin' not in exclude:
members |= self.get_org_admins()
if 'User' not in exclude:
members |= self.get_org_users()
if 'Auditor' not in exclude:
members |= self.get_org_auditors()
return members.exclude(role=User.ROLE_APP).distinct()
def can_admin_by(self, user):
if user.is_superuser:
return True
if user in list(self.get_org_admins()):
if self.get_org_admins().filter(id=user.id):
return True
return False
def can_audit_by(self, user):
if user.is_super_auditor:
return True
if self.get_org_auditors().filter(id=user.id):
return True
return False
......@@ -100,13 +122,40 @@ class Organization(models.Model):
admin_orgs = []
if user.is_anonymous:
return admin_orgs
elif user.is_superuser or user.is_auditor:
elif user.is_superuser:
admin_orgs = list(cls.objects.all())
admin_orgs.append(cls.default())
elif user.is_org_admin:
admin_orgs = user.admin_orgs.all()
admin_orgs = user.related_admin_orgs.all()
return admin_orgs
@classmethod
def get_user_user_orgs(self, user):
user_orgs = []
if user.is_anonymous:
return user_orgs
user_orgs = user.related_user_orgs.all()
return user_orgs
@classmethod
def get_user_audit_orgs(cls, user):
audit_orgs = []
if user.is_anonymous:
return audit_orgs
elif user.is_super_auditor:
audit_orgs = list(cls.objects.all())
audit_orgs.append(cls.default())
elif user.is_org_auditor:
audit_orgs = user.related_audit_orgs.all()
return audit_orgs
@classmethod
def get_user_admin_or_audit_orgs(self, user):
admin_orgs = self.get_user_admin_orgs(user)
audit_orgs = self.get_user_audit_orgs(user)
orgs = set(admin_orgs) | set(audit_orgs)
return orgs
@classmethod
def default(cls):
return cls(id=cls.DEFAULT_ID, name=cls.DEFAULT_NAME)
......
......@@ -21,6 +21,7 @@ class OrgSerializer(ModelSerializer):
class OrgReadSerializer(ModelSerializer):
admins = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
auditors = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
users = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
user_groups = serializers.SerializerMethodField()
assets = serializers.SerializerMethodField()
......
......@@ -5,6 +5,7 @@ from django.views.generic import DetailView, View
from .models import Organization
from common.utils import UUID_PATTERN
from orgs.utils import current_org
class SwitchOrgView(DetailView):
......@@ -22,17 +23,28 @@ class SwitchOrgView(DetailView):
return redirect(reverse('index'))
if UUID_PATTERN.search(referer):
return redirect(reverse('index'))
# 组织管理员切换到组织审计员时(403)
if not self.object.get_org_admins().filter(id=request.user.id):
return redirect(reverse('index'))
return redirect(referer)
class SwitchToAOrgView(View):
def get(self, request, *args, **kwargs):
admin_orgs = Organization.get_user_admin_orgs(request.user)
if not admin_orgs:
if request.user.is_common_user:
return HttpResponseForbidden()
admin_orgs = request.user.admin_orgs
audit_orgs = request.user.audit_orgs
default_org = Organization.default()
if admin_orgs:
if default_org in admin_orgs:
redirect_org = default_org
else:
redirect_org = admin_orgs[0]
return redirect(reverse('orgs:org-switch', kwargs={'pk': redirect_org.id}))
if audit_orgs:
if default_org in audit_orgs:
redirect_org = default_org
else:
redirect_org = audit_orgs[0]
return redirect(reverse('orgs:org-switch', kwargs={'pk': redirect_org.id}))
......@@ -39,7 +39,7 @@ class AssetPermissionForm(OrgModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
users_field = self.fields.get('users')
users_field.queryset = current_org.get_org_users()
users_field.queryset = current_org.get_org_members(exclude=('Auditor',))
if self.data:
return
......
......@@ -19,7 +19,7 @@ class RemoteAppPermissionCreateUpdateForm(OrgModelForm):
super().__init__(*args, **kwargs)
users_field = self.fields.get('users')
if hasattr(users_field, 'queryset'):
users_field.queryset = current_org.get_org_users()
users_field.queryset = current_org.get_org_members(exclude=('Auditor',))
class Meta:
model = RemoteAppPermission
......
......@@ -131,16 +131,15 @@ class AssetPermissionUserView(PermissionsMixin,
return queryset
def get_context_data(self, **kwargs):
user_remain = current_org.get_org_members(exclude=('Auditor',)).exclude(
assetpermission=self.object)
user_groups_remain = UserGroup.objects.exclude(
assetpermission=self.object)
context = {
'app': _('Perms'),
'action': _('Asset permission user list'),
'users_remain': current_org.get_org_users().exclude(
assetpermission=self.object
),
'user_groups_remain': UserGroup.objects.exclude(
assetpermission=self.object
)
'users_remain': user_remain,
'user_groups_remain': user_groups_remain,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
......
......@@ -107,15 +107,15 @@ class RemoteAppPermissionUserView(PermissionsMixin,
return queryset
def get_context_data(self, **kwargs):
user_remain = current_org.get_org_members(exclude=('Auditor',)).exclude(
remoteapppermission=self.object)
user_groups_remain = UserGroup.objects.exclude(
remoteapppermission=self.object)
context = {
'app': _('Perms'),
'action': _('RemoteApp permission user list'),
'users_remain': current_org.get_org_users().exclude(
remoteapppermission=self.object
),
'user_groups_remain': UserGroup.objects.exclude(
remoteapppermission=self.object
)
'users_remain': user_remain,
'user_groups_remain': user_groups_remain,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
......
......@@ -68,7 +68,7 @@
</a>
<ul class="dropdown-menu animated fadeInRight m-t-xs profile-dropdown">
<li><a href="{% url 'users:user-profile' %}"><i class="fa fa-cogs"> </i><span> {% trans 'Profile' %}</span></a></li>
{% if request.user.is_org_admin %}
{% if request.user.can_admin_or_audit_current_org %}
{% if request.COOKIES.IN_ADMIN_PAGE == 'No' %}
<li><a id="switch_admin"><i class="fa fa-exchange"></i><span> {% trans 'Admin page' %}</span></a></li>
{% else %}
......@@ -107,3 +107,23 @@
<div class="col-sm-2">
</div>
</div>
<script>
$(document).ready(function () {
})
.on('click', '#switch_admin', function () {
var cookieName = "IN_ADMIN_PAGE";
setTimeout(function () {
delCookie(cookieName);
setCookie(cookieName, "Yes");
window.location = "/"
}, 100)
})
.on('click', '#switch_user', function () {
var cookieName = "IN_ADMIN_PAGE";
setTimeout(function () {
delCookie(cookieName);
setCookie(cookieName, "No");
window.location = "{% url 'assets:user-asset-list' %}"
}, 100);
})
</script>
......@@ -2,12 +2,10 @@
<div class="sidebar-collapse">
<ul class="nav" id="side-menu">
{% include '_user_profile.html' %}
{% if request.user.is_org_admin and request.COOKIES.IN_ADMIN_PAGE != "No" %}
{% include '_nav.html' %}
{% elif request.user.is_auditor %}
{% include '_nav_audits.html' %}
{% else %}
{% if request.user.is_common_user or request.COOKIES.IN_ADMIN_PAGE == 'No' %}
{% include '_nav_user.html' %}
{% else %}
{% include '_nav.html' %}
{% endif %}
</ul>
</div>
......
{% load i18n %}
<li id="index">
{# Index #}
{% if request.user.can_admin_or_audit_current_org %}
<li id="index">
<a href="{% url 'index' %}">
<i class="fa fa-dashboard" style="width: 14px"></i> <span class="nav-label">{% trans 'Dashboard' %}</span>
<span class="label label-info pull-right"></span>
</a>
</li>
<li id="users">
</li>
{% endif %}
{# Users #}
{% if request.user.can_admin_current_org %}
<li id="users">
<a href="#">
<i class="fa fa-group" style="width: 14px"></i> <span class="nav-label">{% trans 'Users' %}</span><span class="fa arrow"></span>
</a>
......@@ -13,8 +20,21 @@
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User list' %}</a></li>
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li>
</ul>
</li>
<li id="assets">
</li>
{% endif %}
{# User info #}
{% if not request.user.can_admin_current_org and request.user.can_audit_current_org %}
<li id="users">
<a href="{% url 'users:user-profile' %}">
<i class="fa fa-user" style="width: 14px"></i> <span class="nav-label">{% trans 'Profile' %}</span><span class="label label-info pull-right"></span>
</a>
</li>
{% endif %}
{# Assets #}
{% if request.user.can_admin_current_org %}
<li id="assets">
<a>
<i class="fa fa-inbox" style="width: 14px"></i> <span class="nav-label">{% trans 'Assets' %}</span><span class="fa arrow"></span>
</a>
......@@ -26,18 +46,26 @@
<li id="label"><a href="{% url 'assets:label-list' %}">{% trans 'Labels' %}</a></li>
<li id="cmd-filter"><a href="{% url 'assets:cmd-filter-list' %}">{% trans 'Command filters' %}</a></li>
</ul>
</li>
{% if LICENSE_VALID %}
<li id="applications">
</li>
{% endif %}
{# Applications #}
{% if request.user.can_admin_current_org and LICENSE_VALID %}
<li id="applications">
<a>
<i class="fa fa-th" style="width: 14px"></i> <span class="nav-label">{% trans 'Applications' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="remote-app"><a href="{% url 'applications:remote-app-list' %}">{% trans 'RemoteApp' %}</a></li>
</ul>
</li>
</li>
{% endif %}
<li id="perms">
{# Perms #}
{% if request.user.can_admin_current_org %}
<li id="perms">
<a href="#"><i class="fa fa-edit" style="width: 14px"></i> <span class="nav-label">{% trans 'Perms' %}</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li id="asset-permission">
......@@ -49,8 +77,13 @@
</li>
{% endif %}
</ul>
</li>
<li id="terminal">
</li>
{% endif %}
{# Terminal #}
{% if request.user.can_admin_or_audit_current_org %}
<li id="terminal">
<a>
<i class="fa fa-rocket" style="width: 14px"></i> <span class="nav-label">{% trans 'Sessions' %}</span><span class="fa arrow"></span>
</a>
......@@ -58,22 +91,23 @@
<li id="session-online"><a href="{% url 'terminal:session-online-list' %}">{% trans 'Session online' %}</a></li>
<li id="session-offline"><a href="{% url 'terminal:session-offline-list' %}">{% trans 'Session offline' %}</a></li>
<li id="command"><a href="{% url 'terminal:command-list' %}">{% trans 'Commands' %}</a></li>
<li>
<a href="{% url 'terminal:web-terminal' %}" target="_blank">
<span class="nav-label">{% trans 'Web terminal' %}</span>
</a>
</li>
<li>
<a href="{% url 'terminal:web-sftp' %}" target="_blank">
<span class="nav-label">{% trans 'File manager' %}</span>
</a>
</li>
{% if request.user.can_admin_current_org %}
<li><a href="{% url 'terminal:web-terminal' %}" target="_blank"><span class="nav-label">{% trans 'Web terminal' %}</span></a></li>
<li><a href="{% url 'terminal:web-sftp' %}" target="_blank"><span class="nav-label">{% trans 'File manager' %}</span></a></li>
{% endif %}
{% if request.user.is_superuser %}
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
{% endif %}
</ul>
</li>
<li id="ops">
</li>
{% endif %}
{# Ops #}
{% if request.user.can_admin_current_org %}
<li id="ops">
<a>
<i class="fa fa-coffee" style="width: 14px"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
</a>
......@@ -81,8 +115,13 @@
<li id="task"><a href="{% url 'ops:task-list' %}">{% trans 'Task list' %}</a></li>
<li id="command-execution"><a href="{% url 'ops:command-execution-start' %}">{% trans 'Batch command' %}</a></li>
</ul>
</li>
<li id="audits">
</li>
{% endif %}
{# Audits #}
{% if request.user.can_admin_or_audit_current_org %}
<li id="audits">
<a>
<i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
</a>
......@@ -93,9 +132,13 @@
<li id="password-change-log"><a href="{% url 'audits:password-change-log-list' %}">{% trans 'Password change log' %}</a></li>
<li id="command-execution-log"><a href="{% url 'audits:command-execution-log-list' %}">{% trans 'Batch command' %}</a></li>
</ul>
</li>
{% if XPACK_PLUGINS %}
<li id="xpack">
</li>
{% endif %}
{# X-Pack #}
{% if request.user.can_admin_current_org and XPACK_PLUGINS %}
<li id="xpack">
<a>
<i class="fa fa-sitemap" style="width: 14px"></i> <span class="nav-label">{% trans 'XPack' %}</span><span class="fa arrow"></span>
</a>
......@@ -114,14 +157,16 @@
{% endifequal %}
{% endfor %}
</ul>
</li>
</li>
{% endif %}
{# Settings #}
{% if request.user.is_superuser %}
<li id="settings">
<li id="settings">
<a href="{% url 'settings:basic-setting' %}">
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
</a>
</li>
</li>
{% endif %}
<script>
......
{% load i18n %}
<li id="index">
<a href="{% url 'index' %}">
<i class="fa fa-dashboard" style="width: 14px"></i> <span class="nav-label">{% trans 'Dashboard' %}</span>
<span class="label label-info pull-right"></span>
</a>
</li>
<li id="terminal">
<a>
<i class="fa fa-rocket" style="width: 14px"></i> <span class="nav-label">{% trans 'Sessions' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="session-online"><a href="{% url 'terminal:session-online-list' %}">{% trans 'Session online' %}</a></li>
<li id="session-offline"><a href="{% url 'terminal:session-offline-list' %}">{% trans 'Session offline' %}</a></li>
<li id="command"><a href="{% url 'terminal:command-list' %}">{% trans 'Commands' %}</a></li>
</ul>
</li>
<li id="audits">
<a>
<i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="login-log"><a href="{% url 'audits:login-log-list' %}">{% trans 'Login log' %}</a></li>
<li id="ftp-log"><a href="{% url 'audits:ftp-log-list' %}">{% trans 'FTP log' %}</a></li>
<li id="operate-log"><a href="{% url 'audits:operate-log-list' %}">{% trans 'Operate log' %}</a></li>
<li id="password-change-log"><a href="{% url 'audits:password-change-log-list' %}">{% trans 'Password change log' %}</a></li>
<li id="command-execution-log"><a href="{% url 'audits:command-execution-log-list' %}">{% trans 'Batch command' %}</a></li>
</ul>
</li>
\ No newline at end of file
......@@ -9,8 +9,8 @@
<div class="logo-element">
<img alt="image" height="40" src="{{ LOGO_URL }}"/>
</div>
{% if ADMIN_ORGS and request.COOKIES.IN_ADMIN_PAGE != 'No' %}
{% if ADMIN_ORGS|length > 1 or not CURRENT_ORG.is_default %}
{% if ADMIN_OR_AUDIT_ORGS and request.COOKIES.IN_ADMIN_PAGE != 'No' %}
{% if ADMIN_OR_AUDIT_ORGS|length > 1 or not CURRENT_ORG.is_default %}
<div>
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" style="display: block; background-color: transparent; color: #8095a8; padding: 14px 20px 14px 25px">
<i class="fa fa-bookmark" style="width: 14px; "></i>
......@@ -20,7 +20,7 @@
<span class="fa fa-sort-desc pull-right"></span>
</a>
<ul class="dropdown-menu" style="min-width: 220px">
{% for org in ADMIN_ORGS %}
{% for org in ADMIN_OR_AUDIT_ORGS %}
<li>
<a class="org-dropdown" href="{% url 'orgs:org-switch' pk=org.id %}" data-id="{{ org.id }}">
{{ org.name }}
......@@ -35,23 +35,3 @@
{% endif %}
{% endif %}
</li>
<script>
$(document).ready(function () {
})
.on('click', '#switch_admin', function () {
var cookieName = "IN_ADMIN_PAGE";
setTimeout(function () {
delCookie(cookieName);
setCookie(cookieName, "Yes");
window.location = "/"
}, 100)
})
.on('click', '#switch_user', function () {
var cookieName = "IN_ADMIN_PAGE";
setTimeout(function () {
delCookie(cookieName);
setCookie(cookieName, "No");
window.location = "{% url 'assets:user-asset-list' %}"
}, 100);
})
</script>
......@@ -9,7 +9,7 @@ from rest_framework.response import Response
from django.template import loader
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
from common.utils import get_logger
from ..backends import (
get_command_storage, get_multi_command_storage,
......@@ -22,7 +22,7 @@ __all__ = ['CommandViewSet', 'CommandExportApi']
class CommandQueryMixin:
command_store = get_command_storage()
permission_classes = [IsOrgAdminOrAppUser | IsAuditor]
permission_classes = [IsOrgAdminOrAppUser | IsOrgAuditor]
filter_fields = [
"asset", "system_user", "user", "session",
]
......
......@@ -12,7 +12,7 @@ from rest_framework.generics import GenericAPIView
import jms_storage
from common.utils import is_uuid, get_logger
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
from common.filters import DatetimeRangeFilter
from orgs.mixins.api import OrgBulkModelViewSet
from ..hands import SystemUser
......@@ -27,7 +27,7 @@ logger = get_logger(__name__)
class SessionViewSet(OrgBulkModelViewSet):
queryset = Session.objects.all()
serializer_class = serializers.SessionSerializer
permission_classes = (IsOrgAdminOrAppUser | IsAuditor, )
permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor, )
filter_fields = [
"user", "asset", "system_user", "remote_addr",
"protocol", "terminal", "is_finished",
......@@ -62,7 +62,7 @@ class SessionViewSet(OrgBulkModelViewSet):
class SessionReplayViewSet(viewsets.ViewSet):
serializer_class = serializers.ReplaySerializer
permission_classes = (IsOrgAdminOrAppUser | IsAuditor,)
permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor,)
session = None
def create(self, request, *args, **kwargs):
......
......@@ -5,14 +5,14 @@ from django.views.generic import TemplateView
from django.utils.translation import ugettext as _
from django.utils import timezone
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
__all__ = ['CommandListView']
class CommandListView(PermissionsMixin, TemplateView):
template_name = "terminal/command_list.html"
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
default_days_ago = 5
def get_context_data(self, **kwargs):
......
......@@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
from django.utils import timezone
from django.conf import settings
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
from common.mixins import DatetimeSearchMixin
from ..models import Session, Command, Terminal
from ..backends import get_multi_command_storage
......@@ -24,7 +24,7 @@ class SessionListView(PermissionsMixin, TemplateView):
model = Session
template_name = 'terminal/session_list.html'
date_from = date_to = None
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
default_days_ago = 5
def get_context_data(self, **kwargs):
......@@ -63,7 +63,7 @@ class SessionDetailView(SingleObjectMixin, PermissionsMixin, ListView):
template_name = 'terminal/session_detail.html'
model = Session
object = None
permission_classes = [IsOrgAdmin | IsAuditor]
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=self.model.objects.all())
......
......@@ -8,12 +8,11 @@ from django.utils.translation import ugettext as _
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.serializers import ValidationError
from rest_framework_bulk import BulkModelViewSet
from common.permissions import (
IsOrgAdmin, IsCurrentUserOrReadOnly, IsOrgAdminOrAppUser,
CanUpdateDeleteSuperUser,
CanUpdateDeleteUser,
)
from common.mixins import IDInCacheFilterMixin
from common.utils import get_logger
......@@ -36,7 +35,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
search_fields = filter_fields
queryset = User.objects.exclude(role=User.ROLE_APP)
serializer_class = serializers.UserSerializer
permission_classes = (IsOrgAdmin, CanUpdateDeleteSuperUser)
permission_classes = (IsOrgAdmin, CanUpdateDeleteUser)
def send_created_signal(self, users):
if not isinstance(users, list):
......@@ -53,7 +52,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
self.send_created_signal(users)
def get_queryset(self):
queryset = current_org.get_org_users().prefetch_related('groups')
queryset = current_org.get_org_members().prefetch_related('groups')
return queryset
def get_permissions(self):
......@@ -61,32 +60,17 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
self.permission_classes = (IsOrgAdminOrAppUser,)
return super().get_permissions()
def _deny_permission(self, instance):
"""
check current user has permission to handle instance
(update, destroy, bulk_update, bulk destroy)
"""
if instance.is_superuser and not self.request.user.is_superuser:
return True
return False
def _bulk_deny_permission(self, instances):
deny_instances = [i for i in instances if self._deny_permission(i)]
if len(deny_instances) > 0:
return True
else:
return False
def allow_bulk_destroy(self, qs, filtered):
return False
def perform_bulk_update(self, serializer):
users_ids = [d.get("id") or d.get("pk") for d in serializer.validated_data]
users = User.objects.filter(id__in=users_ids)
deny_instances = [str(i.id) for i in users if self._deny_permission(i)]
if deny_instances:
msg = "{} can't be update".format(deny_instances)
raise ValidationError({"id": msg})
# TODO: 需要测试
users_ids = [
d.get("id") or d.get("pk") for d in serializer.validated_data
]
users = current_org.get_org_members().filter(id__in=users_ids)
for user in users:
self.check_object_permissions(self.request, user)
return super().perform_bulk_update(serializer)
......
......@@ -335,7 +335,7 @@ class UserGroupForm(OrgModelForm):
return
users_field = self.fields.get('users')
if hasattr(users_field, 'queryset'):
users_field.queryset = current_org.get_org_users()
users_field.queryset = current_org.get_org_members(exclude=('Auditor',))
def save(self, commit=True):
group = super().save(commit=commit)
......
......@@ -5,7 +5,6 @@ import uuid
import base64
import string
import random
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.hashers import make_password
......@@ -16,6 +15,7 @@ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.shortcuts import reverse
from orgs.utils import current_org
from common.utils import get_signer, date_expired_default, get_logger
from common import fields
......@@ -132,7 +132,16 @@ class RoleMixin:
@property
def role_display(self):
if not current_org.is_real():
return self.get_role_display()
roles = []
if self in current_org.get_org_admins():
roles.append(str(_('Org admin')))
if self in current_org.get_org_auditors():
roles.append(str(_('Org auditor')))
if self in current_org.get_org_users():
roles.append(str(_('User')))
return " | ".join(roles)
@property
def is_superuser(self):
......@@ -148,35 +157,69 @@ class RoleMixin:
else:
self.role = 'User'
@property
def is_super_auditor(self):
return self.role == 'Auditor'
@property
def is_common_user(self):
if self.is_org_admin:
return False
if self.is_org_auditor:
return False
if self.is_app:
return False
return True
@property
def is_app(self):
return self.role == 'App'
@property
def user_orgs(self):
from orgs.models import Organization
return Organization.get_user_user_orgs(self)
@property
def admin_orgs(self):
from orgs.models import Organization
return Organization.get_user_admin_orgs(self)
@property
def audit_orgs(self):
from orgs.models import Organization
return Organization.get_user_audit_orgs(self)
@property
def admin_or_audit_orgs(self):
from orgs.models import Organization
return Organization.get_user_admin_or_audit_orgs(self)
@property
def is_org_admin(self):
if self.is_superuser or self.admin_orgs.exists():
if self.is_superuser or self.related_admin_orgs.exists():
return True
else:
return False
@property
def is_auditor(self):
return self.role == 'Auditor'
def is_org_auditor(self):
if self.is_super_auditor or self.related_audit_orgs.exists():
return True
else:
return False
@property
def is_common_user(self):
if self.is_org_admin:
return False
if self.is_auditor:
return False
if self.is_app:
return False
return True
def can_admin_current_org(self):
return current_org.can_admin_by(self)
@property
def is_app(self):
return self.role == 'App'
def can_audit_current_org(self):
return current_org.can_audit_by(self)
@property
def can_admin_or_audit_current_org(self):
return self.can_admin_current_org or self.can_audit_current_org
@property
def is_staff(self):
......
# -*- coding: utf-8 -*-
#
import copy
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
......@@ -8,6 +9,7 @@ from common.utils import validate_ssh_public_key
from common.mixins import BulkSerializerMixin
from common.fields import StringManyToManyField
from common.serializers import AdaptedBulkListSerializer
from common.permissions import CanUpdateDeleteUser
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ..models import User, UserGroup
......@@ -22,6 +24,9 @@ __all__ = [
class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
can_update = serializers.SerializerMethodField()
can_delete = serializers.SerializerMethodField()
class Meta:
model = User
list_serializer_class = AdaptedBulkListSerializer
......@@ -32,6 +37,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
'comment', 'source', 'source_display', 'is_valid', 'is_expired',
'is_active', 'created_by', 'is_first_login',
'date_password_last_updated', 'date_expired', 'avatar_url',
'can_update', 'can_delete',
]
extra_kwargs = {
'password': {'write_only': True, 'required': False, 'allow_null': True, 'allow_blank': True},
......@@ -43,10 +49,22 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
'is_valid': {'label': _('Is valid')},
'is_expired': {'label': _('Is expired')},
'avatar_url': {'label': _('Avatar url')},
'created_by': {'read_only': True, 'allow_blank': True},
'source': {'read_only': True},
'created_by': {'read_only': True, 'allow_blank': True},
'can_update': {'read_only': True},
'can_delete': {'read_only': True},
}
def get_can_update(self, obj):
return CanUpdateDeleteUser.has_update_object_permission(
self.context['request'], self.context['view'], obj
)
def get_can_delete(self, obj):
return CanUpdateDeleteUser.has_delete_object_permission(
self.context['request'], self.context['view'], obj
)
def validate_role(self, value):
request = self.context.get('request')
if not request.user.is_superuser and value != User.ROLE_USER:
......@@ -67,20 +85,24 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
raise serializers.ValidationError(msg)
return password
def validate_groups(self, groups):
role = self.initial_data.get('role')
if self.instance:
role = role or self.instance.role
if role == User.ROLE_AUDITOR:
return []
return groups
@staticmethod
def change_password_to_raw(validated_data):
password = validated_data.pop('password', None)
def change_password_to_raw(attrs):
password = attrs.pop('password', None)
if password:
validated_data['password_raw'] = password
return validated_data
def create(self, validated_data):
validated_data = self.change_password_to_raw(validated_data)
return super().create(validated_data)
attrs['password_raw'] = password
return attrs
def update(self, instance, validated_data):
validated_data = self.change_password_to_raw(validated_data)
return super().update(instance, validated_data)
def validate(self, attrs):
attrs = self.change_password_to_raw(attrs)
return attrs
class UserPKUpdateSerializer(serializers.ModelSerializer):
......@@ -119,6 +141,13 @@ class UserGroupSerializer(BulkOrgResourceModelSerializer):
'created_by': {'label': _('Created by'), 'read_only': True}
}
def validate_users(self, users):
for user in users:
if user.is_super_auditor:
msg = _('Auditors cannot be join in the group')
raise serializers.ValidationError(msg)
return users
class UserGroupListSerializer(UserGroupSerializer):
users = StringManyToManyField(many=True, read_only=True)
......
......@@ -61,6 +61,17 @@
<link rel="stylesheet" type="text/css" href={% static "css/plugins/daterangepicker/daterangepicker.css" %} />
<script>
var role_id = '#' + '{{ form.role.id_for_label }}';
var groups_id = '#' + '{{ form.groups.id_for_label }}';
function fieldDisplay(){
var role = $(role_id).val();
if (role === 'Auditor'){
$(groups_id).closest('.form-group').addClass('hidden');
}
else {
$(groups_id).closest('.form-group').removeClass('hidden');
}}
var dateOptions = {
singleDatePicker: true,
showDropdowns: true,
......@@ -76,7 +87,10 @@
$('#id_date_expired').daterangepicker(dateOptions);
var mfa_radio = $('#id_otp_level');
mfa_radio.addClass("form-inline");
mfa_radio.children().css("margin-right","15px")
mfa_radio.children().css("margin-right","15px");
fieldDisplay()
}).on('change', role_id, function(){
fieldDisplay();
})
</script>
{% endblock %}
......@@ -22,11 +22,11 @@
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline {% if user_object.is_superuser and not request.user.is_superuser %} disabled {% else %} btn-default {% endif %}" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
<a class="btn btn-outline {% if can_update %} btn-default {% else %} disabled {% endif %}" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline {% if request.user == user_object or user_object.username == "admin" or user_object.is_superuser and not request.user.is_superuser %} disabled {% else %} btn-danger btn-delete-user {% endif %}">
<a class="btn btn-outline {% if can_delete %} btn-danger btn-delete-user {% else %} disabled {% endif %}">
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a>
</li>
......@@ -85,7 +85,7 @@
{% endif %}
<tr>
<td>{% trans 'Role' %}:</td>
<td><b>{{ user_object.get_role_display }}</b></td>
<td><b>{{ user_object.role_display }}</b></td>
</tr>
<tr>
<td>{% trans 'MFA certification' %}:</td>
......@@ -212,6 +212,7 @@
</div>
</div>
{% if user_object.is_current_org_admin %}
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'User group' %}
......@@ -250,6 +251,7 @@
</table>
</div>
</div>
{% endif %}
</div>
</div>
</div>
......
......@@ -99,7 +99,7 @@ function initTable() {
{targets: 7, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = "";
if (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin')) {
if (rowData.can_update === false){
update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>';
}
else{
......@@ -107,7 +107,7 @@ function initTable() {
}
var del_btn = "";
if (rowData.id === 1 || rowData.username === "admin" || rowData.username === "{{ request.user.username }}" || (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin'))) {
if (rowData.can_delete === false){
del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
......
......@@ -76,7 +76,8 @@ class UserGroupDetailView(PermissionsMixin, DetailView):
permission_classes = [IsOrgAdmin]
def get_context_data(self, **kwargs):
users = current_org.get_org_users().exclude(id__in=self.object.users.all())
users = current_org.get_org_members(exclude=('Auditor',)).exclude(
groups=self.object)
context = {
'app': _('Users'),
'action': _('User group detail'),
......
......@@ -27,6 +27,7 @@ from common.utils import get_logger, ssh_key_gen
from common.permissions import (
PermissionsMixin, IsOrgAdmin, IsValidUser,
UserCanUpdatePassword, UserCanUpdateSSHKey,
CanUpdateDeleteUser,
)
from orgs.utils import current_org
from .. import forms
......@@ -86,7 +87,7 @@ class UserCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
user.created_by = self.request.user.username or 'System'
user.save()
if current_org and current_org.is_real():
user.orgs.add(current_org.id)
user.related_user_orgs.add(current_org.id)
post_user_create.send(self.__class__, user=user)
return super().form_valid(form)
......@@ -189,13 +190,19 @@ class UserDetailView(PermissionsMixin, DetailView):
'action': _('User detail'),
'groups': groups,
'unblock': is_need_unblock(key_block),
'can_update': CanUpdateDeleteUser.has_update_object_permission(
self.request, self, user
),
'can_delete': CanUpdateDeleteUser.has_delete_object_permission(
self.request, self, user
),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
def get_queryset(self):
queryset = super().get_queryset()
org_users = current_org.get_org_users().values_list('id', flat=True)
org_users = current_org.get_org_members().values_list('id', flat=True)
queryset = queryset.filter(id__in=org_users)
return queryset
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment