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

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

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

* [Update] 修改小问题

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

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

* [Update] 修改小问题

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

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

* [Update] 优化逻辑

* [Update] 优化类名

* [Update] 修改小问题

* [Update] 优化逻辑

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

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

* [Update] 优化代码

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

* [Update] 优化代码细节

* [Update] 优化权限类逻辑

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

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

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

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

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

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

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

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

* [Update] 修改方法命名

* [Update] 优化代码细节

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

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

* [Update] 修改OrgProcessor Anonymous问题

* [Update] 修改用户序列类校验组织和转换raw密码的逻辑
parent 5f23c358
...@@ -3,7 +3,7 @@ ...@@ -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 ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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
def has_delete_object_permission(request, view, obj):
if not request.user.can_admin_current_org:
return False
# 超级管理员 / 组织管理员
if str(request.user.id) == str(obj.id):
return False
# 超级管理员
if request.user.is_superuser:
if obj.is_superuser and obj.username in ['admin']:
return False
return True return True
elif request.method == 'DELETE' and str(request.user.id) == str(obj.id): # 组织管理员
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 return False
elif request.user.is_superuser: 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 return True
if hasattr(obj, 'is_superuser') and obj.is_superuser: # 超级管理员
if request.user.is_superuser:
return True
# 组织管理员
if obj.is_superuser:
return False
if obj.is_super_auditor:
return False
if obj.is_org_admin:
return False
if len(obj.audit_orgs) > 1:
return False
if len(obj.user_orgs) > 1:
return False
return True
def has_object_permission(self, request, view, obj):
if not request.user.can_admin_current_org:
return False 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 return True
...@@ -34,17 +34,13 @@ class IndexView(PermissionsMixin, TemplateView): ...@@ -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): ...@@ -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): ...@@ -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 @@ ...@@ -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'] ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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: ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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>
......
{% 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> {% endif %}
<ul class="nav nav-second-level active">
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User list' %}</a></li> {# Users #}
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li> {% if request.user.can_admin_current_org %}
</ul> <li id="users">
</li> <a href="#">
<li id="assets"> <i class="fa fa-group" style="width: 14px"></i> <span class="nav-label">{% trans 'Users' %}</span><span class="fa arrow"></span>
<a> </a>
<i class="fa fa-inbox" style="width: 14px"></i> <span class="nav-label">{% trans 'Assets' %}</span><span class="fa arrow"></span> <ul class="nav nav-second-level active">
</a> <li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User list' %}</a></li>
<ul class="nav nav-second-level"> <li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li>
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset list' %}</a></li> </ul>
<li id="domain"><a href="{% url 'assets:domain-list' %}">{% trans 'Domain list' %}</a></li> </li>
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li> {% endif %}
<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> {# User info #}
<li id="cmd-filter"><a href="{% url 'assets:cmd-filter-list' %}">{% trans 'Command filters' %}</a></li> {% if not request.user.can_admin_current_org and request.user.can_audit_current_org %}
</ul> <li id="users">
</li> <a href="{% url 'users:user-profile' %}">
{% if LICENSE_VALID %} <i class="fa fa-user" style="width: 14px"></i> <span class="nav-label">{% trans 'Profile' %}</span><span class="label label-info pull-right"></span>
<li id="applications"> </a>
<a> </li>
<i class="fa fa-th" style="width: 14px"></i> <span class="nav-label">{% trans 'Applications' %}</span><span class="fa arrow"></span> {% endif %}
</a>
<ul class="nav nav-second-level"> {# Assets #}
<li id="remote-app"><a href="{% url 'applications:remote-app-list' %}">{% trans 'RemoteApp' %}</a></li> {% if request.user.can_admin_current_org %}
</ul> <li id="assets">
</li> <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 %} {% 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"> {# Applications #}
<li id="asset-permission"> {% if request.user.can_admin_current_org and LICENSE_VALID %}
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a> <li id="applications">
</li> <a>
{% if LICENSE_VALID %} <i class="fa fa-th" style="width: 14px"></i> <span class="nav-label">{% trans 'Applications' %}</span><span class="fa arrow"></span>
<li id="remote-app-permission"> </a>
<a href="{% url 'perms:remote-app-permission-list' %}">{% trans 'RemoteApp' %}</a> <ul class="nav nav-second-level">
</li> <li id="remote-app"><a href="{% url 'applications:remote-app-list' %}">{% trans 'RemoteApp' %}</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 %}
{# 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>
......
{% load i18n %}
<li id="index">
<a href="{% url 'index' %}">
<i class="fa fa-dashboard" style="width: 14px"></i> <span class="nav-label">{% trans 'Dashboard' %}</span>
<span class="label label-info pull-right"></span>
</a>
</li>
<li id="terminal">
<a>
<i class="fa fa-rocket" style="width: 14px"></i> <span class="nav-label">{% trans 'Sessions' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="session-online"><a href="{% url 'terminal:session-online-list' %}">{% trans 'Session online' %}</a></li>
<li id="session-offline"><a href="{% url 'terminal:session-offline-list' %}">{% trans 'Session offline' %}</a></li>
<li id="command"><a href="{% url 'terminal:command-list' %}">{% trans 'Commands' %}</a></li>
</ul>
</li>
<li id="audits">
<a>
<i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li id="login-log"><a href="{% url 'audits:login-log-list' %}">{% trans 'Login log' %}</a></li>
<li id="ftp-log"><a href="{% url 'audits:ftp-log-list' %}">{% trans 'FTP log' %}</a></li>
<li id="operate-log"><a href="{% url 'audits:operate-log-list' %}">{% trans 'Operate log' %}</a></li>
<li id="password-change-log"><a href="{% url 'audits:password-change-log-list' %}">{% trans 'Password change log' %}</a></li>
<li id="command-execution-log"><a href="{% url 'audits:command-execution-log-list' %}">{% trans 'Batch command' %}</a></li>
</ul>
</li>
\ No newline at end of file
...@@ -9,49 +9,29 @@ ...@@ -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 ...@@ -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'] ...@@ -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 ...@@ -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__) ...@@ -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): ...@@ -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 ...@@ -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 _ ...@@ -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): ...@@ -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): ...@@ -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 _ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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 _ ...@@ -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: ...@@ -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):
...@@ -148,35 +157,69 @@ class RoleMixin: ...@@ -148,35 +157,69 @@ class RoleMixin:
else: else:
self.role = 'User' self.role = 'User'
@property
def is_super_auditor(self):
return self.role == 'Auditor'
@property
def is_common_user(self):
if self.is_org_admin:
return False
if self.is_org_auditor:
return False
if self.is_app:
return False
return True
@property
def is_app(self):
return self.role == 'App'
@property
def user_orgs(self):
from orgs.models import Organization
return Organization.get_user_user_orgs(self)
@property @property
def admin_orgs(self): def admin_orgs(self):
from orgs.models import Organization from orgs.models import Organization
return Organization.get_user_admin_orgs(self) 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 @property
def is_org_admin(self): def is_org_admin(self):
if self.is_superuser or self.admin_orgs.exists(): if self.is_superuser or self.related_admin_orgs.exists():
return True return True
else: else:
return False return False
@property @property
def is_auditor(self): def is_org_auditor(self):
return self.role == 'Auditor' if self.is_super_auditor or self.related_audit_orgs.exists():
return True
else:
return False
@property @property
def is_common_user(self): def can_admin_current_org(self):
if self.is_org_admin: return current_org.can_admin_by(self)
return False
if self.is_auditor:
return False
if self.is_app:
return False
return True
@property @property
def is_app(self): def can_audit_current_org(self):
return self.role == 'App' 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):
......
# -*- 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 ...@@ -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__ = [ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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)
...@@ -140,4 +169,4 @@ class ChangeUserPasswordSerializer(serializers.ModelSerializer): ...@@ -140,4 +169,4 @@ class ChangeUserPasswordSerializer(serializers.ModelSerializer):
class ResetOTPSerializer(serializers.Serializer): class ResetOTPSerializer(serializers.Serializer):
msg = serializers.CharField(read_only=True) msg = serializers.CharField(read_only=True)
\ No newline at end of file
...@@ -61,6 +61,17 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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() { ...@@ -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() { ...@@ -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): ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment