Skip to main content

zino_model/application/
mod.rs

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