sz_rust_core/plugin/
schema.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct SysUser {
14 pub id: i64,
16 pub tenant_id: i64,
18 pub username: String,
20 pub display_name: String,
22 #[serde(skip_serializing)]
24 pub password_hash: String,
25 pub email: Option<String>,
27 pub phone: Option<String>,
29 pub status: String,
31 pub extra: serde_json::Value,
33 pub created_at: chrono::DateTime<chrono::Utc>,
35 pub updated_at: chrono::DateTime<chrono::Utc>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct SysPermission {
42 pub id: i64,
44 pub tenant_id: i64,
46 pub name: String,
48 pub description: String,
50 pub resource: String,
52 pub action: String,
54 pub conditions: Option<serde_json::Value>,
56 pub created_at: chrono::DateTime<chrono::Utc>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct SysEvent {
66 pub id: i64,
68 pub tenant_id: i64,
70 pub event_type: String,
72 pub source_plugin: String,
74 pub payload: serde_json::Value,
76 pub delivered: bool,
78 pub delivered_at: Option<chrono::DateTime<chrono::Utc>>,
80 pub retry_count: i32,
82 pub max_retries: i32,
84 pub created_at: chrono::DateTime<chrono::Utc>,
86 pub updated_at: chrono::DateTime<chrono::Utc>,
88}
89
90impl SysUser {
91 pub fn table_name() -> &'static str {
93 "sys_users"
94 }
95}
96
97impl SysPermission {
98 pub fn table_name() -> &'static str {
100 "sys_permissions"
101 }
102}
103
104impl SysEvent {
105 pub fn table_name() -> &'static str {
107 "sys_events"
108 }
109
110 pub fn new(
112 tenant_id: i64,
113 event_type: impl Into<String>,
114 source_plugin: impl Into<String>,
115 payload: serde_json::Value,
116 ) -> Self {
117 let now = chrono::Utc::now();
118 Self {
119 id: 0,
120 tenant_id,
121 event_type: event_type.into(),
122 source_plugin: source_plugin.into(),
123 payload,
124 delivered: false,
125 delivered_at: None,
126 retry_count: 0,
127 max_retries: 3,
128 created_at: now,
129 updated_at: now,
130 }
131 }
132
133 pub fn mark_delivered(&mut self) {
135 self.delivered = true;
136 self.delivered_at = Some(chrono::Utc::now());
137 self.updated_at = chrono::Utc::now();
138 }
139
140 pub fn increment_retry(&mut self) {
142 self.retry_count += 1;
143 self.updated_at = chrono::Utc::now();
144 }
145
146 pub fn is_exhausted(&self) -> bool {
148 self.retry_count >= self.max_retries
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_sys_event_new() {
158 let event = SysEvent::new(1, "order.created", "shop", serde_json::json!({"id": 1}));
159 assert_eq!(event.tenant_id, 1);
160 assert_eq!(event.event_type, "order.created");
161 assert!(!event.delivered);
162 assert_eq!(event.retry_count, 0);
163 assert_eq!(event.max_retries, 3);
164 }
165
166 #[test]
167 fn test_mark_delivered() {
168 let mut event = SysEvent::new(1, "test", "test", serde_json::json!({}));
169 event.mark_delivered();
170 assert!(event.delivered);
171 assert!(event.delivered_at.is_some());
172 }
173
174 #[test]
175 fn test_retry_exhaustion() {
176 let mut event = SysEvent::new(1, "test", "test", serde_json::json!({}));
177 assert!(!event.is_exhausted());
178 event.increment_retry();
179 event.increment_retry();
180 event.increment_retry();
181 assert!(event.is_exhausted());
182 }
183
184 #[test]
185 fn test_password_hash_skip_serializing() {
186 let user = SysUser {
187 id: 1,
188 tenant_id: 1,
189 username: "admin".to_string(),
190 display_name: "Admin".to_string(),
191 password_hash: "secret_hash".to_string(),
192 email: None,
193 phone: None,
194 status: "active".to_string(),
195 extra: serde_json::json!({}),
196 created_at: chrono::Utc::now(),
197 updated_at: chrono::Utc::now(),
198 };
199 let json = serde_json::to_string(&user).expect("序列化失败");
200 assert!(
201 !json.contains("password_hash"),
202 "敏感字段不应出现在 JSON 中"
203 );
204 assert!(!json.contains("secret_hash"), "敏感值不应出现在 JSON 中");
205 }
206}