From ffac39edd8ff72a5968e1ece8f9ad00653721913 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 13 Feb 2024 15:02:28 +0200 Subject: [PATCH] Reduce repetitive code in cvat/apps/events/handlers.py (#7430) ### Motivation and context This is a preparatory PR before I add more events. ### How has this been tested? ### Checklist - [x] I submit my changes into the `develop` branch - ~~[ ] I have created a changelog fragment~~ - ~~[ ] I have updated the documentation accordingly~~ - ~~[ ] I have added tests to cover my changes~~ - ~~[ ] I have linked related issues (see [GitHub docs]( https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))~~ - ~~[ ] I have increased versions of npm packages if it is necessary ([cvat-canvas](https://github.com/opencv/cvat/tree/develop/cvat-canvas#versioning), [cvat-core](https://github.com/opencv/cvat/tree/develop/cvat-core#versioning), [cvat-data](https://github.com/opencv/cvat/tree/develop/cvat-data#versioning) and [cvat-ui](https://github.com/opencv/cvat/tree/develop/cvat-ui#versioning))~~ ### License - [x] I submit _my code changes_ under the same [MIT License]( https://github.com/opencv/cvat/blob/develop/LICENSE) that covers the project. Feel free to contact the maintainers if that's a concern. --- cvat/apps/events/event.py | 34 +++++++++---- cvat/apps/events/handlers.py | 92 ++++++++++-------------------------- 2 files changed, 48 insertions(+), 78 deletions(-) diff --git a/cvat/apps/events/event.py b/cvat/apps/events/event.py index 9f3f31fbda38..361bd19984a2 100644 --- a/cvat/apps/events/event.py +++ b/cvat/apps/events/event.py @@ -4,6 +4,9 @@ from rest_framework.renderers import JSONRenderer from datetime import datetime, timezone +from typing import Optional + +from cvat.apps.engine.log import vlogger def event_scope(action, resource): return f"{action}:{resource}" @@ -31,22 +34,33 @@ def select(cls, resources): for action in cls.RESOURCES.get(resource, []) ] -def create_event(scope, - source, - **kwargs): - payload = kwargs.pop('payload', {}) - timestamp = kwargs.pop('timestamp', str(datetime.now(timezone.utc).timestamp())) +def record_server_event( + *, + scope: str, + request_id: Optional[str], + payload: Optional[dict] = None, + **kwargs, +) -> None: + payload = payload or {} + + payload_with_request_id = { + **payload, + "request": { + **payload.get("request", {}), + "id": request_id, + }, + } data = { "scope": scope, - "timestamp": timestamp, - "source": source, + "timestamp": str(datetime.now(timezone.utc).timestamp()), + "source": "server", + "payload": JSONRenderer().render(payload_with_request_id).decode('UTF-8'), **kwargs, } - if payload: - data["payload"] = JSONRenderer().render(payload).decode('UTF-8') - return data + vlogger.info(JSONRenderer().render(data).decode('UTF-8')) + class EventScopeChoice: @classmethod diff --git a/cvat/apps/events/handlers.py b/cvat/apps/events/handlers.py index 2fdff4794ded..eb74fa110280 100644 --- a/cvat/apps/events/handlers.py +++ b/cvat/apps/events/handlers.py @@ -3,11 +3,9 @@ # SPDX-License-Identifier: MIT from copy import deepcopy -from datetime import datetime, timezone import traceback import rq -from rest_framework.renderers import JSONRenderer from rest_framework.views import exception_handler from rest_framework.exceptions import NotAuthenticated from rest_framework import status @@ -36,9 +34,8 @@ from cvat.apps.engine.models import ShapeType from cvat.apps.organizations.models import Membership, Organization, Invitation from cvat.apps.organizations.serializers import OrganizationReadSerializer, MembershipReadSerializer, InvitationReadSerializer -from cvat.apps.engine.log import vlogger -from .event import event_scope, create_event +from .event import event_scope, record_server_event from .cache import get_cache def project_id(instance): @@ -264,16 +261,6 @@ def get_serializer_without_url(instance): serializer.fields.pop("url", None) return serializer -def set_request_id(payload=None, **kwargs): - _payload = payload or {} - return { - **_payload, - "request": { - **_payload.get("request", {}), - "id": request_id(**kwargs), - }, - } - def handle_create(scope, instance, **kwargs): oid = organization_id(instance) oslug = organization_slug(instance) @@ -291,11 +278,11 @@ def handle_create(scope, instance, **kwargs): payload = {} payload = _cleanup_fields(obj=payload) - event = create_event( + record_server_event( scope=scope, + request_id=request_id(), obj_id=getattr(instance, 'id', None), obj_name=_get_object_name(instance), - source='server', org_id=oid, org_slug=oslug, project_id=pid, @@ -304,11 +291,8 @@ def handle_create(scope, instance, **kwargs): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id(payload), + payload=payload, ) - message = JSONRenderer().render(event).decode('UTF-8') - - vlogger.info(message) def handle_update(scope, instance, old_instance, **kwargs): oid = organization_id(instance) @@ -324,16 +308,14 @@ def handle_update(scope, instance, old_instance, **kwargs): serializer = get_serializer_without_url(instance=instance) diff = get_instance_diff(old_data=old_serializer.data, data=serializer.data) - timestamp = str(datetime.now(timezone.utc).timestamp()) for prop, change in diff.items(): change = _cleanup_fields(change) - event = create_event( + record_server_event( scope=scope, - timestamp=timestamp, + request_id=request_id(), obj_name=prop, obj_id=getattr(instance, f'{prop}_id', None), obj_val=str(change["new_value"]), - source='server', org_id=oid, org_slug=oslug, project_id=pid, @@ -342,14 +324,9 @@ def handle_update(scope, instance, old_instance, **kwargs): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id({ - "old_value": change["old_value"], - }), + payload={"old_value": change["old_value"]}, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) - def handle_delete(scope, instance, store_in_deletion_cache=False, **kwargs): deletion_cache = get_cache() if store_in_deletion_cache: @@ -384,11 +361,11 @@ def handle_delete(scope, instance, store_in_deletion_cache=False, **kwargs): uname = user_name(instance) uemail = user_email(instance) - event = create_event( + record_server_event( scope=scope, + request_id=request_id(), obj_id=getattr(instance, 'id', None), obj_name=_get_object_name(instance), - source='server', org_id=oid, org_slug=oslug, project_id=pid, @@ -397,11 +374,7 @@ def handle_delete(scope, instance, store_in_deletion_cache=False, **kwargs): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id(), ) - message = JSONRenderer().render(event).decode('UTF-8') - - vlogger.info(message) def handle_annotations_change(instance, annotations, action, **kwargs): _annotations = deepcopy(annotations) @@ -429,9 +402,9 @@ def filter_shape_data(shape): tags = [filter_shape_data(tag) for tag in _annotations.get("tags", [])] if tags: - event = create_event( + record_server_event( scope=event_scope(action, "tags"), - source='server', + request_id=request_id(), count=len(tags), org_id=oid, org_slug=oslug, @@ -441,12 +414,8 @@ def filter_shape_data(shape): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id({ - "tags": tags, - }), + payload={"tags": tags}, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) shapes_by_type = {shape_type[0]: [] for shape_type in ShapeType.choices()} for shape in _annotations.get("shapes", []): @@ -455,10 +424,10 @@ def filter_shape_data(shape): scope = event_scope(action, "shapes") for shape_type, shapes in shapes_by_type.items(): if shapes: - event = create_event( + record_server_event( scope=scope, + request_id=request_id(), obj_name=shape_type, - source='server', count=len(shapes), org_id=oid, org_slug=oslug, @@ -468,12 +437,8 @@ def filter_shape_data(shape): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id({ - "shapes": shapes, - }), + payload={"shapes": shapes}, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) tracks_by_type = {shape_type[0]: [] for shape_type in ShapeType.choices()} for track in _annotations.get("tracks", []): @@ -487,10 +452,10 @@ def filter_shape_data(shape): scope = event_scope(action, "tracks") for track_type, tracks in tracks_by_type.items(): if tracks: - event = create_event( + record_server_event( scope=scope, + request_id=request_id(), obj_name=track_type, - source='server', count=len(tracks), org_id=oid, org_slug=oslug, @@ -500,12 +465,8 @@ def filter_shape_data(shape): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id({ - "tracks": tracks, - }), + payload={"tracks": tracks}, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) def handle_rq_exception(rq_job, exc_type, exc_value, tb): oid = rq_job.meta.get("org_id", None) @@ -523,9 +484,9 @@ def handle_rq_exception(rq_job, exc_type, exc_value, tb): "stack": ''.join(tb_strings), } - event = create_event( + record_server_event( scope="send:exception", - source='server', + request_id=request_id(instance=rq_job), count=1, org_id=oid, org_slug=oslug, @@ -535,10 +496,8 @@ def handle_rq_exception(rq_job, exc_type, exc_value, tb): user_id=uid, user_name=uname, user_email=uemail, - payload=set_request_id(payload, instance=rq_job), + payload=payload, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) return False @@ -572,17 +531,14 @@ def handle_viewset_exception(exc, context): "status_code": status_code, } - event = create_event( + record_server_event( scope="send:exception", - source='server', + request_id=request_id(), count=1, user_id=getattr(request.user, "id", None), user_name=getattr(request.user, "username", None), user_email=getattr(request.user, "email", None), - payload=set_request_id(payload), + payload=payload, ) - message = JSONRenderer().render(event).decode('UTF-8') - vlogger.info(message) - return response