mirror of https://github.com/jumpserver/jumpserver
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
5.4 KiB
177 lines
5.4 KiB
# -*- coding: utf-8 -*- |
|
# |
|
from collections import defaultdict |
|
from functools import partial |
|
|
|
from django.conf import settings |
|
from django.db.models.signals import post_save, pre_delete, m2m_changed, post_delete |
|
from django.db.utils import ProgrammingError, OperationalError |
|
from django.dispatch import receiver |
|
from django.utils.functional import LazyObject |
|
|
|
from common.const.signals import PRE_REMOVE, POST_REMOVE |
|
from common.decorators import delay_run |
|
from common.decorators import on_transaction_commit |
|
from common.signals import django_ready |
|
from common.utils import get_logger |
|
from common.utils.connection import RedisPubSub |
|
from orgs.hands import set_current_org, Node, get_current_org |
|
from orgs.models import Organization |
|
from orgs.utils import tmp_to_org, set_to_default_org |
|
from perms.models import AssetPermission |
|
from users.models import UserGroup, User |
|
from users.signals import post_user_leave_org |
|
|
|
logger = get_logger(__file__) |
|
|
|
|
|
class OrgsMappingForMemoryPubSub(LazyObject): |
|
def _setup(self): |
|
self._wrapped = RedisPubSub('fm.orgs_mapping') |
|
|
|
|
|
orgs_mapping_for_memory_pub_sub = OrgsMappingForMemoryPubSub() |
|
|
|
|
|
def expire_orgs_mapping_for_memory(org_id): |
|
orgs_mapping_for_memory_pub_sub.publish(str(org_id)) |
|
|
|
|
|
@receiver(django_ready) |
|
def subscribe_orgs_mapping_expire(sender, **kwargs): |
|
logger.debug("Start subscribe for expire orgs mapping from memory") |
|
|
|
if settings.DEBUG: |
|
try: |
|
set_to_default_org() |
|
except (ProgrammingError, OperationalError): |
|
pass |
|
|
|
orgs_mapping_for_memory_pub_sub.subscribe( |
|
lambda org_id: Organization.expire_orgs_mapping() |
|
) |
|
|
|
|
|
@delay_run(ttl=5) |
|
def expire_user_orgs(): |
|
User.expire_users_rbac_perms_cache() |
|
|
|
|
|
@receiver(post_save, sender=Organization) |
|
def on_org_create(sender, instance, created=False, **kwargs): |
|
expire_user_orgs() |
|
|
|
|
|
# 创建对应的root |
|
@receiver(post_save, sender=Organization) |
|
def on_org_create_or_update(sender, instance, **kwargs): |
|
# 必须放到最开始, 因为下面调用Node.save方法时会获取当前组织的org_id(即instance.org_id), 如果不过期会找不到 |
|
expire_orgs_mapping_for_memory(instance.id) |
|
|
|
old_org = get_current_org() |
|
set_current_org(instance) |
|
node_root = Node.org_root() |
|
if node_root.value != instance.name: |
|
node_root.value = instance.name |
|
node_root.save() |
|
set_current_org(old_org) |
|
|
|
|
|
@receiver(pre_delete, sender=Organization) |
|
def delete_org_root_node_on_org_delete(sender, instance, **kwargs): |
|
expire_orgs_mapping_for_memory(instance.id) |
|
|
|
# 删除该组织下所有 节点 |
|
with tmp_to_org(instance): |
|
root_node = Node.org_root() |
|
if root_node: |
|
root_node.delete() |
|
|
|
|
|
@receiver(post_delete, sender=Organization) |
|
def expire_user_orgs_on_org_delete(sender, instance, **kwargs): |
|
expire_user_orgs() |
|
|
|
|
|
@receiver(post_save, sender=User) |
|
@on_transaction_commit |
|
def on_user_created_set_default_org(sender, instance, created, **kwargs): |
|
if not instance.id: |
|
# 用户已被手动删除,instance.orgs 时会使用 id 进行查找报错,所以判断不存在id时不做处理 |
|
return |
|
if not created: |
|
return |
|
if instance.orgs.count() > 0: |
|
return |
|
default_org = Organization.default() |
|
with tmp_to_org(default_org): |
|
default_org.add_member(instance) |
|
default_group = UserGroup.objects.filter(name='Default').first() |
|
if default_group: |
|
default_group.users.add(instance) |
|
|
|
|
|
def _remove_user_resource(model, users, org, user_field_name='users'): |
|
with tmp_to_org(org): |
|
if not isinstance(users, (tuple, list, set)): |
|
users = (users,) |
|
|
|
user_field = getattr(model, user_field_name) |
|
m2m_model = user_field.through |
|
reverse = user_field.reverse |
|
if reverse: |
|
m2m_field_name = user_field.field.m2m_reverse_field_name() |
|
else: |
|
m2m_field_name = user_field.field.m2m_field_name() |
|
relations = m2m_model.objects.filter(**{ |
|
'user__in': users, |
|
f'{m2m_field_name}__org_id': org.id |
|
}) |
|
|
|
object_id_user_ids_map = defaultdict(set) |
|
|
|
m2m_field_attr_name = f'{m2m_field_name}_id' |
|
for relation in relations: |
|
object_id = getattr(relation, m2m_field_attr_name) |
|
object_id_user_ids_map[object_id].add(relation.user_id) |
|
|
|
objects = model.objects.filter(id__in=object_id_user_ids_map.keys()) |
|
send_m2m_change_signal = partial( |
|
m2m_changed.send, sender=m2m_model, reverse=reverse, |
|
model=User, using=model.objects.db |
|
) |
|
|
|
for obj in objects: |
|
send_m2m_change_signal( |
|
instance=obj, |
|
pk_set=object_id_user_ids_map[obj.id], |
|
action=PRE_REMOVE |
|
) |
|
|
|
relations.delete() |
|
|
|
for obj in objects: |
|
send_m2m_change_signal( |
|
instance=obj, |
|
pk_set=object_id_user_ids_map[obj.id], |
|
action=POST_REMOVE |
|
) |
|
|
|
|
|
def _clear_users_from_org(org, users): |
|
""" |
|
清理用户在该组织下的相关数据, 包括用户组, 资产授权, 用户授权 |
|
""" |
|
if not users: |
|
return |
|
|
|
models = (AssetPermission, UserGroup) |
|
|
|
for m in models: |
|
_remove_user_resource(m, users, org) |
|
|
|
|
|
@receiver(post_user_leave_org) |
|
def on_user_leave_org(sender, user=None, org=None, **kwargs): |
|
logger.debug('User leave org signal recv: {} <> {}'.format(user, org)) |
|
_clear_users_from_org(org, [user])
|
|
|