-
-
Notifications
You must be signed in to change notification settings - Fork 4k
/
manager.py
116 lines (86 loc) · 3.61 KB
/
manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from __future__ import annotations
from dataclasses import dataclass
from sentry.models.auditlogentry import AuditLogEntry
class DuplicateAuditLogEvent(Exception):
pass
class AuditLogEventNotRegistered(Exception):
pass
"""
The audit log system records changes made to an organization and displays them in
organization settings.
To add a new audit log event:
1. Create a new instance of AuditLogEvent. You'll need an event_id, name, api_name,
and optional template.
Note: The template uses AuditLogEntry.data fields to construct a simple audit
log message. For more complicated messages, subclass AuditLogEvent in events.py
and override the render function.
2. Register the AuditLogEvent using `default_manager.add()`.
default_manager.add(
AuditLogEvent(
event_id=1,
name="MEMBER_INVITE",
api_name="member.invite",
template="invited member {email}",
)
)
3. Record your AuditLogEvent.
self.create_audit_entry(
request=request,
organization_id=organization.id,
target_object=member.id,
data={"email": "email@gmail.com"},
event=audit_log.get_event_id(MEMBER_INVITE),
)
"""
@dataclass(init=False)
class AuditLogEvent:
# Unique event ID (ex. 1)
event_id: int
# Unique event name (ex. MEMBER_INVITE)
name: str
# Unique event api name (ex. member.invite)
api_name: str
# Simple template for rendering the audit log message using
# the AuditLogEntry.data fields. For more complicated messages,
# subclass AuditLogEvent and override the render method.
template: str | None = None
def __init__(self, event_id, name, api_name, template=None):
self.event_id = event_id
self.name = name
self.api_name = api_name
self.template = template
def render(self, audit_log_entry: AuditLogEntry):
if not self.template:
return ""
return self.template.format(**audit_log_entry.data)
class AuditLogEventManager:
def __init__(self) -> None:
self._event_registry: dict[str, AuditLogEvent] = {}
self._event_id_lookup: dict[int, AuditLogEvent] = {}
self._api_name_lookup: dict[str, AuditLogEvent] = {}
def add(self, audit_log_event: AuditLogEvent) -> None:
if (
audit_log_event.name in self._event_registry
or audit_log_event.event_id in self._event_id_lookup
or audit_log_event.api_name in self._api_name_lookup
):
raise DuplicateAuditLogEvent(
f"Duplicate audit log: {audit_log_event.name} with ID {audit_log_event.event_id} and api name {audit_log_event.api_name}"
)
self._event_registry[audit_log_event.name] = audit_log_event
self._event_id_lookup[audit_log_event.event_id] = audit_log_event
self._api_name_lookup[audit_log_event.api_name] = audit_log_event
def get(self, event_id: int) -> AuditLogEvent:
if event_id not in self._event_id_lookup:
raise AuditLogEventNotRegistered(f"Event ID {event_id} does not exist")
return self._event_id_lookup[event_id]
def get_event_id(self, name: str) -> int:
if name not in self._event_registry:
raise AuditLogEventNotRegistered(f"Event {name} does not exist")
return self._event_registry[name].event_id
def get_event_id_from_api_name(self, api_name: str) -> int | None:
if api_name not in self._api_name_lookup:
return None
return self._api_name_lookup[api_name].event_id
def get_api_names(self) -> list[str]:
return list(self._api_name_lookup)