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 rest_framework import viewsets
|
||||||
|
|
||||||
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
|
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
|
||||||
from .models import FTPLog
|
from .models import FTPLog
|
||||||
from .serializers import FTPLogSerializer
|
from .serializers import FTPLogSerializer
|
||||||
|
|
||||||
|
@ -11,4 +11,4 @@ from .serializers import FTPLogSerializer
|
||||||
class FTPLogViewSet(viewsets.ModelViewSet):
|
class FTPLogViewSet(viewsets.ModelViewSet):
|
||||||
queryset = FTPLog.objects.all()
|
queryset = FTPLog.objects.all()
|
||||||
serializer_class = FTPLogSerializer
|
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 audits.utils import get_excel_response, write_content_to_excel
|
||||||
from common.mixins import DatetimeSearchMixin
|
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 orgs.utils import current_org
|
||||||
from ops.views import CommandExecutionListView as UserCommandExecutionListView
|
from ops.views import CommandExecutionListView as UserCommandExecutionListView
|
||||||
from .models import FTPLog, OperateLog, PasswordChangeLog, UserLoginLog
|
from .models import FTPLog, OperateLog, PasswordChangeLog, UserLoginLog
|
||||||
|
@ -47,7 +48,7 @@ class FTPLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
paginate_by = settings.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
user = asset = system_user = filename = ''
|
user = asset = system_user = filename = ''
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = super().get_queryset()
|
self.queryset = super().get_queryset()
|
||||||
|
@ -96,7 +97,7 @@ class OperateLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
user = action = resource_type = ''
|
user = action = resource_type = ''
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
actions_dict = dict(OperateLog.ACTION_CHOICES)
|
actions_dict = dict(OperateLog.ACTION_CHOICES)
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = super().get_queryset()
|
self.queryset = super().get_queryset()
|
||||||
|
@ -119,7 +120,7 @@ class OperateLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'user_list': current_org.get_org_users(),
|
'user_list': current_org.get_org_members(),
|
||||||
'actions': self.actions_dict,
|
'actions': self.actions_dict,
|
||||||
'resource_type_list': get_resource_type_list(),
|
'resource_type_list': get_resource_type_list(),
|
||||||
'date_from': self.date_from,
|
'date_from': self.date_from,
|
||||||
|
@ -139,10 +140,10 @@ class PasswordChangeLogList(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
paginate_by = settings.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
user = ''
|
user = ''
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
users = current_org.get_org_users()
|
users = current_org.get_org_members()
|
||||||
self.queryset = super().get_queryset().filter(
|
self.queryset = super().get_queryset().filter(
|
||||||
user__in=[user.__str__() for user in users]
|
user__in=[user.__str__() for user in users]
|
||||||
)
|
)
|
||||||
|
@ -159,7 +160,7 @@ class PasswordChangeLogList(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'user_list': current_org.get_org_users(),
|
'user_list': current_org.get_org_members(),
|
||||||
'date_from': self.date_from,
|
'date_from': self.date_from,
|
||||||
'date_to': self.date_to,
|
'date_to': self.date_to,
|
||||||
'user': self.user,
|
'user': self.user,
|
||||||
|
@ -176,18 +177,18 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
paginate_by = settings.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
user = keyword = ""
|
user = keyword = ""
|
||||||
date_to = date_from = None
|
date_to = date_from = None
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_org_users():
|
def get_org_members():
|
||||||
users = current_org.get_org_users().values_list('username', flat=True)
|
users = current_org.get_org_members().values_list('username', flat=True)
|
||||||
return users
|
return users
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if current_org.is_default():
|
if current_org.is_default():
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
else:
|
else:
|
||||||
users = self.get_org_users()
|
users = self.get_org_members()
|
||||||
queryset = super().get_queryset().filter(username__in=users)
|
queryset = super().get_queryset().filter(username__in=users)
|
||||||
|
|
||||||
self.user = self.request.GET.get('user', '')
|
self.user = self.request.GET.get('user', '')
|
||||||
|
@ -214,7 +215,7 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
'date_to': self.date_to,
|
'date_to': self.date_to,
|
||||||
'user': self.user,
|
'user': self.user,
|
||||||
'keyword': self.keyword,
|
'keyword': self.keyword,
|
||||||
'user_list': self.get_org_users(),
|
'user_list': self.get_org_members(),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
@ -223,6 +224,10 @@ class LoginLogListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
class CommandExecutionListView(UserCommandExecutionListView):
|
class CommandExecutionListView(UserCommandExecutionListView):
|
||||||
user_id = None
|
user_id = None
|
||||||
|
|
||||||
|
def get_user_list(self):
|
||||||
|
users = current_org.get_org_members(exclude=('Auditor',))
|
||||||
|
return users
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = self._get_queryset()
|
queryset = self._get_queryset()
|
||||||
self.user_id = self.request.GET.get('user')
|
self.user_id = self.request.GET.get('user')
|
||||||
|
@ -233,10 +238,6 @@ class CommandExecutionListView(UserCommandExecutionListView):
|
||||||
queryset = queryset.filter(user__in=org_users)
|
queryset = queryset.filter(user__in=org_users)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_user_list(self):
|
|
||||||
users = current_org.get_org_users()
|
|
||||||
return users
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context.update({
|
context.update({
|
||||||
|
|
|
@ -4,8 +4,6 @@ import time
|
||||||
|
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
from django.shortcuts import redirect
|
|
||||||
from django.http.response import HttpResponseForbidden
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
|
@ -27,12 +25,6 @@ class IsAppUser(IsValidUser):
|
||||||
and request.user.is_app
|
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):
|
class IsSuperUser(IsValidUser):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
return super(IsSuperUser, self).has_permission(request, view) \
|
return super(IsSuperUser, self).has_permission(request, view) \
|
||||||
|
@ -45,6 +37,20 @@ class IsSuperUserOrAppUser(IsSuperUser):
|
||||||
or request.user.is_app
|
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):
|
class IsOrgAdmin(IsValidUser):
|
||||||
"""Allows access only to superuser"""
|
"""Allows access only to superuser"""
|
||||||
|
|
||||||
|
@ -81,43 +87,6 @@ class IsCurrentUserOrReadOnly(permissions.BasePermission):
|
||||||
return obj == request.user
|
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):
|
class WithBootstrapToken(permissions.BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
authorization = request.META.get('HTTP_AUTHORIZATION', '')
|
||||||
|
@ -159,14 +128,61 @@ class NeedMFAVerify(permissions.BasePermission):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class CanUpdateDeleteSuperUser(permissions.BasePermission):
|
class CanUpdateDeleteUser(permissions.BasePermission):
|
||||||
def has_object_permission(self, request, view, obj):
|
|
||||||
if request.method in ['GET', 'OPTIONS']:
|
@staticmethod
|
||||||
return True
|
def has_delete_object_permission(request, view, obj):
|
||||||
elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
|
if not request.user.can_admin_current_org:
|
||||||
return False
|
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
|
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 False
|
||||||
return True
|
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):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
return self.handle_no_permission()
|
return self.handle_no_permission()
|
||||||
if request.user.is_auditor:
|
if request.user.is_common_user:
|
||||||
return super(IndexView, self).dispatch(request, *args, **kwargs)
|
|
||||||
if not request.user.is_org_admin:
|
|
||||||
return redirect('assets:user-asset-list')
|
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)
|
return super(IndexView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_count():
|
def get_user_count():
|
||||||
return current_org.get_org_users().count()
|
return current_org.get_org_members().count()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_asset_count():
|
def get_asset_count():
|
||||||
|
@ -99,7 +95,7 @@ class IndexView(PermissionsMixin, TemplateView):
|
||||||
return self.session_month.values('user').distinct().count()
|
return self.session_month.values('user').distinct().count()
|
||||||
|
|
||||||
def get_month_inactive_user_total(self):
|
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:
|
if count < 0:
|
||||||
count = 0
|
count = 0
|
||||||
return count
|
return count
|
||||||
|
@ -115,7 +111,7 @@ class IndexView(PermissionsMixin, TemplateView):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_disabled_total():
|
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
|
@staticmethod
|
||||||
def get_asset_disabled_total():
|
def get_asset_disabled_total():
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
|
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['CeleryTaskLogView']
|
__all__ = ['CeleryTaskLogView']
|
||||||
|
@ -10,7 +10,7 @@ __all__ = ['CeleryTaskLogView']
|
||||||
|
|
||||||
class CeleryTaskLogView(PermissionsMixin, TemplateView):
|
class CeleryTaskLogView(PermissionsMixin, TemplateView):
|
||||||
template_name = 'ops/celery_task_log.html'
|
template_name = 'ops/celery_task_log.html'
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.conf import settings
|
||||||
from django.views.generic import ListView, TemplateView
|
from django.views.generic import ListView, TemplateView
|
||||||
|
|
||||||
from common.permissions import (
|
from common.permissions import (
|
||||||
PermissionsMixin, IsOrgAdmin, IsAuditor, IsValidUser
|
PermissionsMixin, IsOrgAdmin, IsValidUser, IsOrgAuditor
|
||||||
)
|
)
|
||||||
from common.mixins import DatetimeSearchMixin
|
from common.mixins import DatetimeSearchMixin
|
||||||
from ..models import CommandExecution
|
from ..models import CommandExecution
|
||||||
|
@ -25,7 +25,7 @@ class CommandExecutionListView(PermissionsMixin, DatetimeSearchMixin, ListView):
|
||||||
ordering = ('-date_created',)
|
ordering = ('-date_created',)
|
||||||
context_object_name = 'task_list'
|
context_object_name = 'task_list'
|
||||||
keyword = ''
|
keyword = ''
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
self.keyword = self.request.GET.get('keyword', '')
|
self.keyword = self.request.GET.get('keyword', '')
|
||||||
|
|
|
@ -33,7 +33,7 @@ class OrgViewSet(BulkModelViewSet):
|
||||||
|
|
||||||
def get_data_from_model(self, model):
|
def get_data_from_model(self, model):
|
||||||
if model == User:
|
if model == User:
|
||||||
data = model.objects.filter(orgs__id=self.org.id)
|
data = model.objects.filter(related_user_orgs__id=self.org.id)
|
||||||
else:
|
else:
|
||||||
data = model.objects.filter(org_id=self.org.id)
|
data = model.objects.filter(org_id=self.org.id)
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -7,9 +7,11 @@ from .models import Organization
|
||||||
|
|
||||||
def org_processor(request):
|
def org_processor(request):
|
||||||
context = {
|
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),
|
'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
|
return context
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,23 @@ class OrgMiddleware:
|
||||||
def set_permed_org_if_need(request):
|
def set_permed_org_if_need(request):
|
||||||
if request.path.startswith('/api'):
|
if request.path.startswith('/api'):
|
||||||
return
|
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
|
return
|
||||||
org = get_org_from_request(request)
|
org = get_org_from_request(request)
|
||||||
if org.can_admin_by(request.user):
|
if org.can_admin_by(request.user):
|
||||||
return
|
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:
|
if admin_orgs:
|
||||||
request.session['oid'] = str(admin_orgs[0].id)
|
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):
|
def __call__(self, request):
|
||||||
self.set_permed_org_if_need(request)
|
self.set_permed_org_if_need(request)
|
||||||
|
|
|
@ -9,8 +9,9 @@ from common.utils import is_uuid
|
||||||
class Organization(models.Model):
|
class Organization(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
|
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
|
||||||
users = models.ManyToManyField('users.User', related_name='orgs', blank=True)
|
users = models.ManyToManyField('users.User', related_name='related_user_orgs', blank=True)
|
||||||
admins = models.ManyToManyField('users.User', related_name='admin_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'))
|
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'))
|
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'))
|
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
|
org = cls.default() if default else None
|
||||||
return org
|
return org
|
||||||
|
|
||||||
def get_org_users(self, include_app=False):
|
def get_org_users(self):
|
||||||
from users.models import User
|
from users.models import User
|
||||||
if self.is_real():
|
if self.is_real():
|
||||||
users = self.users.all()
|
return self.users.all()
|
||||||
else:
|
return User.objects.filter(role=User.ROLE_USER)
|
||||||
users = User.objects.all()
|
|
||||||
if not include_app:
|
|
||||||
users = users.exclude(role=User.ROLE_APP)
|
|
||||||
return users
|
|
||||||
|
|
||||||
def get_org_admins(self):
|
def get_org_admins(self):
|
||||||
|
from users.models import User
|
||||||
if self.is_real():
|
if self.is_real():
|
||||||
return self.admins.all()
|
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):
|
def can_admin_by(self, user):
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
return True
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -100,13 +122,40 @@ class Organization(models.Model):
|
||||||
admin_orgs = []
|
admin_orgs = []
|
||||||
if user.is_anonymous:
|
if user.is_anonymous:
|
||||||
return admin_orgs
|
return admin_orgs
|
||||||
elif user.is_superuser or user.is_auditor:
|
elif user.is_superuser:
|
||||||
admin_orgs = list(cls.objects.all())
|
admin_orgs = list(cls.objects.all())
|
||||||
admin_orgs.append(cls.default())
|
admin_orgs.append(cls.default())
|
||||||
elif user.is_org_admin:
|
elif user.is_org_admin:
|
||||||
admin_orgs = user.admin_orgs.all()
|
admin_orgs = user.related_admin_orgs.all()
|
||||||
return admin_orgs
|
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
|
@classmethod
|
||||||
def default(cls):
|
def default(cls):
|
||||||
return cls(id=cls.DEFAULT_ID, name=cls.DEFAULT_NAME)
|
return cls(id=cls.DEFAULT_ID, name=cls.DEFAULT_NAME)
|
||||||
|
|
|
@ -21,6 +21,7 @@ class OrgSerializer(ModelSerializer):
|
||||||
|
|
||||||
class OrgReadSerializer(ModelSerializer):
|
class OrgReadSerializer(ModelSerializer):
|
||||||
admins = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
|
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)
|
users = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
|
||||||
user_groups = serializers.SerializerMethodField()
|
user_groups = serializers.SerializerMethodField()
|
||||||
assets = serializers.SerializerMethodField()
|
assets = serializers.SerializerMethodField()
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.views.generic import DetailView, View
|
||||||
|
|
||||||
from .models import Organization
|
from .models import Organization
|
||||||
from common.utils import UUID_PATTERN
|
from common.utils import UUID_PATTERN
|
||||||
|
from orgs.utils import current_org
|
||||||
|
|
||||||
|
|
||||||
class SwitchOrgView(DetailView):
|
class SwitchOrgView(DetailView):
|
||||||
|
@ -22,17 +23,28 @@ class SwitchOrgView(DetailView):
|
||||||
return redirect(reverse('index'))
|
return redirect(reverse('index'))
|
||||||
if UUID_PATTERN.search(referer):
|
if UUID_PATTERN.search(referer):
|
||||||
return redirect(reverse('index'))
|
return redirect(reverse('index'))
|
||||||
|
# 组织管理员切换到组织审计员时(403)
|
||||||
|
if not self.object.get_org_admins().filter(id=request.user.id):
|
||||||
|
return redirect(reverse('index'))
|
||||||
return redirect(referer)
|
return redirect(referer)
|
||||||
|
|
||||||
|
|
||||||
class SwitchToAOrgView(View):
|
class SwitchToAOrgView(View):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
admin_orgs = Organization.get_user_admin_orgs(request.user)
|
if request.user.is_common_user:
|
||||||
if not admin_orgs:
|
|
||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
admin_orgs = request.user.admin_orgs
|
||||||
|
audit_orgs = request.user.audit_orgs
|
||||||
default_org = Organization.default()
|
default_org = Organization.default()
|
||||||
if default_org in admin_orgs:
|
if admin_orgs:
|
||||||
redirect_org = default_org
|
if default_org in admin_orgs:
|
||||||
else:
|
redirect_org = default_org
|
||||||
redirect_org = admin_orgs[0]
|
else:
|
||||||
return redirect(reverse('orgs:org-switch', kwargs={'pk': redirect_org.id}))
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
users_field = self.fields.get('users')
|
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:
|
if self.data:
|
||||||
return
|
return
|
||||||
|
|
|
@ -19,7 +19,7 @@ class RemoteAppPermissionCreateUpdateForm(OrgModelForm):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
users_field = self.fields.get('users')
|
users_field = self.fields.get('users')
|
||||||
if hasattr(users_field, 'queryset'):
|
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:
|
class Meta:
|
||||||
model = RemoteAppPermission
|
model = RemoteAppPermission
|
||||||
|
|
|
@ -131,16 +131,15 @@ class AssetPermissionUserView(PermissionsMixin,
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
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 = {
|
context = {
|
||||||
'app': _('Perms'),
|
'app': _('Perms'),
|
||||||
'action': _('Asset permission user list'),
|
'action': _('Asset permission user list'),
|
||||||
'users_remain': current_org.get_org_users().exclude(
|
'users_remain': user_remain,
|
||||||
assetpermission=self.object
|
'user_groups_remain': user_groups_remain,
|
||||||
),
|
|
||||||
'user_groups_remain': UserGroup.objects.exclude(
|
|
||||||
assetpermission=self.object
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -107,15 +107,15 @@ class RemoteAppPermissionUserView(PermissionsMixin,
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
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 = {
|
context = {
|
||||||
'app': _('Perms'),
|
'app': _('Perms'),
|
||||||
'action': _('RemoteApp permission user list'),
|
'action': _('RemoteApp permission user list'),
|
||||||
'users_remain': current_org.get_org_users().exclude(
|
'users_remain': user_remain,
|
||||||
remoteapppermission=self.object
|
'user_groups_remain': user_groups_remain,
|
||||||
),
|
|
||||||
'user_groups_remain': UserGroup.objects.exclude(
|
|
||||||
remoteapppermission=self.object
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu animated fadeInRight m-t-xs profile-dropdown">
|
<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>
|
<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' %}
|
{% 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>
|
<li><a id="switch_admin"><i class="fa fa-exchange"></i><span> {% trans 'Admin page' %}</span></a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -107,3 +107,23 @@
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="sidebar-collapse">
|
||||||
<ul class="nav" id="side-menu">
|
<ul class="nav" id="side-menu">
|
||||||
{% include '_user_profile.html' %}
|
{% include '_user_profile.html' %}
|
||||||
{% if request.user.is_org_admin and request.COOKIES.IN_ADMIN_PAGE != "No" %}
|
{% if request.user.is_common_user or request.COOKIES.IN_ADMIN_PAGE == 'No' %}
|
||||||
{% include '_nav.html' %}
|
|
||||||
{% elif request.user.is_auditor %}
|
|
||||||
{% include '_nav_audits.html' %}
|
|
||||||
{% else %}
|
|
||||||
{% include '_nav_user.html' %}
|
{% include '_nav_user.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% include '_nav.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,127 +1,172 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<li id="index">
|
|
||||||
<a href="{% url 'index' %}">
|
{# Index #}
|
||||||
<i class="fa fa-dashboard" style="width: 14px"></i> <span class="nav-label">{% trans 'Dashboard' %}</span>
|
{% if request.user.can_admin_or_audit_current_org %}
|
||||||
<span class="label label-info pull-right"></span>
|
<li id="index">
|
||||||
</a>
|
<a href="{% url 'index' %}">
|
||||||
</li>
|
<i class="fa fa-dashboard" style="width: 14px"></i> <span class="nav-label">{% trans 'Dashboard' %}</span>
|
||||||
<li id="users">
|
<span class="label label-info pull-right"></span>
|
||||||
<a href="#">
|
</a>
|
||||||
<i class="fa fa-group" style="width: 14px"></i> <span class="nav-label">{% trans 'Users' %}</span><span class="fa arrow"></span>
|
</li>
|
||||||
</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>
|
|
||||||
{% endif %}
|
{% 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>
|
{# Users #}
|
||||||
<ul class="nav nav-second-level">
|
{% if request.user.can_admin_current_org %}
|
||||||
<li id="asset-permission">
|
<li id="users">
|
||||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a>
|
<a href="#">
|
||||||
</li>
|
<i class="fa fa-group" style="width: 14px"></i> <span class="nav-label">{% trans 'Users' %}</span><span class="fa arrow"></span>
|
||||||
{% if LICENSE_VALID %}
|
</a>
|
||||||
<li id="remote-app-permission">
|
<ul class="nav nav-second-level active">
|
||||||
<a href="{% url 'perms:remote-app-permission-list' %}">{% trans 'RemoteApp' %}</a>
|
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User list' %}</a></li>
|
||||||
</li>
|
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li>
|
||||||
{% endif %}
|
</ul>
|
||||||
</ul>
|
</li>
|
||||||
</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>
|
|
||||||
{% endif %}
|
{% 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 %}
|
{% if request.user.is_superuser %}
|
||||||
<li id="settings">
|
<li id="settings">
|
||||||
<a href="{% url 'settings:basic-setting' %}">
|
<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>
|
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<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">
|
<div class="logo-element">
|
||||||
<img alt="image" height="40" src="{{ LOGO_URL }}"/>
|
<img alt="image" height="40" src="{{ LOGO_URL }}"/>
|
||||||
</div>
|
</div>
|
||||||
{% if ADMIN_ORGS and request.COOKIES.IN_ADMIN_PAGE != 'No' %}
|
{% if ADMIN_OR_AUDIT_ORGS and request.COOKIES.IN_ADMIN_PAGE != 'No' %}
|
||||||
{% if ADMIN_ORGS|length > 1 or not CURRENT_ORG.is_default %}
|
{% if ADMIN_OR_AUDIT_ORGS|length > 1 or not CURRENT_ORG.is_default %}
|
||||||
<div>
|
<div>
|
||||||
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" style="display: block; background-color: transparent; color: #8095a8; padding: 14px 20px 14px 25px">
|
<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>
|
<i class="fa fa-bookmark" style="width: 14px; "></i>
|
||||||
<span class="nav-label" style="padding-left: 7px">
|
<span class="nav-label" style="padding-left: 7px">
|
||||||
{{ CURRENT_ORG.name }}
|
{{ CURRENT_ORG.name }}
|
||||||
</span>
|
</span>
|
||||||
<span class="fa fa-sort-desc pull-right"></span>
|
<span class="fa fa-sort-desc pull-right"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" style="min-width: 220px">
|
<ul class="dropdown-menu" style="min-width: 220px">
|
||||||
{% for org in ADMIN_ORGS %}
|
{% for org in ADMIN_OR_AUDIT_ORGS %}
|
||||||
<li>
|
<li>
|
||||||
<a class="org-dropdown" href="{% url 'orgs:org-switch' pk=org.id %}" data-id="{{ org.id }}">
|
<a class="org-dropdown" href="{% url 'orgs:org-switch' pk=org.id %}" data-id="{{ org.id }}">
|
||||||
{{ org.name }}
|
{{ org.name }}
|
||||||
{% if org.id == CURRENT_ORG.id %}
|
{% if org.id == CURRENT_ORG.id %}
|
||||||
<span class="fa fa-circle" style="padding-top: 5px; color: #1ab394"></span>
|
<span class="fa fa-circle" style="padding-top: 5px; color: #1ab394"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</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 django.template import loader
|
||||||
|
|
||||||
|
|
||||||
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
|
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from ..backends import (
|
from ..backends import (
|
||||||
get_command_storage, get_multi_command_storage,
|
get_command_storage, get_multi_command_storage,
|
||||||
|
@ -22,7 +22,7 @@ __all__ = ['CommandViewSet', 'CommandExportApi']
|
||||||
|
|
||||||
class CommandQueryMixin:
|
class CommandQueryMixin:
|
||||||
command_store = get_command_storage()
|
command_store = get_command_storage()
|
||||||
permission_classes = [IsOrgAdminOrAppUser | IsAuditor]
|
permission_classes = [IsOrgAdminOrAppUser | IsOrgAuditor]
|
||||||
filter_fields = [
|
filter_fields = [
|
||||||
"asset", "system_user", "user", "session",
|
"asset", "system_user", "user", "session",
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,7 +12,7 @@ from rest_framework.generics import GenericAPIView
|
||||||
import jms_storage
|
import jms_storage
|
||||||
|
|
||||||
from common.utils import is_uuid, get_logger
|
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 common.filters import DatetimeRangeFilter
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from ..hands import SystemUser
|
from ..hands import SystemUser
|
||||||
|
@ -27,7 +27,7 @@ logger = get_logger(__name__)
|
||||||
class SessionViewSet(OrgBulkModelViewSet):
|
class SessionViewSet(OrgBulkModelViewSet):
|
||||||
queryset = Session.objects.all()
|
queryset = Session.objects.all()
|
||||||
serializer_class = serializers.SessionSerializer
|
serializer_class = serializers.SessionSerializer
|
||||||
permission_classes = (IsOrgAdminOrAppUser | IsAuditor, )
|
permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor, )
|
||||||
filter_fields = [
|
filter_fields = [
|
||||||
"user", "asset", "system_user", "remote_addr",
|
"user", "asset", "system_user", "remote_addr",
|
||||||
"protocol", "terminal", "is_finished",
|
"protocol", "terminal", "is_finished",
|
||||||
|
@ -62,7 +62,7 @@ class SessionViewSet(OrgBulkModelViewSet):
|
||||||
|
|
||||||
class SessionReplayViewSet(viewsets.ViewSet):
|
class SessionReplayViewSet(viewsets.ViewSet):
|
||||||
serializer_class = serializers.ReplaySerializer
|
serializer_class = serializers.ReplaySerializer
|
||||||
permission_classes = (IsOrgAdminOrAppUser | IsAuditor,)
|
permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor,)
|
||||||
session = None
|
session = None
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
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.translation import ugettext as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
|
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
|
||||||
|
|
||||||
__all__ = ['CommandListView']
|
__all__ = ['CommandListView']
|
||||||
|
|
||||||
|
|
||||||
class CommandListView(PermissionsMixin, TemplateView):
|
class CommandListView(PermissionsMixin, TemplateView):
|
||||||
template_name = "terminal/command_list.html"
|
template_name = "terminal/command_list.html"
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
default_days_ago = 5
|
default_days_ago = 5
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.conf import settings
|
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 common.mixins import DatetimeSearchMixin
|
||||||
from ..models import Session, Command, Terminal
|
from ..models import Session, Command, Terminal
|
||||||
from ..backends import get_multi_command_storage
|
from ..backends import get_multi_command_storage
|
||||||
|
@ -24,7 +24,7 @@ class SessionListView(PermissionsMixin, TemplateView):
|
||||||
model = Session
|
model = Session
|
||||||
template_name = 'terminal/session_list.html'
|
template_name = 'terminal/session_list.html'
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
default_days_ago = 5
|
default_days_ago = 5
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -63,7 +63,7 @@ class SessionDetailView(SingleObjectMixin, PermissionsMixin, ListView):
|
||||||
template_name = 'terminal/session_detail.html'
|
template_name = 'terminal/session_detail.html'
|
||||||
model = Session
|
model = Session
|
||||||
object = None
|
object = None
|
||||||
permission_classes = [IsOrgAdmin | IsAuditor]
|
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object(queryset=self.model.objects.all())
|
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 import generics
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.serializers import ValidationError
|
|
||||||
from rest_framework_bulk import BulkModelViewSet
|
from rest_framework_bulk import BulkModelViewSet
|
||||||
|
|
||||||
from common.permissions import (
|
from common.permissions import (
|
||||||
IsOrgAdmin, IsCurrentUserOrReadOnly, IsOrgAdminOrAppUser,
|
IsOrgAdmin, IsCurrentUserOrReadOnly, IsOrgAdminOrAppUser,
|
||||||
CanUpdateDeleteSuperUser,
|
CanUpdateDeleteUser,
|
||||||
)
|
)
|
||||||
from common.mixins import IDInCacheFilterMixin
|
from common.mixins import IDInCacheFilterMixin
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
@ -36,7 +35,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
|
||||||
search_fields = filter_fields
|
search_fields = filter_fields
|
||||||
queryset = User.objects.exclude(role=User.ROLE_APP)
|
queryset = User.objects.exclude(role=User.ROLE_APP)
|
||||||
serializer_class = serializers.UserSerializer
|
serializer_class = serializers.UserSerializer
|
||||||
permission_classes = (IsOrgAdmin, CanUpdateDeleteSuperUser)
|
permission_classes = (IsOrgAdmin, CanUpdateDeleteUser)
|
||||||
|
|
||||||
def send_created_signal(self, users):
|
def send_created_signal(self, users):
|
||||||
if not isinstance(users, list):
|
if not isinstance(users, list):
|
||||||
|
@ -53,7 +52,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
|
||||||
self.send_created_signal(users)
|
self.send_created_signal(users)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = current_org.get_org_users().prefetch_related('groups')
|
queryset = current_org.get_org_members().prefetch_related('groups')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
|
@ -61,32 +60,17 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
|
||||||
self.permission_classes = (IsOrgAdminOrAppUser,)
|
self.permission_classes = (IsOrgAdminOrAppUser,)
|
||||||
return super().get_permissions()
|
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):
|
def allow_bulk_destroy(self, qs, filtered):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def perform_bulk_update(self, serializer):
|
def perform_bulk_update(self, serializer):
|
||||||
users_ids = [d.get("id") or d.get("pk") for d in serializer.validated_data]
|
# TODO: 需要测试
|
||||||
users = User.objects.filter(id__in=users_ids)
|
users_ids = [
|
||||||
deny_instances = [str(i.id) for i in users if self._deny_permission(i)]
|
d.get("id") or d.get("pk") for d in serializer.validated_data
|
||||||
if deny_instances:
|
]
|
||||||
msg = "{} can't be update".format(deny_instances)
|
users = current_org.get_org_members().filter(id__in=users_ids)
|
||||||
raise ValidationError({"id": msg})
|
for user in users:
|
||||||
|
self.check_object_permissions(self.request, user)
|
||||||
return super().perform_bulk_update(serializer)
|
return super().perform_bulk_update(serializer)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,7 @@ class UserGroupForm(OrgModelForm):
|
||||||
return
|
return
|
||||||
users_field = self.fields.get('users')
|
users_field = self.fields.get('users')
|
||||||
if hasattr(users_field, 'queryset'):
|
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):
|
def save(self, commit=True):
|
||||||
group = super().save(commit=commit)
|
group = super().save(commit=commit)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import uuid
|
||||||
import base64
|
import base64
|
||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.hashers import make_password
|
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.utils import timezone
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
|
|
||||||
|
from orgs.utils import current_org
|
||||||
from common.utils import get_signer, date_expired_default, get_logger
|
from common.utils import get_signer, date_expired_default, get_logger
|
||||||
from common import fields
|
from common import fields
|
||||||
|
|
||||||
|
@ -132,7 +132,16 @@ class RoleMixin:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def role_display(self):
|
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
|
@property
|
||||||
def is_superuser(self):
|
def is_superuser(self):
|
||||||
|
@ -149,26 +158,14 @@ class RoleMixin:
|
||||||
self.role = 'User'
|
self.role = 'User'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def admin_orgs(self):
|
def is_super_auditor(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):
|
|
||||||
return self.role == 'Auditor'
|
return self.role == 'Auditor'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_common_user(self):
|
def is_common_user(self):
|
||||||
if self.is_org_admin:
|
if self.is_org_admin:
|
||||||
return False
|
return False
|
||||||
if self.is_auditor:
|
if self.is_org_auditor:
|
||||||
return False
|
return False
|
||||||
if self.is_app:
|
if self.is_app:
|
||||||
return False
|
return False
|
||||||
|
@ -178,6 +175,52 @@ class RoleMixin:
|
||||||
def is_app(self):
|
def is_app(self):
|
||||||
return self.role == 'App'
|
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
|
@property
|
||||||
def is_staff(self):
|
def is_staff(self):
|
||||||
if self.is_authenticated and self.is_valid:
|
if self.is_authenticated and self.is_valid:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
import copy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
@ -8,6 +9,7 @@ from common.utils import validate_ssh_public_key
|
||||||
from common.mixins import BulkSerializerMixin
|
from common.mixins import BulkSerializerMixin
|
||||||
from common.fields import StringManyToManyField
|
from common.fields import StringManyToManyField
|
||||||
from common.serializers import AdaptedBulkListSerializer
|
from common.serializers import AdaptedBulkListSerializer
|
||||||
|
from common.permissions import CanUpdateDeleteUser
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
from ..models import User, UserGroup
|
from ..models import User, UserGroup
|
||||||
|
|
||||||
|
@ -22,6 +24,9 @@ __all__ = [
|
||||||
|
|
||||||
class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
|
can_update = serializers.SerializerMethodField()
|
||||||
|
can_delete = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
list_serializer_class = AdaptedBulkListSerializer
|
list_serializer_class = AdaptedBulkListSerializer
|
||||||
|
@ -32,6 +37,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
'comment', 'source', 'source_display', 'is_valid', 'is_expired',
|
'comment', 'source', 'source_display', 'is_valid', 'is_expired',
|
||||||
'is_active', 'created_by', 'is_first_login',
|
'is_active', 'created_by', 'is_first_login',
|
||||||
'date_password_last_updated', 'date_expired', 'avatar_url',
|
'date_password_last_updated', 'date_expired', 'avatar_url',
|
||||||
|
'can_update', 'can_delete',
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'password': {'write_only': True, 'required': False, 'allow_null': True, 'allow_blank': True},
|
'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_valid': {'label': _('Is valid')},
|
||||||
'is_expired': {'label': _('Is expired')},
|
'is_expired': {'label': _('Is expired')},
|
||||||
'avatar_url': {'label': _('Avatar url')},
|
'avatar_url': {'label': _('Avatar url')},
|
||||||
'created_by': {'read_only': True, 'allow_blank': True},
|
|
||||||
'source': {'read_only': 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):
|
def validate_role(self, value):
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
if not request.user.is_superuser and value != User.ROLE_USER:
|
if not request.user.is_superuser and value != User.ROLE_USER:
|
||||||
|
@ -67,20 +85,24 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
return password
|
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
|
@staticmethod
|
||||||
def change_password_to_raw(validated_data):
|
def change_password_to_raw(attrs):
|
||||||
password = validated_data.pop('password', None)
|
password = attrs.pop('password', None)
|
||||||
if password:
|
if password:
|
||||||
validated_data['password_raw'] = password
|
attrs['password_raw'] = password
|
||||||
return validated_data
|
return attrs
|
||||||
|
|
||||||
def create(self, validated_data):
|
def validate(self, attrs):
|
||||||
validated_data = self.change_password_to_raw(validated_data)
|
attrs = self.change_password_to_raw(attrs)
|
||||||
return super().create(validated_data)
|
return attrs
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
|
||||||
validated_data = self.change_password_to_raw(validated_data)
|
|
||||||
return super().update(instance, validated_data)
|
|
||||||
|
|
||||||
|
|
||||||
class UserPKUpdateSerializer(serializers.ModelSerializer):
|
class UserPKUpdateSerializer(serializers.ModelSerializer):
|
||||||
|
@ -119,6 +141,13 @@ class UserGroupSerializer(BulkOrgResourceModelSerializer):
|
||||||
'created_by': {'label': _('Created by'), 'read_only': True}
|
'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):
|
class UserGroupListSerializer(UserGroupSerializer):
|
||||||
users = StringManyToManyField(many=True, read_only=True)
|
users = StringManyToManyField(many=True, read_only=True)
|
||||||
|
|
|
@ -61,6 +61,17 @@
|
||||||
<link rel="stylesheet" type="text/css" href={% static "css/plugins/daterangepicker/daterangepicker.css" %} />
|
<link rel="stylesheet" type="text/css" href={% static "css/plugins/daterangepicker/daterangepicker.css" %} />
|
||||||
|
|
||||||
<script>
|
<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 = {
|
var dateOptions = {
|
||||||
singleDatePicker: true,
|
singleDatePicker: true,
|
||||||
showDropdowns: true,
|
showDropdowns: true,
|
||||||
|
@ -76,7 +87,10 @@
|
||||||
$('#id_date_expired').daterangepicker(dateOptions);
|
$('#id_date_expired').daterangepicker(dateOptions);
|
||||||
var mfa_radio = $('#id_otp_level');
|
var mfa_radio = $('#id_otp_level');
|
||||||
mfa_radio.addClass("form-inline");
|
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>
|
</script>
|
||||||
{% endblock %}
|
{% 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>
|
<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>
|
||||||
<li class="pull-right">
|
<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>
|
||||||
|
|
||||||
<li class="pull-right">
|
<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' %}
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Role' %}:</td>
|
<td>{% trans 'Role' %}:</td>
|
||||||
<td><b>{{ user_object.get_role_display }}</b></td>
|
<td><b>{{ user_object.role_display }}</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'MFA certification' %}:</td>
|
<td>{% trans 'MFA certification' %}:</td>
|
||||||
|
@ -212,44 +212,46 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-info">
|
{% if user_object.is_current_org_admin %}
|
||||||
<div class="panel-heading">
|
<div class="panel panel-info">
|
||||||
<i class="fa fa-info-circle"></i> {% trans 'User group' %}
|
<div class="panel-heading">
|
||||||
</div>
|
<i class="fa fa-info-circle"></i> {% trans 'User group' %}
|
||||||
<div class="panel-body">
|
</div>
|
||||||
<table class="table group_edit">
|
<div class="panel-body">
|
||||||
<tbody>
|
<table class="table group_edit">
|
||||||
<form>
|
<tbody>
|
||||||
<tr>
|
<form>
|
||||||
<td colspan="2" class="no-borders">
|
<tr>
|
||||||
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
|
<td colspan="2" class="no-borders">
|
||||||
{% for group in groups %}
|
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||||
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
|
{% for group in groups %}
|
||||||
{% endfor %}
|
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
</td>
|
</select>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td colspan="2" class="no-borders">
|
<tr>
|
||||||
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
|
<td colspan="2" class="no-borders">
|
||||||
</td>
|
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
|
||||||
</tr>
|
</td>
|
||||||
</form>
|
</tr>
|
||||||
|
</form>
|
||||||
|
|
||||||
{% for group in user_object.groups.all %}
|
{% for group in user_object.groups.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td >
|
<td >
|
||||||
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
|
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
|
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -99,7 +99,7 @@ function initTable() {
|
||||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||||
var name = htmlEscape(rowData.name);
|
var name = htmlEscape(rowData.name);
|
||||||
var update_btn = "";
|
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>';
|
update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>';
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
@ -107,7 +107,7 @@ function initTable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var del_btn = "";
|
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>'
|
del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
|
||||||
.replace('{{ DEFAULT_PK }}', cellData)
|
.replace('{{ DEFAULT_PK }}', cellData)
|
||||||
.replace('99991938', name);
|
.replace('99991938', name);
|
||||||
|
|
|
@ -76,7 +76,8 @@ class UserGroupDetailView(PermissionsMixin, DetailView):
|
||||||
permission_classes = [IsOrgAdmin]
|
permission_classes = [IsOrgAdmin]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
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 = {
|
context = {
|
||||||
'app': _('Users'),
|
'app': _('Users'),
|
||||||
'action': _('User group detail'),
|
'action': _('User group detail'),
|
||||||
|
|
|
@ -27,6 +27,7 @@ from common.utils import get_logger, ssh_key_gen
|
||||||
from common.permissions import (
|
from common.permissions import (
|
||||||
PermissionsMixin, IsOrgAdmin, IsValidUser,
|
PermissionsMixin, IsOrgAdmin, IsValidUser,
|
||||||
UserCanUpdatePassword, UserCanUpdateSSHKey,
|
UserCanUpdatePassword, UserCanUpdateSSHKey,
|
||||||
|
CanUpdateDeleteUser,
|
||||||
)
|
)
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
from .. import forms
|
from .. import forms
|
||||||
|
@ -86,7 +87,7 @@ class UserCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
|
||||||
user.created_by = self.request.user.username or 'System'
|
user.created_by = self.request.user.username or 'System'
|
||||||
user.save()
|
user.save()
|
||||||
if current_org and current_org.is_real():
|
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)
|
post_user_create.send(self.__class__, user=user)
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
@ -189,13 +190,19 @@ class UserDetailView(PermissionsMixin, DetailView):
|
||||||
'action': _('User detail'),
|
'action': _('User detail'),
|
||||||
'groups': groups,
|
'groups': groups,
|
||||||
'unblock': is_need_unblock(key_block),
|
'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)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
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)
|
queryset = queryset.filter(id__in=org_users)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue