tetratto_core2/database/
groups.rs1use crate::{
2 DataManager, auto_method,
3 model::{
4 Error, Result,
5 groups::{GroupSettings, GroupMembership, Group, GroupRole},
6 id::Id,
7 },
8};
9use oiseau::query_rows;
10use oiseau::{PostgresRow, cache::Cache, execute, get, params, query_row};
11
12impl DataManager {
13 pub(crate) fn get_group_from_row(x: &PostgresRow) -> Group {
15 Group {
16 id: Id::deserialize(&get!(x->0(String))),
17 created: get!(x->1(i64)) as u128,
18 owner: Id::deserialize(&get!(x->2(String))),
19 name: get!(x->3(String)),
20 settings: serde_json::from_str(&get!(x->4(String))).unwrap(),
21 members: get!(x->5(i32)),
22 }
23 }
24
25 auto_method!(get_group_by_id()@get_group_from_row -> "SELECT * FROM groups WHERE id = $1" --name="group" --returns=Group --cache-key-tmpl="atto.group:{}");
26 auto_method!(get_group_by_name(&str)@get_group_from_row -> "SELECT * FROM groups WHERE name = $1" --name="group" --returns=Group --cache-key-tmpl="atto.group:{}");
27
28 pub async fn get_groups_searched(
30 &self,
31 query: &str,
32 batch: usize,
33 page: usize,
34 ) -> Result<Vec<Group>> {
35 let conn = match self.0.connect().await {
36 Ok(c) => c,
37 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
38 };
39
40 let res = query_rows!(
41 &conn,
42 "SELECT * FROM groups WHERE name LIKE $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
43 &[
44 &format!("%{query}%"),
45 &(batch as i64),
46 &((page * batch) as i64)
47 ],
48 |x| { Self::get_group_from_row(x) }
49 );
50
51 if res.is_err() {
52 return Err(Error::GeneralNotFound("group".to_string()));
53 }
54
55 Ok(res.unwrap())
56 }
57
58 pub async fn create_group(&self, mut data: Group) -> Result<Id> {
63 data.name = data.name.to_lowercase();
64
65 if self.get_group_by_name(&data.name).await.is_ok() {
67 return Err(Error::MiscError("Name is already in use".to_string()));
68 }
69
70 let conn = match self.0.connect().await {
72 Ok(c) => c,
73 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
74 };
75
76 let res = execute!(
77 &conn,
78 "INSERT INTO groups VALUES ($1, $2, $3, $4, $5, $6)",
79 params![
80 &data.id.printable(),
81 &(data.created as i64),
82 &data.owner.printable(),
83 &data.name,
84 &serde_json::to_string(&data.settings).unwrap(),
85 &data.members,
86 ]
87 );
88
89 if let Err(e) = res {
90 return Err(Error::DatabaseError(e.to_string()));
91 }
92
93 self.create_group_membership(GroupMembership::new(
95 data.owner,
96 data.id.clone(),
97 GroupRole::Owner,
98 ))
99 .await?;
100
101 Ok(data.id)
103 }
104
105 pub async fn update_group_settings(&self, id: &Id, settings: GroupSettings) -> Result<()> {
106 let y = self.get_group_by_id(id).await?;
107
108 let conn = match self.0.connect().await {
109 Ok(c) => c,
110 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
111 };
112
113 let res = execute!(
114 &conn,
115 "UPDATE groups SET settings = $1 WHERE id = $2",
116 &[&serde_json::to_string(&settings).unwrap(), &id.printable()]
117 );
118
119 if let Err(e) = res {
120 return Err(Error::DatabaseError(e.to_string()));
121 }
122
123 self.cache_clear_group(&y).await;
124
125 Ok(())
127 }
128
129 pub async fn update_group_owner(&self, id: &Id, owner: Id) -> Result<()> {
130 let y = self.get_group_by_id(id).await?;
131
132 let conn = match self.0.connect().await {
133 Ok(c) => c,
134 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
135 };
136
137 let res = execute!(
138 &conn,
139 "UPDATE groups SET owner = $1 WHERE id = $2",
140 &[&owner.printable(), &id.printable()]
141 );
142
143 if let Err(e) = res {
144 return Err(Error::DatabaseError(e.to_string()));
145 }
146
147 self.cache_clear_group(&y).await;
148
149 Ok(())
151 }
152
153 pub async fn delete_group(&self, id: &Id) -> Result<()> {
154 let y = self.get_group_by_id(id).await?;
155
156 let conn = match self.0.connect().await {
157 Ok(c) => c,
158 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
159 };
160
161 let res = execute!(
162 &conn,
163 "DELETE FROM groups WHERE id = $1",
164 &[&id.printable()]
165 );
166
167 if let Err(e) = res {
168 return Err(Error::DatabaseError(e.to_string()));
169 }
170
171 self.cache_clear_group(&y).await;
172
173 if let Ok(avatar) = self
175 .1
176 .get_upload_by_id_bucket(id.as_usize(), "group_avatars")
177 .await
178 && let Err(e) = self
179 .1
180 .delete_upload_with_bucket(avatar.id, "group_avatars")
181 .await
182 {
183 return Err(Error::MiscError(e.to_string()));
184 }
185
186 if let Ok(banner) = self
187 .1
188 .get_upload_by_id_bucket(id.as_usize(), "group_banners")
189 .await
190 && let Err(e) = self
191 .1
192 .delete_upload_with_bucket(banner.id, "group_banners")
193 .await
194 {
195 return Err(Error::MiscError(e.to_string()));
196 }
197
198 Ok(())
200 }
201
202 pub async fn cache_clear_group(&self, c: &Group) -> bool {
203 self.0.1.remove(format!("atto.group:{}", c.id)).await
204 && self.0.1.remove(format!("atto.group:{}", c.name)).await
205 }
206
207 auto_method!(incr_group_members()@get_group_by_id -> "UPDATE groups SET members = members + 1 WHERE id = $1" --cache-key-tmpl=cache_clear_group --incr);
208 auto_method!(decr_group_members()@get_group_by_id -> "UPDATE groups SET members = members - 1 WHERE id = $1" --cache-key-tmpl=cache_clear_group --decr=members);
209}