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