mirror of https://github.com/jumpserver/jumpserver
超级管理员可创建超级审计员并可设置审计员为组织审计员 (#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密码的逻辑pull/3224/head
parent
5f23c358da
commit
a2376d3afd
|
@ -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']:
|
||||
return True
|
||||
elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
|
||||
class CanUpdateDeleteUser(permissions.BasePermission):
|
||||
|
||||
@staticmethod
|
||||
def has_delete_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 False
|
||||
# 超级管理员
|
||||
if request.user.is_superuser:
|
||||
if obj.is_superuser and obj.username in ['admin']:
|
||||
return False
|
||||
return True
|
||||
if hasattr(obj, 'is_superuser') and obj.is_superuser:
|
||||
# 组织管理员
|
||||
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
|
||||
|
||||
@staticmethod
|
||||
def has_update_object_permission(request, view, obj):
|
||||
if not request.user.can_admin_current_org:
|
||||
return False
|
||||
# 超级管理员 / 组织管理员
|
||||
if str(request.user.id) == str(obj.id):
|
||||
return True
|
||||
# 超级管理员
|
||||
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 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 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>
|
||||
|
|
|
@ -1,127 +1,172 @@
|
|||
{% 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="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>
|
||||
<ul class="nav nav-second-level active">
|
||||
<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">
|
||||
<a>
|
||||
<i class="fa fa-inbox" style="width: 14px"></i> <span class="nav-label">{% trans 'Assets' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li>
|
||||
<li id="domain"><a href="{% url 'assets:domain-list' %}">{% trans 'Domain list' %}</a></li>
|
||||
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
|
||||
<li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
|
||||
<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">
|
||||
<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>
|
||||
|
||||
{# 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>
|
||||
{% endif %}
|
||||
<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">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
{% if LICENSE_VALID %}
|
||||
<li id="remote-app-permission">
|
||||
<a href="{% url 'perms:remote-app-permission-list' %}">{% trans 'RemoteApp' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</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>
|
||||
<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.is_superuser %}
|
||||
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
<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>
|
||||
<ul class="nav nav-second-level">
|
||||
<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">
|
||||
<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>
|
||||
{% if 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>
|
||||
<ul class="nav nav-second-level">
|
||||
{% for plugin in XPACK_PLUGINS %}
|
||||
{% ifequal plugin.name 'cloud'%}
|
||||
<li id="{{ plugin.name }}">
|
||||
<a href="#"><span class="nav-label">{% trans plugin.verbose_name %}</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-third-level">
|
||||
<li id="account"><a href="{% url 'xpack:cloud:account-list' %}">{% trans 'Account list' %}</a></li>
|
||||
<li id="sync-instance-task"><a href="{% url 'xpack:cloud:sync-instance-task-list' %}">{% trans 'Sync instance' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li id="{{ plugin.name }}"><a href="{{ plugin.endpoint }}">{% trans plugin.verbose_name %}</a></li>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
{# 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>
|
||||
<ul class="nav nav-second-level active">
|
||||
<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>
|
||||
{% 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>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li>
|
||||
<li id="domain"><a href="{% url 'assets:domain-list' %}">{% trans 'Domain list' %}</a></li>
|
||||
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
|
||||
<li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
|
||||
<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>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{# 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">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
{% if LICENSE_VALID %}
|
||||
<li id="remote-app-permission">
|
||||
<a href="{% url 'perms:remote-app-permission-list' %}">{% trans 'RemoteApp' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
{% 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>
|
||||
{% 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>
|
||||
<ul class="nav nav-second-level">
|
||||
<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>
|
||||
{% 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>
|
||||
<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>
|
||||
{% 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>
|
||||
<ul class="nav nav-second-level">
|
||||
{% for plugin in XPACK_PLUGINS %}
|
||||
{% ifequal plugin.name 'cloud'%}
|
||||
<li id="{{ plugin.name }}">
|
||||
<a href="#"><span class="nav-label">{% trans plugin.verbose_name %}</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-third-level">
|
||||
<li id="account"><a href="{% url 'xpack:cloud:account-list' %}">{% trans 'Account list' %}</a></li>
|
||||
<li id="sync-instance-task"><a href="{% url 'xpack:cloud:sync-instance-task-list' %}">{% trans 'Sync instance' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li id="{{ plugin.name }}"><a href="{{ plugin.endpoint }}">{% trans plugin.verbose_name %}</a></li>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Settings #}
|
||||
{% if request.user.is_superuser %}
|
||||
<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 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>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{% 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>
|
|
@ -9,49 +9,29 @@
|
|||
<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 %}
|
||||
<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>
|
||||
<span class="nav-label" style="padding-left: 7px">
|
||||
{{ CURRENT_ORG.name }}
|
||||
</span>
|
||||
<span class="fa fa-sort-desc pull-right"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" style="min-width: 220px">
|
||||
{% for org in ADMIN_ORGS %}
|
||||
<li>
|
||||
<a class="org-dropdown" href="{% url 'orgs:org-switch' pk=org.id %}" data-id="{{ org.id }}">
|
||||
{{ org.name }}
|
||||
{% if org.id == CURRENT_ORG.id %}
|
||||
<span class="fa fa-circle" style="padding-top: 5px; color: #1ab394"></span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% 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>
|
||||
<span class="nav-label" style="padding-left: 7px">
|
||||
{{ CURRENT_ORG.name }}
|
||||
</span>
|
||||
<span class="fa fa-sort-desc pull-right"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" style="min-width: 220px">
|
||||
{% 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 }}
|
||||
{% if org.id == CURRENT_ORG.id %}
|
||||
<span class="fa fa-circle" style="padding-top: 5px; color: #1ab394"></span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% 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):
|
||||
return self.get_role_display()
|
||||
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):
|
||||
|
@ -149,26 +158,14 @@ class RoleMixin:
|
|||
self.role = 'User'
|
||||
|
||||
@property
|
||||
def admin_orgs(self):
|
||||
from orgs.models import Organization
|
||||
return Organization.get_user_admin_orgs(self)
|
||||
|
||||
@property
|
||||
def is_org_admin(self):
|
||||
if self.is_superuser or self.admin_orgs.exists():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_auditor(self):
|
||||
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_auditor:
|
||||
if self.is_org_auditor:
|
||||
return False
|
||||
if self.is_app:
|
||||
return False
|
||||
|
@ -178,6 +175,52 @@ class RoleMixin:
|
|||
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.related_admin_orgs.exists():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_org_auditor(self):
|
||||
if self.is_super_auditor or self.related_audit_orgs.exists():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_admin_current_org(self):
|
||||
return current_org.can_admin_by(self)
|
||||
|
||||
@property
|
||||
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):
|
||||
if self.is_authenticated and self.is_valid:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- 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
|
||||
attrs['password_raw'] = password
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data = self.change_password_to_raw(validated_data)
|
||||
return super().create(validated_data)
|
||||
|
||||
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)
|
||||
|
@ -140,4 +169,4 @@ class ChangeUserPasswordSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class ResetOTPSerializer(serializers.Serializer):
|
||||
msg = serializers.CharField(read_only=True)
|
||||
msg = serializers.CharField(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,44 +212,46 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'User group' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for group in groups %}
|
||||
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
{% 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' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for group in groups %}
|
||||
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td >
|
||||
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td >
|
||||
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</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
|
||||
|
||||
|
|
Loading…
Reference in New Issue