reinfer_client/resources/
audit.rs1use chrono::{DateTime, Utc};
2
3use crate::{Continuation, DatasetId, DatasetName, ProjectName, UserEmail, UserId, Username};
4
5use super::{comment::CommentTimestampFilter, project::Id as ProjectId};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Deserialize, Serialize)]
9pub struct AuditQueryFilter {
10 pub timestamp: CommentTimestampFilter,
11}
12
13#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
14pub struct AuditEventId(pub String);
15
16#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
17pub struct AuditEventType(pub String);
18
19#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
20pub struct AuditTenantName(pub String);
21
22#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
23pub struct AuditTenantId(pub String);
24
25#[derive(Debug, Clone, Deserialize, Serialize)]
26pub struct AuditQueryRequest {
27 pub filter: AuditQueryFilter,
28 #[serde(skip_serializing_if = "Option::is_none", default)]
29 pub continuation: Option<Continuation>,
30}
31
32#[derive(Debug, Clone, Deserialize, Serialize)]
33pub struct AuditEvent {
34 actor_user_id: UserId,
35 actor_tenant_id: AuditTenantId,
36 #[serde(skip_serializing_if = "Vec::is_empty", default)]
37 dataset_ids: Vec<DatasetId>,
38 event_id: AuditEventId,
39 event_type: AuditEventType,
40 #[serde(skip_serializing_if = "Vec::is_empty", default)]
41 project_ids: Vec<ProjectId>,
42 tenant_ids: Vec<AuditTenantId>,
43 timestamp: DateTime<Utc>,
44}
45
46#[derive(Debug, Clone, Deserialize, Serialize)]
47pub struct PrintableAuditEvent {
48 pub actor_email: UserEmail,
49 pub actor_tenant_name: AuditTenantName,
50 pub event_type: AuditEventType,
51 pub dataset_names: Vec<DatasetName>,
52 pub event_id: AuditEventId,
53 pub project_names: Vec<ProjectName>,
54 pub tenant_names: Vec<AuditTenantName>,
55 pub timestamp: DateTime<Utc>,
56}
57
58#[derive(Debug, Clone, Deserialize, Serialize)]
59struct AuditDataset {
60 id: DatasetId,
61 name: DatasetName,
62 project_id: ProjectId,
63 title: String,
64}
65
66#[derive(Debug, Clone, Deserialize, Serialize)]
67struct AuditProject {
68 id: ProjectId,
69 name: ProjectName,
70 tenant_id: AuditTenantId,
71}
72
73#[derive(Debug, Clone, Deserialize, Serialize)]
74struct AuditTenant {
75 id: AuditTenantId,
76 name: AuditTenantName,
77}
78
79#[derive(Debug, Clone, Deserialize, Serialize)]
80struct AuditUser {
81 display_name: Username,
82 email: UserEmail,
83 id: UserId,
84 tenant_id: AuditTenantId,
85 username: Username,
86}
87
88#[derive(Debug, Clone, Deserialize, Serialize)]
89pub struct AuditQueryResponse {
90 audit_events: Vec<AuditEvent>,
91 projects: Vec<AuditProject>,
92 pub continuation: Option<Continuation>,
93 datasets: Vec<AuditDataset>,
94 tenants: Vec<AuditTenant>,
95 users: Vec<AuditUser>,
96}
97
98impl AuditQueryResponse {
99 pub fn into_iter_printable(self) -> QueryResponseIterator {
100 QueryResponseIterator {
101 response: self,
102 index: 0,
103 }
104 }
105
106 fn get_user(&self, user_id: &UserId) -> Option<&AuditUser> {
107 self.users.iter().find(|user| user.id == *user_id)
108 }
109
110 fn get_dataset(&self, dataset_id: &DatasetId) -> Option<&AuditDataset> {
111 self.datasets
112 .iter()
113 .find(|dataset| dataset.id == *dataset_id)
114 }
115
116 fn get_project(&self, project_id: &ProjectId) -> Option<&AuditProject> {
117 self.projects
118 .iter()
119 .find(|project| project.id == *project_id)
120 }
121
122 fn get_tenant(&self, tenant_id: &AuditTenantId) -> Option<&AuditTenant> {
123 self.tenants.iter().find(|tenant| tenant.id == *tenant_id)
124 }
125}
126
127pub struct QueryResponseIterator {
128 response: AuditQueryResponse,
129 index: usize,
130}
131
132impl Iterator for QueryResponseIterator {
133 type Item = PrintableAuditEvent;
134 fn next(&mut self) -> Option<Self::Item> {
135 let event = self.response.audit_events.get(self.index)?;
136
137 let actor_email = &self
138 .response
139 .get_user(&event.actor_user_id)
140 .unwrap_or_else(|| panic!("Could not find user for id `{}`", event.actor_user_id.0))
141 .email;
142
143 let dataset_names = event
144 .dataset_ids
145 .iter()
146 .map(|dataset_id| {
147 &self
148 .response
149 .get_dataset(dataset_id)
150 .unwrap_or_else(|| panic!("Could not get dataset for id `{}`", dataset_id.0))
151 .name
152 })
153 .cloned()
154 .collect();
155
156 let project_names = event
157 .project_ids
158 .iter()
159 .map(|project_id| {
160 &self
161 .response
162 .get_project(project_id)
163 .unwrap_or_else(|| panic!("Could not get project for id `{}`", project_id.0))
164 .name
165 })
166 .cloned()
167 .collect();
168
169 let tenant_names = event
170 .tenant_ids
171 .iter()
172 .map(|tenant_id| {
173 &self
174 .response
175 .get_tenant(tenant_id)
176 .unwrap_or_else(|| panic!("Could not get tenant for id `{}`", tenant_id.0))
177 .name
178 })
179 .cloned()
180 .collect();
181
182 let actor_tenant_name = &self
183 .response
184 .get_tenant(&event.actor_tenant_id)
185 .unwrap_or_else(|| panic!("Could not get tenant for id `{}`", event.actor_tenant_id.0))
186 .name;
187
188 self.index += 1;
189
190 Some(PrintableAuditEvent {
191 event_type: event.event_type.clone(),
192 actor_tenant_name: actor_tenant_name.clone(),
193 event_id: event.event_id.clone(),
194 timestamp: event.timestamp,
195 actor_email: actor_email.clone(),
196 dataset_names,
197 project_names,
198 tenant_names,
199 })
200 }
201}