1use serde::{Deserialize, Serialize};
4use zino_core::{
5 Map, Uuid,
6 datetime::DateTime,
7 error::Error,
8 extension::JsonObjectExt,
9 model::{Model, ModelHooks},
10 validation::Validation,
11};
12use zino_derive::{DecodeRow, Entity, ModelAccessor, Schema};
13
14#[cfg(any(feature = "owner-id", feature = "maintainer-id"))]
15use crate::user::User;
16
17#[cfg(feature = "maintainer-id")]
18use zino_auth::UserSession;
19
20#[derive(
22 Debug, Clone, Default, Serialize, Deserialize, DecodeRow, Entity, Schema, ModelAccessor,
23)]
24#[serde(default)]
25#[schema(auto_rename)]
26pub struct Log {
27 #[schema(read_only)]
29 id: Uuid,
30 #[schema(not_null)]
31 name: String,
32 #[cfg(feature = "namespace")]
33 #[schema(default_value = "Log::model_namespace", index_type = "hash")]
34 namespace: String,
35 #[cfg(feature = "visibility")]
36 #[schema(default_value = "Internal")]
37 visibility: String,
38 #[schema(default_value = "Active", index_type = "hash")]
39 status: String,
40 description: String,
41
42 #[schema(not_null, read_only)]
44 service: String,
45 #[schema(read_only)]
46 server_host: String,
47 #[schema(read_only)]
48 client_ip: String,
49 topic: String,
50 #[schema(read_only)]
51 level: String,
52 #[schema(read_only)]
53 message: String,
54 #[schema(read_only)]
55 source: String,
56 #[schema(read_only, index_type = "btree")]
57 recorded_at: DateTime,
58
59 #[schema(read_only)]
61 extra: Map,
62
63 #[cfg(feature = "owner-id")]
65 #[schema(reference = "User")]
66 owner_id: Option<Uuid>, #[cfg(feature = "maintainer-id")]
68 #[schema(reference = "User")]
69 maintainer_id: Option<Uuid>, #[schema(read_only, default_value = "now", index_type = "btree")]
71 created_at: DateTime,
72 #[schema(default_value = "now", index_type = "btree")]
73 updated_at: DateTime,
74 version: u64,
75 #[cfg(feature = "edition")]
76 edition: u32,
77}
78
79impl Model for Log {
80 const MODEL_NAME: &'static str = "log";
81
82 #[inline]
83 fn new() -> Self {
84 Self {
85 id: Uuid::now_v7(),
86 ..Self::default()
87 }
88 }
89
90 fn read_map(&mut self, data: &Map) -> Validation {
91 let mut validation = Validation::new();
92 if let Some(result) = data.parse_uuid("id") {
93 match result {
94 Ok(id) => self.id = id,
95 Err(err) => validation.record_fail("id", err),
96 }
97 }
98 if let Some(name) = data.parse_string("name") {
99 self.name = name.into_owned();
100 }
101 if let Some(description) = data.parse_string("description") {
102 self.description = description.into_owned();
103 }
104 #[cfg(feature = "owner-id")]
105 if let Some(result) = data.parse_uuid("owner_id") {
106 match result {
107 Ok(owner_id) => self.owner_id = Some(owner_id),
108 Err(err) => validation.record_fail("owner_id", err),
109 }
110 }
111 #[cfg(feature = "maintainer-id")]
112 if let Some(result) = data.parse_uuid("maintainer_id") {
113 match result {
114 Ok(maintainer_id) => self.maintainer_id = Some(maintainer_id),
115 Err(err) => validation.record_fail("maintainer_id", err),
116 }
117 }
118 validation
119 }
120}
121
122impl ModelHooks for Log {
123 type Data = ();
124 #[cfg(feature = "maintainer-id")]
125 type Extension = UserSession<Uuid, String>;
126 #[cfg(not(feature = "maintainer-id"))]
127 type Extension = ();
128
129 #[cfg(feature = "maintainer-id")]
130 #[inline]
131 async fn after_extract(&mut self, session: Self::Extension) -> Result<(), Error> {
132 self.maintainer_id = Some(*session.user_id());
133 Ok(())
134 }
135
136 #[cfg(feature = "maintainer-id")]
137 #[inline]
138 async fn before_validation(
139 data: &mut Map,
140 extension: Option<&Self::Extension>,
141 ) -> Result<(), Error> {
142 if let Some(session) = extension {
143 data.upsert("maintainer_id", session.user_id().to_string());
144 }
145 Ok(())
146 }
147}