mirror of https://github.com/jumpserver/jumpserver
perf: optimize user operation logs (#13221)
parent
cdfb11549e
commit
dfd133cf5a
|
@ -52,7 +52,7 @@ class OperateLogStore(object):
|
|||
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):
|
||||
|
|
|
@ -37,6 +37,9 @@ class ActionChoices(TextChoices):
|
|||
approve = 'approve', _('Approve')
|
||||
close = 'close', _('Close')
|
||||
|
||||
# Custom action
|
||||
finished = 'finished', _('Finished')
|
||||
|
||||
|
||||
class LoginTypeChoices(TextChoices):
|
||||
web = "W", _("Web")
|
||||
|
|
|
@ -58,7 +58,7 @@ class OperatorLogHandler(metaclass=Singleton):
|
|||
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:
|
||||
|
|
|
@ -257,6 +257,8 @@ class UserLoginLog(models.Model):
|
|||
|
||||
|
||||
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"))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -75,6 +75,7 @@ class AuthMixin:
|
|||
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
|
||||
|
|
|
@ -17,6 +17,7 @@ from orgs.utils import current_org
|
|||
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 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, ResourceLa
|
|||
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 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, ResourceLa
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue