Skip to main content

tibba_model/
detector_group_user.rs

1// Copyright 2025 Tree xie.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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// 在相应的模型文件中定义
30#[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 from_i8(value: i8) -> Option<Self> {
40    //     match value {
41    //         1 => Some(Self::Owner),
42    //         2 => Some(Self::Admin),
43    //         3 => Some(Self::Member),
44    //         4 => Some(Self::Viewer),
45    //         _ => None,
46    //     }
47    // }
48
49    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(&params.effective_start_time)?)
245        .bind(parse_primitive_datetime(&params.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}