diff --git a/apps/audits/backends/db.py b/apps/audits/backends/db.py index e8fe43c2293d..3a47036bbca8 100644 --- a/apps/audits/backends/db.py +++ b/apps/audits/backends/db.py @@ -52,7 +52,7 @@ def _get_special_handler(resource_type): resource_map = { 'Asset permission': lambda k, v: ActionChoices.display(int(v)) if k == 'Actions' else v } - return resource_map.get(resource_type, lambda k, v: v) + return resource_map.get(resource_type, lambda k, v: _(v)) @classmethod def convert_diff_friendly(cls, op_log): diff --git a/apps/audits/const.py b/apps/audits/const.py index 4418e9e7f83a..43396148f64e 100644 --- a/apps/audits/const.py +++ b/apps/audits/const.py @@ -37,6 +37,9 @@ class ActionChoices(TextChoices): approve = 'approve', _('Approve') close = 'close', _('Close') + # Custom action + finished = 'finished', _('Finished') + class LoginTypeChoices(TextChoices): web = "W", _("Web") diff --git a/apps/audits/handler.py b/apps/audits/handler.py index 3f0e444f1dca..debe0a0684a5 100644 --- a/apps/audits/handler.py +++ b/apps/audits/handler.py @@ -58,7 +58,7 @@ def cache_instance_before_data(self, instance_dict): return key = '%s_%s' % (self.CACHE_KEY, instance_id) - cache.set(key, instance_dict, 3 * 60) + cache.set(key, instance_dict, 3) def get_instance_dict_from_cache(self, instance_id): if instance_id is None: diff --git a/apps/audits/models.py b/apps/audits/models.py index 512f50bc1bea..762147c98622 100644 --- a/apps/audits/models.py +++ b/apps/audits/models.py @@ -257,6 +257,8 @@ class Meta: class UserSession(models.Model): + _OPERATE_LOG_ACTION = {'delete': ActionChoices.finished} + id = models.UUIDField(default=uuid.uuid4, primary_key=True) ip = models.GenericIPAddressField(verbose_name=_("Login IP")) key = models.CharField(max_length=128, verbose_name=_("Session key")) diff --git a/apps/audits/signal_handlers/operate_log.py b/apps/audits/signal_handlers/operate_log.py index 39069b108d15..9f4958ca8a77 100644 --- a/apps/audits/signal_handlers/operate_log.py +++ b/apps/audits/signal_handlers/operate_log.py @@ -3,7 +3,9 @@ import uuid from django.apps import apps -from django.db.models.signals import post_save, pre_save, m2m_changed, pre_delete +from django.db.models.signals import ( + pre_delete, pre_save, m2m_changed, post_delete, post_save +) from django.dispatch import receiver from django.utils import translation @@ -94,7 +96,7 @@ def signal_of_operate_log_whether_continue( return condition -@receiver(pre_save) +@receiver([pre_save, pre_delete]) def on_object_pre_create_or_update( sender, instance=None, raw=False, using=None, update_fields=None, **kwargs ): @@ -103,6 +105,7 @@ def on_object_pre_create_or_update( ) if not ok: return + with translation.override('en'): # users.PrivateToken Model 没有 id 有 pk字段 instance_id = getattr(instance, 'id', getattr(instance, 'pk', None)) @@ -145,7 +148,7 @@ def on_object_created_or_update( ) -@receiver(pre_delete) +@receiver(post_delete) def on_object_delete(sender, instance=None, **kwargs): ok = signal_of_operate_log_whether_continue(sender, instance, False) if not ok: @@ -153,9 +156,15 @@ def on_object_delete(sender, instance=None, **kwargs): with translation.override('en'): resource_type = sender._meta.verbose_name + action = getattr(sender, '_OPERATE_LOG_ACTION', {}) + action = action.get('delete', ActionChoices.delete) + instance_id = getattr(instance, 'id', getattr(instance, 'pk', None)) + log_id, before = get_instance_dict_from_cache(instance_id) + if not log_id: + log_id, before = None, model_to_dict(instance) create_or_update_operate_log( - ActionChoices.delete, resource_type, - resource=instance, before=model_to_dict(instance) + action, resource_type, log_id=log_id, + resource=instance, before=before, ) @@ -166,7 +175,7 @@ def on_django_start_set_operate_log_monitor_models(sender, **kwargs): 'django_celery_beat', 'contenttypes', 'sessions', 'auth', } exclude_models = { - 'UserPasswordHistory', 'ContentType', + 'UserPasswordHistory', 'ContentType', 'Asset', 'MessageContent', 'SiteMessage', 'PlatformAutomation', 'PlatformProtocol', 'Protocol', 'HistoricalAccount', 'GatheredUser', 'ApprovalRule', @@ -180,11 +189,13 @@ def on_django_start_set_operate_log_monitor_models(sender, **kwargs): 'ApplyCommandTicket', 'ApplyLoginAssetTicket', 'FavoriteAsset', } + include_models = {'UserSession'} for i, app in enumerate(apps.get_models(), 1): app_name = app._meta.app_label model_name = app._meta.object_name if app_name in exclude_apps or \ model_name in exclude_models or \ model_name.endswith('Execution'): - continue + if model_name not in include_models: + continue MODELS_NEED_RECORD.add(model_name) diff --git a/apps/audits/utils.py b/apps/audits/utils.py index d9728fbbd454..1b1e4b8e62c5 100644 --- a/apps/audits/utils.py +++ b/apps/audits/utils.py @@ -49,9 +49,15 @@ def _get_instance_field_value( continue value = getattr(instance, f.name, None) or getattr(instance, f.attname, None) - if not isinstance(value, bool) and not value: + if not isinstance(value, (bool, int)) and not value: continue + choices = getattr(f, 'choices', []) or [] + for c_value, c_label in choices: + if c_value == value: + value = c_label + break + if getattr(f, 'primary_key', False): f.verbose_name = 'id' elif isinstance(value, list): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index e01e2b65e441..3be9654163f7 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -75,6 +75,7 @@ def set_public_key(self, public_key): if self.can_update_ssh_key(): self.public_key = public_key self.save() + post_user_change_password.send(self.__class__, user=self) def can_update_password(self): return self.is_local diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index beb69b57eec0..e9d051820449 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -17,6 +17,7 @@ from rbac.builtin import BuiltinRole from rbac.models import OrgRoleBinding, SystemRoleBinding, Role from rbac.permissions import RBACPermission +from users.signals import post_user_change_password from ..const import PasswordStrategy from ..models import User @@ -268,6 +269,8 @@ def update(self, instance, validated_data): instance = self.save_and_set_custom_m2m_fields( validated_data, save_handler, created=False ) + if validated_data.get('public_key'): + post_user_change_password.send(instance.__class__, user=instance) return instance def create(self, validated_data): @@ -275,6 +278,8 @@ def create(self, validated_data): instance = self.save_and_set_custom_m2m_fields( validated_data, save_handler, created=True ) + if validated_data.get('public_key'): + post_user_change_password.send(instance.__class__, user=instance) return instance @classmethod