Compare commits

...

20 Commits

Author SHA1 Message Date
feng626
9560c4b05d fix: 修复用户数据不同步问题 2022-04-08 15:44:10 +08:00
Jiangjie.Bai
81a5febfbc fix: 添加用户不能自更新字段逻辑 & 修复用户is_active创建失败的问题
fix: 添加用户不能自更新字段逻辑 & 修复用户is_active创建失败的问题

fix: 添加用户不能自更新字段逻辑 & 修复用户is_active创建失败的问题
2022-03-30 19:45:31 +08:00
ibuler
a09a59e7b3 perf: 优化 perms 缓存刷新 2022-03-22 18:58:30 +08:00
Jiangjie.Bai
a7d0e3ce70 fix: 修复获取远程应用认证信息问题 2022-03-22 18:54:50 +08:00
ibuler
6f762d7198 fix: 修复权限 view 没有 Model 的问题 2022-03-22 16:57:00 +08:00
feng626
ddbcbb0d66 fix: 修复用户绑定角色重大bug 2022-03-22 16:55:15 +08:00
feng626
a1976e4f0b fix: api docs 2022-03-22 13:05:27 +08:00
ibuler
0eeb1e6f6d perf: 去掉导入的 trans 2022-03-21 19:25:51 +08:00
ibuler
ae5487720c perf: 去掉注释 2022-03-21 19:25:51 +08:00
ibuler
0d8386359e perf: 修复创建 superuser 错误 2022-03-21 19:25:51 +08:00
fit2bot
d338e53862 fix: 修复wateway api (#7948)
Co-authored-by: feng626 <1304903146@qq.com>
2022-03-21 17:52:27 +08:00
Jiangjie.Bai
441c6a7f60 fix: 修复用户API权限 2022-03-21 11:59:59 +08:00
Jiangjie.Bai
79a40f7ded fix: 修复用户API权限 2022-03-21 11:56:50 +08:00
fit2bot
b9c221c856 fix: 修复api docs打不开的问题 (#7939)
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2022-03-21 11:14:29 +08:00
Jiangjie.Bai
f6dada03bf fix: 应用树隐藏mongodb节点 2022-03-18 18:02:39 +08:00
fit2bot
d3d18b8f48 perf: org del ticket perm (#7933)
Co-authored-by: feng626 <1304903146@qq.com>
2022-03-18 17:44:39 +08:00
Jiangjie.Bai
a2f23c2d81 fix: 工单权限位放到sys角色中 2022-03-18 17:36:03 +08:00
Jiangjie.Bai
f0df23a15a fix: 移除权限dashboard 2022-03-18 17:10:17 +08:00
fit2bot
a6a4bb1c7d fix: apikey perm (#7919)
Co-authored-by: feng626 <1304903146@qq.com>
2022-03-18 15:53:10 +08:00
Jiangjie.Bai
9ac3c6b120 fix: 修复去除rolebiding change 权限 2022-03-18 15:38:15 +08:00
17 changed files with 134 additions and 40 deletions

View File

@@ -8,6 +8,7 @@ from django.conf import settings
from orgs.mixins.models import OrgModelMixin from orgs.mixins.models import OrgModelMixin
from common.mixins import CommonModelMixin from common.mixins import CommonModelMixin
from common.tree import TreeNode from common.tree import TreeNode
from common.utils import is_uuid
from assets.models import Asset, SystemUser from assets.models import Asset, SystemUser
from ..utils import KubernetesTree from ..utils import KubernetesTree
@@ -100,6 +101,9 @@ class ApplicationTreeNodeMixin:
type_category_mapper = const.AppType.type_category_mapper() type_category_mapper = const.AppType.type_category_mapper()
types = const.AppType.type_category_mapper().keys() types = const.AppType.type_category_mapper().keys()
for tp in types: for tp in types:
# TODO: Temporary exclude mongodb
if tp == const.AppType.mongodb:
continue
if not settings.XPACK_ENABLED and const.AppType.is_xpack(tp): if not settings.XPACK_ENABLED and const.AppType.is_xpack(tp):
continue continue
category = type_category_mapper.get(tp) category = type_category_mapper.get(tp)
@@ -264,12 +268,12 @@ class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin):
'parameters': parameters 'parameters': parameters
} }
def get_remote_app_asset(self): def get_remote_app_asset(self, raise_exception=True):
asset_id = self.attrs.get('asset') asset_id = self.attrs.get('asset')
if not asset_id: if is_uuid(asset_id):
return Asset.objects.filter(id=asset_id).first()
if raise_exception:
raise ValueError("Remote App not has asset attr") raise ValueError("Remote App not has asset attr")
asset = Asset.objects.filter(id=asset_id).first()
return asset
class ApplicationUser(SystemUser): class ApplicationUser(SystemUser):

View File

@@ -16,7 +16,7 @@ from perms.filters import AssetPermissionFilter
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins import generics from orgs.mixins import generics
from assets.api import FilterAssetByNodeMixin from assets.api import FilterAssetByNodeMixin
from ..models import Asset, Node, Platform from ..models import Asset, Node, Platform, Gateway
from .. import serializers from .. import serializers
from ..tasks import ( from ..tasks import (
update_assets_hardware_info_manual, test_assets_connectivity_manual, update_assets_hardware_info_manual, test_assets_connectivity_manual,
@@ -181,7 +181,7 @@ class AssetsTaskCreateApi(AssetsTaskMixin, generics.CreateAPIView):
def check_permissions(self, request): def check_permissions(self, request):
action = request.data.get('action') action = request.data.get('action')
action_perm_require = { action_perm_require = {
'refresh': 'assets.refresh_assethardwareinfo1', 'refresh': 'assets.refresh_assethardwareinfo',
} }
perm_required = action_perm_require.get(action) perm_required = action_perm_require.get(action)
has = self.request.user.has_perm(perm_required) has = self.request.user.has_perm(perm_required)
@@ -199,7 +199,7 @@ class AssetGatewayListApi(generics.ListAPIView):
asset_id = self.kwargs.get('pk') asset_id = self.kwargs.get('pk')
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
if not asset.domain: if not asset.domain:
return [] return Gateway.objects.none()
queryset = asset.domain.gateways.filter(protocol='ssh') queryset = asset.domain.gateways.filter(protocol='ssh')
return queryset return queryset

View File

@@ -133,6 +133,14 @@ class AuthMixin:
self.password = password self.password = password
def load_app_more_auth(self, app_id=None, username=None, user_id=None): def load_app_more_auth(self, app_id=None, username=None, user_id=None):
from applications.models import Application
app = get_object_or_none(Application, pk=app_id)
if app and app.category_remote_app:
# Remote app
self._load_remoteapp_more_auth(app, username, user_id)
return
# Other app
self._clean_auth_info_if_manual_login_mode() self._clean_auth_info_if_manual_login_mode()
# 加载临时认证信息 # 加载临时认证信息
if self.login_mode == self.LOGIN_MANUAL: if self.login_mode == self.LOGIN_MANUAL:
@@ -148,6 +156,11 @@ class AuthMixin:
_username = username _username = username
self.username = _username self.username = _username
def _load_remoteapp_more_auth(self, app, username, user_id):
asset = app.get_remote_app_asset(raise_exception=False)
if asset:
self.load_asset_more_auth(asset_id=asset.id, username=username, user_id=user_id)
def load_asset_special_auth(self, asset, username=''): def load_asset_special_auth(self, asset, username=''):
""" """
AuthBook 的数据状态 AuthBook 的数据状态

View File

@@ -8,7 +8,6 @@ from .. import serializers
class AccessKeyViewSet(ModelViewSet): class AccessKeyViewSet(ModelViewSet):
permission_classes = (IsValidUser,)
serializer_class = serializers.AccessKeySerializer serializer_class = serializers.AccessKeySerializer
search_fields = ['^id', '^secret'] search_fields = ['^id', '^secret']

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:449810c3661c09f6448b9c67e7a193f303a3bef7ccc3d0f1efe6e099804e782a oid sha256:b1c6c0f9212f9d154a432d93785677ebc206eed4fd4338d3fe11b4b528d65c11
size 104323 size 104323

View File

@@ -2050,7 +2050,7 @@ msgstr "请修改密码"
#: authentication/models.py:33 terminal/serializers/storage.py:30 #: authentication/models.py:33 terminal/serializers/storage.py:30
msgid "Access key" msgid "Access key"
msgstr "Api key" msgstr "API key"
#: authentication/models.py:40 #: authentication/models.py:40
msgid "Private Token" msgid "Private Token"

View File

@@ -1,33 +1,54 @@
from functools import wraps
from django.db.models.signals import post_save, pre_delete, pre_save, post_delete from django.db.models.signals import post_save, pre_delete, pre_save, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from orgs.models import Organization from orgs.models import Organization
from assets.models import Node from assets.models import Node
from perms.models import (AssetPermission, ApplicationPermission) from perms.models import AssetPermission, ApplicationPermission
from users.models import UserGroup, User from users.models import UserGroup, User
from users.signals import pre_user_leave_org
from applications.models import Application from applications.models import Application
from terminal.models import Session from terminal.models import Session
from rbac.models import OrgRoleBinding
from assets.models import Asset, SystemUser, Domain, Gateway from assets.models import Asset, SystemUser, Domain, Gateway
from orgs.caches import OrgResourceStatisticsCache from orgs.caches import OrgResourceStatisticsCache
from common.utils import get_logger
logger = get_logger(__name__)
def refresh_user_amount_on_user_create_or_delete(user_id): def refresh_cache(name, org):
orgs = Organization.objects.filter(m2m_org_members__user_id=user_id).distinct() names = None
if isinstance(name, (str,)):
names = [name, ]
if isinstance(names, (list, tuple)):
for name in names:
OrgResourceStatisticsCache(org).expire(name)
OrgResourceStatisticsCache(Organization.root()).expire(name)
else:
logger.warning('refresh cache fail: {}'.format(name))
def refresh_user_amount_cache(user):
orgs = user.orgs.distinct()
for org in orgs: for org in orgs:
org_cache = OrgResourceStatisticsCache(org) refresh_cache('users_amount', org)
org_cache.expire('users_amount')
OrgResourceStatisticsCache(Organization.root()).expire('users_amount')
@receiver(post_save, sender=User) @receiver(post_save, sender=OrgRoleBinding)
def on_user_create_refresh_cache(sender, instance, created, **kwargs): def on_user_create_or_invite_refresh_cache(sender, instance, created, **kwargs):
if created: if created:
refresh_user_amount_on_user_create_or_delete(instance.id) refresh_cache('users_amount', instance.org)
@receiver(pre_user_leave_org)
def on_user_remove_refresh_cache(sender, org=None, **kwargs):
refresh_cache('users_amount', org)
@receiver(pre_delete, sender=User) @receiver(pre_delete, sender=User)
def on_user_delete_refresh_cache(sender, instance, **kwargs): def on_user_delete_refresh_cache(sender, instance, **kwargs):
refresh_user_amount_on_user_create_or_delete(instance.id) refresh_user_amount_cache(instance)
# @receiver(m2m_changed, sender=OrganizationMember) # @receiver(m2m_changed, sender=OrganizationMember)

View File

@@ -16,7 +16,7 @@ class RBACBackend(JMSBaseAuthBackend):
return False return False
def has_perm(self, user_obj, perm, obj=None): def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active: if not user_obj.is_active or not perm:
raise PermissionDenied() raise PermissionDenied()
if perm == '*': if perm == '*':
return True return True

View File

@@ -22,7 +22,6 @@ exclude_permissions = (
('common', 'setting', '*', '*'), ('common', 'setting', '*', '*'),
('authentication', 'privatetoken', '*', '*'), ('authentication', 'privatetoken', '*', '*'),
('authentication', 'accesskey', 'change,delete', 'accesskey'),
('authentication', 'connectiontoken', 'change,delete', 'connectiontoken'), ('authentication', 'connectiontoken', 'change,delete', 'connectiontoken'),
('authentication', 'ssotoken', '*', '*'), ('authentication', 'ssotoken', '*', '*'),
('authentication', 'superconnectiontoken', 'change,delete', 'superconnectiontoken'), ('authentication', 'superconnectiontoken', 'change,delete', 'superconnectiontoken'),
@@ -49,6 +48,8 @@ exclude_permissions = (
('rbac', 'contenttype', '*', '*'), ('rbac', 'contenttype', '*', '*'),
('rbac', 'permission', 'add,delete,change', 'permission'), ('rbac', 'permission', 'add,delete,change', 'permission'),
('rbac', 'rolebinding', '*', '*'), ('rbac', 'rolebinding', '*', '*'),
('rbac', 'systemrolebinding', 'change', 'systemrolebinding'),
('rbac', 'orgrolebinding', 'change', 'orgrolebinding'),
('rbac', 'role', '*', '*'), ('rbac', 'role', '*', '*'),
('ops', 'adhoc', 'delete,change', '*'), ('ops', 'adhoc', 'delete,change', '*'),
('ops', 'adhocexecution', 'add,delete,change', '*'), ('ops', 'adhocexecution', 'add,delete,change', '*'),
@@ -99,6 +100,7 @@ only_system_permissions = (
('orgs', 'organization', '*', '*'), ('orgs', 'organization', '*', '*'),
('xpack', 'license', '*', '*'), ('xpack', 'license', '*', '*'),
('settings', 'setting', '*', '*'), ('settings', 'setting', '*', '*'),
('tickets', '*', '*', '*'),
('ops', 'task', 'view', 'taskmonitor'), ('ops', 'task', 'view', 'taskmonitor'),
('terminal', 'terminal', '*', '*'), ('terminal', 'terminal', '*', '*'),
('terminal', 'commandstorage', '*', '*'), ('terminal', 'commandstorage', '*', '*'),
@@ -106,6 +108,7 @@ only_system_permissions = (
('terminal', 'status', '*', '*'), ('terminal', 'status', '*', '*'),
('terminal', 'task', '*', '*'), ('terminal', 'task', '*', '*'),
('authentication', '*', '*', '*'), ('authentication', '*', '*', '*'),
('tickets', '*', '*', '*'),
) )
only_org_permissions = ( only_org_permissions = (

View File

@@ -93,7 +93,7 @@ class RBACPermission(permissions.DjangoModelPermissions):
try: try:
queryset = self._queryset(view) queryset = self._queryset(view)
model_cls = queryset.model model_cls = queryset.model
except AssertionError: except:
model_cls = None model_cls = None
return model_cls return model_cls

View File

@@ -87,7 +87,6 @@ special_pid_mapper = {
'terminal.status': 'terminal_node', 'terminal.status': 'terminal_node',
'terminal.task': 'terminal_node', 'terminal.task': 'terminal_node',
'audits.ftplog': 'terminal', 'audits.ftplog': 'terminal',
'rbac.menupermission': 'view_other',
'perms.view_myassets': 'my_assets', 'perms.view_myassets': 'my_assets',
'perms.view_myapps': 'my_apps', 'perms.view_myapps': 'my_apps',
'ops.add_commandexecution': 'view_workspace', 'ops.add_commandexecution': 'view_workspace',

View File

@@ -6,7 +6,7 @@ from common.exceptions import JMSException
from common.utils import lazyproperty from common.utils import lazyproperty
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
from tickets import serializers from tickets import serializers
from tickets.models import Ticket from tickets.models import Ticket, Comment
from tickets.permissions.comment import IsAssignee, IsApplicant, IsSwagger from tickets.permissions.comment import IsAssignee, IsApplicant, IsSwagger
@@ -36,5 +36,7 @@ class CommentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
return context return context
def get_queryset(self): def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Comment.objects.none()
queryset = self.ticket.comments.all() queryset = self.ticket.comments.all()
return queryset return queryset

View File

@@ -108,6 +108,9 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelV
self.check_object_permissions(self.request, user) self.check_object_permissions(self.request, user)
return super().perform_bulk_update(serializer) return super().perform_bulk_update(serializer)
def allow_bulk_destroy(self, qs, filtered):
return filtered.count() < qs.count()
def perform_bulk_destroy(self, objects): def perform_bulk_destroy(self, objects):
for obj in objects: for obj in objects:
self.check_object_permissions(self.request, obj) self.check_object_permissions(self.request, obj)

View File

@@ -22,6 +22,7 @@ from orgs.models import Organization
from common.utils import date_expired_default, get_logger, lazyproperty, random_string from common.utils import date_expired_default, get_logger, lazyproperty, random_string
from common import fields from common import fields
from django.db.models import TextChoices from django.db.models import TextChoices
from rbac.const import Scope
from ..signals import post_user_change_password, post_user_leave_org, pre_user_leave_org from ..signals import post_user_change_password, post_user_leave_org, pre_user_leave_org
__all__ = ['User', 'UserPasswordHistory'] __all__ = ['User', 'UserPasswordHistory']
@@ -204,6 +205,13 @@ class RoleManager(models.Manager):
return return
return self.role_bindings.delete() return self.role_bindings.delete()
def refresh_user_amount_cache(self):
from orgs.signal_handlers.cache import refresh_user_amount_cache, refresh_cache
if current_org.is_root():
refresh_cache('users_amount', current_org)
elif self.scope == Scope.org:
refresh_user_amount_cache(self.user)
def add(self, *roles): def add(self, *roles):
from rbac.models import RoleBinding from rbac.models import RoleBinding
items = [] items = []
@@ -224,6 +232,9 @@ class RoleManager(models.Manager):
RoleBinding.objects.bulk_create(items, ignore_conflicts=True) RoleBinding.objects.bulk_create(items, ignore_conflicts=True)
except Exception as e: except Exception as e:
logger.error('Create role binding error: {}'.format(e)) logger.error('Create role binding error: {}'.format(e))
finally:
self.user.expire_users_rbac_perms_cache()
self.refresh_user_amount_cache()
def set(self, roles): def set(self, roles):
self.clear() self.clear()
@@ -237,16 +248,16 @@ class RoleManager(models.Manager):
class OrgRoleManager(RoleManager): class OrgRoleManager(RoleManager):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from rbac.const import Scope from rbac.const import Scope
self.scope = Scope.org self.scope = Scope.org
super().__init__(*args, **kwargs)
class SystemRoleManager(RoleManager): class SystemRoleManager(RoleManager):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from rbac.const import Scope from rbac.const import Scope
self.scope = Scope.system self.scope = Scope.system
super().__init__(*args, **kwargs)
class RoleMixin: class RoleMixin:
@@ -257,6 +268,8 @@ class RoleMixin:
_org_roles = None _org_roles = None
_system_roles = None _system_roles = None
PERM_CACHE_KEY = 'USER_PERMS_{}_{}' PERM_CACHE_KEY = 'USER_PERMS_{}_{}'
_is_superuser = None
_update_superuser = False
@lazyproperty @lazyproperty
def roles(self): def roles(self):
@@ -288,17 +301,25 @@ class RoleMixin:
key = cls.PERM_CACHE_KEY.format('*', '*') key = cls.PERM_CACHE_KEY.format('*', '*')
cache.delete_pattern(key) cache.delete_pattern(key)
@lazyproperty @property
def is_superuser(self): def is_superuser(self):
""" """
由于这里用了 cache ,所以不能改成 self.system_roles.filter().exists() 会查询的 由于这里用了 cache ,所以不能改成 self.system_roles.filter().exists() 会查询的
""" """
if self._is_superuser is not None:
return self._is_superuser
from rbac.builtin import BuiltinRole from rbac.builtin import BuiltinRole
# return self.system_roles.all().filter(id=BuiltinRole.system_admin.id).exists() # return self.system_roles.all().filter(id=BuiltinRole.system_admin.id).exists()
ids = [str(r.id) for r in self.system_roles.all()] ids = [str(r.id) for r in self.system_roles.all()]
yes = BuiltinRole.system_admin.id in ids yes = BuiltinRole.system_admin.id in ids
self._is_superuser = yes
return yes return yes
@is_superuser.setter
def is_superuser(self, value):
self._is_superuser = value
self._update_superuser = True
@lazyproperty @lazyproperty
def is_org_admin(self): def is_org_admin(self):
from rbac.builtin import BuiltinRole from rbac.builtin import BuiltinRole

View File

@@ -49,6 +49,8 @@ class RolesSerializerMixin(serializers.Serializer):
return fields return fields
action = view.action or 'list' action = view.action or 'list'
if action in ('partial_bulk_update', 'bulk_update', 'partial_update', 'update'):
action = 'create'
model_cls_field_mapper = { model_cls_field_mapper = {
SystemRoleBinding: ['system_roles', 'system_roles_display'], SystemRoleBinding: ['system_roles', 'system_roles_display'],
OrgRoleBinding: ['org_roles', 'system_roles_display'] OrgRoleBinding: ['org_roles', 'system_roles_display']
@@ -130,6 +132,7 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializer
'date_joined', 'last_login', 'created_by', 'is_first_login', 'date_joined', 'last_login', 'created_by', 'is_first_login',
'wecom_id', 'dingtalk_id', 'feishu_id' 'wecom_id', 'dingtalk_id', 'feishu_id'
] ]
disallow_self_update_fields = ['is_active']
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},
'public_key': {'write_only': True}, 'public_key': {'write_only': True},
@@ -178,7 +181,23 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializer
attrs.pop(field, None) attrs.pop(field, None)
return attrs return attrs
def check_disallow_self_update_fields(self, attrs):
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return attrs
if not self.instance:
return attrs
if request.user.id != self.instance.id:
return attrs
disallow_fields = set(list(attrs.keys())) & set(self.Meta.disallow_self_update_fields)
if not disallow_fields:
return attrs
# 用户自己不能更新自己的一些字段
error = 'User Cannot self-update fields: {}'.format(disallow_fields)
raise serializers.ValidationError(error)
def validate(self, attrs): def validate(self, attrs):
attrs = self.check_disallow_self_update_fields(attrs)
attrs = self.change_password_to_raw(attrs) attrs = self.change_password_to_raw(attrs)
attrs = self.clean_auth_fields(attrs) attrs = self.clean_auth_fields(attrs)
attrs.pop('password_strategy', None) attrs.pop('password_strategy', None)
@@ -203,17 +222,6 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializer
field.set(value) field.set(value)
return instance return instance
def validate_is_active(self, is_active):
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return is_active
user = request.user
if user.id == self.instance.id and not is_active:
# 用户自己不能禁用启用自己
raise serializers.ValidationError("Cannot inactive self")
return is_active
def update(self, instance, validated_data): def update(self, instance, validated_data):
save_handler = partial(super().update, instance) save_handler = partial(super().update, instance)
instance = self.save_and_set_custom_m2m_fields(validated_data, save_handler, created=False) instance = self.save_and_set_custom_m2m_fields(validated_data, save_handler, created=False)

View File

@@ -60,9 +60,30 @@ def save_passwd_change(sender, instance: User, **kwargs):
) )
def update_role_superuser_if_need(user):
if not user._update_superuser:
return
value = user._is_superuser
from rbac.models import SystemRoleBinding
from rbac.builtin import BuiltinRole
role = BuiltinRole.system_admin.get_role()
kwargs = {'user_id': user.id, 'role_id': role.id, 'scope': 'system'}
exists = SystemRoleBinding.objects.filter(**kwargs).exists()
# 需要添加并且不存在
if value and not exists:
SystemRoleBinding.objects.create(**kwargs)
# 需要删除并且存在
elif not value and exists:
SystemRoleBinding.objects.filter(**kwargs).delete()
else:
print("No need operate")
@receiver(post_save, sender=User) @receiver(post_save, sender=User)
@on_transaction_commit @on_transaction_commit
def on_user_create_set_default_system_role(sender, instance, created, **kwargs): def on_user_create_set_default_system_role(sender, instance, created, **kwargs):
update_role_superuser_if_need(instance)
if not created: if not created:
return return
has_system_role = instance.system_roles.all().exists() has_system_role = instance.system_roles.all().exists()

View File

@@ -58,7 +58,7 @@ def clean_db_content_types():
('perms', 'applicationpermission', 'view_permuserapplication'), ('perms', 'applicationpermission', 'view_permuserapplication'),
('perms', 'assetpermission', 'view_permuserasset'), ('perms', 'assetpermission', 'view_permuserasset'),
('perms', 'assetpermission', 'view_permusergroupasset'), ('perms', 'assetpermission', 'view_permusergroupasset'),
('rbac', 'menupermission', 'view_dashboard'),
('applications', 'databaseapp', 'add_databaseapp'), ('applications', 'databaseapp', 'add_databaseapp'),
('applications', 'databaseapp', 'change_databaseapp'), ('applications', 'databaseapp', 'change_databaseapp'),
('applications', 'databaseapp', 'delete_databaseapp'), ('applications', 'databaseapp', 'delete_databaseapp'),