Skip to main content

zino_model/log/
mod.rs

1//! The `log` model and related services.
2
3use 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/// The `log` model.
21#[derive(
22    Debug, Clone, Default, Serialize, Deserialize, DecodeRow, Entity, Schema, ModelAccessor,
23)]
24#[serde(default)]
25#[schema(auto_rename)]
26pub struct Log {
27    // Basic fields.
28    #[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    // Info fields.
43    #[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    // Extensions.
60    #[schema(read_only)]
61    extra: Map,
62
63    // Revisions.
64    #[cfg(feature = "owner-id")]
65    #[schema(reference = "User")]
66    owner_id: Option<Uuid>, // user.id
67    #[cfg(feature = "maintainer-id")]
68    #[schema(reference = "User")]
69    maintainer_id: Option<Uuid>, // user.id
70    #[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}