1use super::{
16 DetectorGroupModel, Error, JsonSnafu, Model, ModelListParams, Schema, SchemaAllowCreate,
17 SchemaAllowEdit, SchemaOption, SchemaOptionValue, SchemaType, SchemaView, SqlxSnafu,
18 format_datetime, parse_primitive_datetime,
19};
20use serde::{Deserialize, Serialize};
21use snafu::ResultExt;
22use sqlx::FromRow;
23use sqlx::{Pool, Postgres, QueryBuilder};
24use std::collections::HashMap;
25use time::PrimitiveDateTime;
26
27type Result<T> = std::result::Result<T, Error>;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum DetectorGroupRole {
32 Owner = 1,
33 Admin = 2,
34 Member = 3,
35 Viewer = 4,
36}
37
38impl DetectorGroupRole {
39 pub fn to_i16(self) -> i16 {
50 self as i16
51 }
52
53 pub fn as_str(self) -> &'static str {
54 match self {
55 Self::Owner => "owner",
56 Self::Admin => "admin",
57 Self::Member => "member",
58 Self::Viewer => "viewer",
59 }
60 }
61}
62
63impl std::fmt::Display for DetectorGroupRole {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "{}", self.as_str())
66 }
67}
68
69#[derive(FromRow)]
70struct DetectorGroupUserSchema {
71 id: i64,
72 user_id: i64,
73 group_id: i64,
74 role: i16,
75 status: i16,
76 effective_start_time: PrimitiveDateTime,
77 effective_end_time: PrimitiveDateTime,
78 invited_by: i64,
79 remark: String,
80 created: PrimitiveDateTime,
81 modified: PrimitiveDateTime,
82}
83
84#[derive(Deserialize, Serialize, Clone, Debug)]
85pub struct DetectorGroupUser {
86 pub id: i64,
87 pub user_id: i64,
88 pub group_id: i64,
89 pub role: i16,
90 pub status: i16,
91 pub effective_start_time: String,
92 pub effective_end_time: String,
93 pub invited_by: i64,
94 pub remark: String,
95 pub created: String,
96 pub modified: String,
97}
98
99impl From<DetectorGroupUserSchema> for DetectorGroupUser {
100 fn from(schema: DetectorGroupUserSchema) -> Self {
101 Self {
102 id: schema.id,
103 user_id: schema.user_id,
104 group_id: schema.group_id,
105 role: schema.role,
106 status: schema.status,
107 effective_start_time: format_datetime(schema.effective_start_time),
108 effective_end_time: format_datetime(schema.effective_end_time),
109 invited_by: schema.invited_by,
110 remark: schema.remark,
111 created: format_datetime(schema.created),
112 modified: format_datetime(schema.modified),
113 }
114 }
115}
116
117#[derive(Deserialize, Serialize, Clone, Debug)]
118pub struct DetectorGroupUserInsertParams {
119 pub user_id: u64,
120 pub group_id: u64,
121 pub role: i16,
122 pub status: i16,
123 pub effective_start_time: String,
124 pub effective_end_time: String,
125 pub invited_by: u64,
126 pub created_by: u64,
127 pub remark: String,
128}
129
130#[derive(Deserialize, Serialize, Clone, Debug)]
131pub struct DetectorGroupUserUpdateParams {
132 pub role: Option<i16>,
133 pub status: Option<i16>,
134 pub effective_start_time: Option<String>,
135 pub effective_end_time: Option<String>,
136 pub invited_by: Option<u64>,
137 pub remark: Option<String>,
138}
139
140pub struct DetectorGroupUserModel {}
141
142impl Model for DetectorGroupUserModel {
143 type Output = DetectorGroupUser;
144 fn new() -> Self {
145 Self {}
146 }
147 async fn schema_view(&self, pool: &Pool<Postgres>) -> SchemaView {
148 let mut group_options = vec![];
149 if let Ok(groups) = DetectorGroupModel::new().list_enabled(pool).await {
150 for group in groups {
151 group_options.push(SchemaOption {
152 label: group.name,
153 value: SchemaOptionValue::Integer(group.id),
154 });
155 }
156 group_options.sort_by_key(|option| option.label.clone());
157 }
158 SchemaView {
159 schemas: vec![
160 Schema::new_id(),
161 Schema::new_user_search("user_id"),
162 Schema {
163 name: "group_id".to_string(),
164 category: SchemaType::Number,
165 required: true,
166 options: Some(group_options),
167 ..Default::default()
168 },
169 Schema {
170 name: "role".to_string(),
171 category: SchemaType::Number,
172 options: Some(vec![
173 SchemaOption {
174 label: DetectorGroupRole::Owner.to_string(),
175 value: SchemaOptionValue::Integer(
176 DetectorGroupRole::Owner.to_i16() as i64
177 ),
178 },
179 SchemaOption {
180 label: DetectorGroupRole::Admin.to_string(),
181 value: SchemaOptionValue::Integer(
182 DetectorGroupRole::Admin.to_i16() as i64
183 ),
184 },
185 SchemaOption {
186 label: DetectorGroupRole::Member.to_string(),
187 value: SchemaOptionValue::Integer(
188 DetectorGroupRole::Member.to_i16() as i64
189 ),
190 },
191 SchemaOption {
192 label: DetectorGroupRole::Viewer.to_string(),
193 value: SchemaOptionValue::Integer(
194 DetectorGroupRole::Viewer.to_i16() as i64
195 ),
196 },
197 ]),
198 ..Default::default()
199 },
200 Schema::new_status(),
201 Schema::new_effective_start_time(),
202 Schema::new_effective_end_time(),
203 Schema::new_remark(),
204 Schema::new_created(),
205 ],
206 allow_edit: SchemaAllowEdit {
207 owner: true,
208 roles: vec!["*".to_string()],
209 ..Default::default()
210 },
211 allow_create: SchemaAllowCreate {
212 roles: vec!["*".to_string()],
213 ..Default::default()
214 },
215 }
216 }
217
218 fn push_filter_conditions<'args>(
219 &self,
220 qb: &mut QueryBuilder<'args, Postgres>,
221 filters: &HashMap<String, String>,
222 ) -> Result<()> {
223 if let Some(status) = filters.get("status").and_then(|s| s.parse::<i16>().ok()) {
224 qb.push(" AND status = ");
225 qb.push_bind(status);
226 }
227 if let Some(group_id) = filters.get("group_id").and_then(|s| s.parse::<i64>().ok()) {
228 qb.push(" AND group_id = ");
229 qb.push_bind(group_id);
230 }
231 Ok(())
232 }
233
234 async fn insert(&self, pool: &Pool<Postgres>, params: serde_json::Value) -> Result<u64> {
235 let params: DetectorGroupUserInsertParams =
236 serde_json::from_value(params).context(JsonSnafu)?;
237 let row: (i64,) = sqlx::query_as(
238 r#"INSERT INTO detector_group_users (user_id, group_id, role, status, effective_start_time, effective_end_time, invited_by, created_by, remark) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id"#,
239 )
240 .bind(params.user_id as i64)
241 .bind(params.group_id as i64)
242 .bind(params.role)
243 .bind(params.status)
244 .bind(parse_primitive_datetime(¶ms.effective_start_time)?)
245 .bind(parse_primitive_datetime(¶ms.effective_end_time)?)
246 .bind(params.invited_by as i64)
247 .bind(params.created_by as i64)
248 .bind(params.remark)
249 .fetch_one(pool)
250 .await
251 .context(SqlxSnafu)?;
252
253 Ok(row.0 as u64)
254 }
255
256 async fn get_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<Option<Self::Output>> {
257 let result = sqlx::query_as::<_, DetectorGroupUserSchema>(
258 r#"SELECT * FROM detector_group_users WHERE id = $1 AND deleted_at IS NULL"#,
259 )
260 .bind(id as i64)
261 .fetch_optional(pool)
262 .await
263 .context(SqlxSnafu)?;
264
265 Ok(result.map(|schema| schema.into()))
266 }
267
268 async fn delete_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<()> {
269 sqlx::query(r#"UPDATE detector_group_users SET deleted_at = NOW() WHERE id = $1"#)
270 .bind(id as i64)
271 .execute(pool)
272 .await
273 .context(SqlxSnafu)?;
274
275 Ok(())
276 }
277
278 async fn update_by_id(
279 &self,
280 pool: &Pool<Postgres>,
281 id: u64,
282 params: serde_json::Value,
283 ) -> Result<()> {
284 let params: DetectorGroupUserUpdateParams =
285 serde_json::from_value(params).context(JsonSnafu)?;
286
287 let _ = sqlx::query(
288 r#"UPDATE detector_group_users SET role = COALESCE($1, role), status = COALESCE($2, status), effective_start_time = COALESCE($3, effective_start_time), effective_end_time = COALESCE($4, effective_end_time), invited_by = COALESCE($5, invited_by), remark = COALESCE($6, remark) WHERE id = $7 AND deleted_at IS NULL"#,
289 )
290 .bind(params.role)
291 .bind(params.status)
292 .bind(params.effective_start_time.as_deref().map(parse_primitive_datetime).transpose()?)
293 .bind(params.effective_end_time.as_deref().map(parse_primitive_datetime).transpose()?)
294 .bind(params.invited_by.map(|v| v as i64))
295 .bind(params.remark)
296 .bind(id as i64)
297 .execute(pool)
298 .await
299 .context(SqlxSnafu)?;
300
301 Ok(())
302 }
303
304 async fn count(&self, pool: &Pool<Postgres>, params: &ModelListParams) -> Result<i64> {
305 let mut qb = QueryBuilder::new("SELECT COUNT(*) FROM detector_group_users");
306 self.push_conditions(&mut qb, params)?;
307 let count = qb
308 .build_query_scalar::<i64>()
309 .fetch_one(pool)
310 .await
311 .context(SqlxSnafu)?;
312 Ok(count)
313 }
314
315 async fn list(
316 &self,
317 pool: &Pool<Postgres>,
318 params: &ModelListParams,
319 ) -> Result<Vec<Self::Output>> {
320 let mut qb = QueryBuilder::new("SELECT * FROM detector_group_users");
321 self.push_conditions(&mut qb, params)?;
322 params.push_pagination(&mut qb);
323 let users = qb
324 .build_query_as::<DetectorGroupUserSchema>()
325 .fetch_all(pool)
326 .await
327 .context(SqlxSnafu)?;
328 Ok(users.into_iter().map(|s| s.into()).collect())
329 }
330}