Skip to main content

tetratto_core2/database/
group_memberships.rs

1use oiseau::{PostgresRow, cache::Cache, execute, get, params, query_row, query_rows};
2use crate::{
3    DataManager, auto_method,
4    model::{
5        groups::{GroupRole, GroupMembership},
6        id::Id,
7        Error, Result,
8    },
9};
10
11impl DataManager {
12    /// Get a [`GroupMembership`] from an SQL row.
13    pub(crate) fn get_group_membership_from_row(x: &PostgresRow) -> GroupMembership {
14        GroupMembership {
15            id: Id::deserialize(&get!(x->0(String))),
16            created: get!(x->1(i64)) as u128,
17            owner: Id::deserialize(&get!(x->2(String))),
18            group: Id::deserialize(&get!(x->3(String))),
19            role: serde_json::from_str(&get!(x->4(String))).unwrap(),
20        }
21    }
22
23    auto_method!(get_group_membership_by_id()@get_group_membership_from_row -> "SELECT * FROM group_memberships WHERE id = $1" --name="membership" --returns=GroupMembership --cache-key-tmpl="juic.group_membership:{}");
24
25    /// Get a membership by `owner` and `group` (in that order).
26    pub async fn get_group_membership_by_owner_group(
27        &self,
28        owner: &Id,
29        group: &Id,
30    ) -> Result<GroupMembership> {
31        let conn = match self.0.connect().await {
32            Ok(c) => c,
33            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
34        };
35
36        let res = query_row!(
37            &conn,
38            "SELECT * FROM group_memberships WHERE owner = $1 AND group_id = $2",
39            &[&owner.printable(), &group.printable()],
40            |x| { Ok(Self::get_group_membership_from_row(x)) }
41        );
42
43        if res.is_err() {
44            return Err(Error::GeneralNotFound("membership".to_string()));
45        }
46
47        Ok(res.unwrap())
48    }
49
50    /// Get group memberships by the given user.
51    ///
52    /// # Arguments
53    /// * `id` - the ID of the user
54    /// * `batch` - the limit of group memberships in each page
55    /// * `page` - the page number
56    pub async fn get_group_memberships_by_owner(
57        &self,
58        id: &Id,
59        batch: usize,
60        page: usize,
61    ) -> Result<Vec<GroupMembership>> {
62        let conn = match self.0.connect().await {
63            Ok(c) => c,
64            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
65        };
66
67        let res = query_rows!(
68            &conn,
69            "SELECT * FROM group_memberships WHERE owner = $1 AND role != '\"Banned\"' ORDER BY created DESC LIMIT $2 OFFSET $3",
70            &[&id.printable(), &(batch as i64), &((page * batch) as i64)],
71            |x| { Self::get_group_membership_from_row(x) }
72        );
73
74        if res.is_err() {
75            return Err(Error::GeneralNotFound("group membership".to_string()));
76        }
77
78        Ok(res.unwrap())
79    }
80
81    /// Get group memberships by the given user.
82    ///
83    /// # Arguments
84    /// * `id` - the ID of the user
85    pub async fn get_group_memberships_group_by_owner_all(&self, id: &Id) -> Result<Vec<Id>> {
86        let conn = match self.0.connect().await {
87            Ok(c) => c,
88            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
89        };
90
91        let res = query_rows!(
92            &conn,
93            "SELECT group_id FROM group_memberships WHERE owner = $1 AND role != '\"Banned\"'",
94            &[&id.printable()],
95            |x| { Id::deserialize(&get!(x->0(String))) }
96        );
97
98        if res.is_err() {
99            return Err(Error::GeneralNotFound("group membership".to_string()));
100        }
101
102        Ok(res.unwrap())
103    }
104
105    /// Get all memberships of a group by role.
106    pub async fn get_group_memberships_by_group_role(
107        &self,
108        group: &Id,
109        role: &GroupRole,
110        batch: usize,
111        page: usize,
112    ) -> Result<Vec<GroupMembership>> {
113        let conn = match self.0.connect().await {
114            Ok(c) => c,
115            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
116        };
117
118        let res = query_rows!(
119            &conn,
120            "SELECT * FROM group_memberships WHERE role = $1 AND group_id = $2 ORDER BY created DESC LIMIT $3 OFFSET $4",
121            &[
122                &serde_json::to_string(&role).unwrap(),
123                &group.printable(),
124                &(batch as i64),
125                &((page * batch) as i64)
126            ],
127            |x| { Self::get_group_membership_from_row(x) }
128        );
129
130        if res.is_err() {
131            return Err(Error::GeneralNotFound("membership".to_string()));
132        }
133
134        Ok(res.unwrap())
135    }
136
137    /// Create a new membership in the database.
138    ///
139    /// # Arguments
140    /// * `data` - a mock [`GroupMembership`] object to insert
141    pub async fn create_group_membership(&self, data: GroupMembership) -> Result<()> {
142        let conn = match self.0.connect().await {
143            Ok(c) => c,
144            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
145        };
146
147        let res = execute!(
148            &conn,
149            "INSERT INTO group_memberships VALUES ($1, $2, $3, $4, $5)",
150            params![
151                &data.id.printable(),
152                &(data.created as i64),
153                &data.owner.printable(),
154                &data.group.printable(),
155                &serde_json::to_string(&data.role).unwrap(),
156            ]
157        );
158
159        if let Err(e) = res {
160            return Err(Error::DatabaseError(e.to_string()));
161        }
162
163        // ...
164        if data.role == GroupRole::Owner || data.role == GroupRole::Member {
165            self.incr_group_members(&data.group).await?;
166        }
167
168        // return
169        Ok(())
170    }
171
172    pub async fn delete_group_membership(&self, id: &Id) -> Result<()> {
173        let y = self.get_group_membership_by_id(id).await?;
174
175        let conn = match self.0.connect().await {
176            Ok(c) => c,
177            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
178        };
179
180        let res = execute!(
181            &conn,
182            "DELETE FROM group_memberships WHERE id = $1",
183            &[&id.printable()]
184        );
185
186        if let Err(e) = res {
187            return Err(Error::DatabaseError(e.to_string()));
188        }
189
190        self.0
191            .1
192            .remove(format!("juic.group_membership:{}", id))
193            .await;
194
195        // ...
196        if y.role == GroupRole::Owner || y.role == GroupRole::Member {
197            self.decr_group_members(&y.group).await?;
198        }
199
200        // return
201        Ok(())
202    }
203
204    pub async fn update_group_membership_role(&self, id: &Id, role: GroupRole) -> Result<()> {
205        let y = self.get_group_membership_by_id(id).await?;
206
207        let conn = match self.0.connect().await {
208            Ok(c) => c,
209            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
210        };
211
212        let res = execute!(
213            &conn,
214            "UPDATE group_memberships SET role = $1 WHERE id = $2",
215            &[&serde_json::to_string(&role).unwrap(), &id.printable()]
216        );
217
218        if let Err(e) = res {
219            return Err(Error::DatabaseError(e.to_string()));
220        }
221
222        self.0
223            .1
224            .remove(format!("juic.group_membership:{}", id))
225            .await;
226
227        // ...
228        if (y.role == GroupRole::Owner || y.role == GroupRole::Member)
229            && (role == GroupRole::Banned || role == GroupRole::Pending)
230        {
231            // owner/member -> banned/pending
232            self.decr_group_members(&y.group).await?;
233        } else if (y.role == GroupRole::Banned || y.role == GroupRole::Pending)
234            && (role == GroupRole::Owner || role == GroupRole::Member)
235        {
236            // banned/pending -> owner/member
237            self.incr_group_members(&y.group).await?;
238        }
239
240        // return
241        Ok(())
242    }
243}