1use oiseau::cache::Cache;
2use crate::model::auth::AchievementName;
3use crate::model::communities::Community;
4use crate::model::requests::{ActionRequest, ActionType};
5use crate::model::{
6 Error, Result,
7 auth::User,
8 communities::{CommunityJoinAccess, CommunityMembership},
9 communities_permissions::CommunityPermission,
10 permissions::FinePermission,
11};
12use crate::{auto_method, DataManager};
13
14use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
15
16impl DataManager {
17 pub(crate) fn get_membership_from_row(x: &PostgresRow) -> CommunityMembership {
19 CommunityMembership {
20 id: get!(x->0(i64)) as usize,
21 created: get!(x->1(i64)) as usize,
22 owner: get!(x->2(i64)) as usize,
23 community: get!(x->3(i64)) as usize,
24 role: CommunityPermission::from_bits(get!(x->4(i32)) as u32).unwrap(),
25 }
26 }
27
28 auto_method!(get_membership_by_id()@get_membership_from_row -> "SELECT * FROM memberships WHERE id = $1" --name="community membership" --returns=CommunityMembership --cache-key-tmpl="atto.membership:{}");
29
30 pub async fn fill_communities(&self, list: Vec<CommunityMembership>) -> Result<Vec<Community>> {
32 let mut communities: Vec<Community> = Vec::new();
33
34 for membership in &list {
35 if membership.community == 0 {
36 continue;
37 }
38
39 communities.push(self.get_community_by_id(membership.community).await?);
40 }
41
42 Ok(communities)
43 }
44
45 pub async fn fill_users(
47 &self,
48 list: Vec<CommunityMembership>,
49 ) -> Result<Vec<(CommunityMembership, User)>> {
50 let mut users: Vec<(CommunityMembership, User)> = Vec::new();
51 for membership in list {
52 let owner = membership.owner;
53 users.push((membership, self.get_user_by_id(owner).await?));
54 }
55 Ok(users)
56 }
57
58 pub async fn get_membership_by_owner_community(
60 &self,
61 owner: usize,
62 community: usize,
63 ) -> Result<CommunityMembership> {
64 let conn = match self.0.connect().await {
65 Ok(c) => c,
66 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
67 };
68
69 let res = query_row!(
70 &conn,
71 "SELECT * FROM memberships WHERE owner = $1 AND community = $2",
72 &[&(owner as i64), &(community as i64)],
73 |x| { Ok(Self::get_membership_from_row(x)) }
74 );
75
76 if res.is_err() {
77 return Ok(CommunityMembership::new(
79 owner,
80 community,
81 CommunityPermission::DEFAULT,
82 ));
83 }
84
85 Ok(res.unwrap())
86 }
87
88 pub async fn get_membership_by_owner_community_no_void(
90 &self,
91 owner: usize,
92 community: usize,
93 ) -> Result<CommunityMembership> {
94 let conn = match self.0.connect().await {
95 Ok(c) => c,
96 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
97 };
98
99 let res = query_row!(
100 &conn,
101 "SELECT * FROM memberships WHERE owner = $1 AND community = $2",
102 &[&(owner as i64), &(community as i64)],
103 |x| { Ok(Self::get_membership_from_row(x)) }
104 );
105
106 if res.is_err() {
107 return Err(Error::GeneralNotFound("community membership".to_string()));
108 }
109
110 Ok(res.unwrap())
111 }
112
113 pub async fn get_memberships_by_owner(&self, owner: usize) -> Result<Vec<CommunityMembership>> {
115 let conn = match self.0.connect().await {
116 Ok(c) => c,
117 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
118 };
119
120 let res = query_rows!(
121 &conn,
122 "SELECT * FROM memberships WHERE owner = $1 AND NOT role = 33 AND NOT role = 65 ORDER BY created DESC",
124 &[&(owner as i64)],
125 |x| { Self::get_membership_from_row(x) }
126 );
127
128 if res.is_err() {
129 return Err(Error::GeneralNotFound("community membership".to_string()));
130 }
131
132 Ok(res.unwrap())
133 }
134
135 pub async fn get_memberships_by_community(
137 &self,
138 community: usize,
139 community_owner: usize, batch: usize,
141 page: usize,
142 ) -> Result<Vec<CommunityMembership>> {
143 let conn = match self.0.connect().await {
144 Ok(c) => c,
145 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
146 };
147
148 let res = query_rows!(
149 &conn,
150 "SELECT * FROM memberships WHERE community = $1 AND NOT owner = $2 AND NOT role = 33 AND NOT role = 65 ORDER BY created DESC LIMIT $3 OFFSET $4",
152 &[
153 &(community as i64),
154 &(community_owner as i64),
155 &(batch as i64),
156 &((page * batch) as i64)
157 ],
158 |x| { Self::get_membership_from_row(x) }
159 );
160
161 if res.is_err() {
162 return Err(Error::GeneralNotFound("community membership".to_string()));
163 }
164
165 Ok(res.unwrap())
166 }
167
168 #[async_recursion::async_recursion]
173 pub async fn create_membership(
174 &self,
175 data: CommunityMembership,
176 user: &User,
177 ) -> Result<String> {
178 if self
180 .get_membership_by_owner_community_no_void(data.owner, data.community)
181 .await
182 .is_ok()
183 {
184 return Err(Error::MiscError("Already joined community".to_string()));
185 }
186
187 let community = self.get_community_by_id(data.community).await?;
189
190 match community.join_access {
191 CommunityJoinAccess::Nobody => return Err(Error::NotAllowed),
192 CommunityJoinAccess::Request => {
193 if !data.role.check(CommunityPermission::REQUESTED) {
194 let mut data = data.clone();
195 data.role = CommunityPermission::DEFAULT | CommunityPermission::REQUESTED;
196
197 self.create_request(ActionRequest::with_id(
199 data.owner,
200 community.owner,
201 ActionType::CommunityJoin,
202 community.id,
203 None,
204 ))
205 .await?;
206
207 return self.create_membership(data, user).await;
209 }
210 }
211 _ => (),
212 }
213
214 let conn = match self.0.connect().await {
216 Ok(c) => c,
217 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
218 };
219
220 let res = execute!(
221 &conn,
222 "INSERT INTO memberships VALUES ($1, $2, $3, $4, $5)",
223 params![
224 &(data.id as i64),
225 &(data.created as i64),
226 &(data.owner as i64),
227 &(data.community as i64),
228 &(data.role.bits() as i32),
229 ]
230 );
231
232 if let Err(e) = res {
233 return Err(Error::DatabaseError(e.to_string()));
234 }
235
236 if !data.role.check(CommunityPermission::REQUESTED) {
237 self.incr_community_member_count(data.community)
239 .await
240 .unwrap();
241 }
242
243 Ok(if data.role.check(CommunityPermission::REQUESTED) {
244 "Join request sent".to_string()
245 } else {
246 self.add_achievement(
247 &mut user.clone(),
248 AchievementName::JoinCommunity.into(),
249 true,
250 )
251 .await?;
252
253 "Community joined".to_string()
254 })
255 }
256
257 pub async fn delete_membership(&self, id: usize, user: &User) -> Result<()> {
259 let y = self.get_membership_by_id(id).await?;
260
261 if user.id != y.owner {
262 if let Ok(z) = self
264 .get_membership_by_owner_community_no_void(user.id, y.community)
265 .await
266 {
267 if (!z.role.check(CommunityPermission::MANAGE_ROLES) | (z.role < y.role))
269 && !z.role.check(CommunityPermission::ADMINISTRATOR)
270 {
271 return Err(Error::NotAllowed);
272 }
273 } else if !user.permissions.check(FinePermission::MANAGE_MEMBERSHIPS) {
274 return Err(Error::NotAllowed);
275 }
276 }
277
278 let conn = match self.0.connect().await {
279 Ok(c) => c,
280 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
281 };
282
283 let res = execute!(
284 &conn,
285 "DELETE FROM memberships WHERE id = $1",
286 &[&(id as i64)]
287 );
288
289 if let Err(e) = res {
290 return Err(Error::DatabaseError(e.to_string()));
291 }
292
293 self.0.1.remove(format!("atto.membership:{}", id)).await;
294
295 self.decr_community_member_count(y.community).await.unwrap();
296
297 Ok(())
298 }
299
300 pub async fn delete_membership_force(&self, id: usize) -> Result<()> {
302 let y = self.get_membership_by_id(id).await?;
303
304 let conn = match self.0.connect().await {
305 Ok(c) => c,
306 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
307 };
308
309 let res = execute!(
310 &conn,
311 "DELETE FROM memberships WHERE id = $1",
312 &[&(id as i64)]
313 );
314
315 if let Err(e) = res {
316 return Err(Error::DatabaseError(e.to_string()));
317 }
318
319 self.0.1.remove(format!("atto.membership:{}", id)).await;
320
321 self.decr_community_member_count(y.community).await.unwrap();
322
323 Ok(())
324 }
325
326 pub async fn update_membership_role(
328 &self,
329 id: usize,
330 new_role: CommunityPermission,
331 ) -> Result<()> {
332 let conn = match self.0.connect().await {
333 Ok(c) => c,
334 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
335 };
336
337 let res = execute!(
338 &conn,
339 "UPDATE memberships SET role = $1 WHERE id = $2",
340 params![&(new_role.bits() as i32), &(id as i64)]
341 );
342
343 if let Err(e) = res {
344 return Err(Error::DatabaseError(e.to_string()));
345 }
346
347 self.0.1.remove(format!("atto.membership:{}", id)).await;
348
349 Ok(())
350 }
351}