1use oiseau::cache::Cache;
2use crate::model::moderation::AuditLogEntry;
3use crate::model::{
4 Error, Result, auth::User, permissions::FinePermission,
5 communities_permissions::CommunityPermission, channels::Channel,
6};
7use crate::{auto_method, DataManager};
8use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
9
10impl DataManager {
11 pub(crate) fn get_channel_from_row(x: &PostgresRow) -> Channel {
13 Channel {
14 id: get!(x->0(i64)) as usize,
15 community: get!(x->1(i64)) as usize,
16 owner: get!(x->2(i64)) as usize,
17 created: get!(x->3(i64)) as usize,
18 minimum_role_read: get!(x->4(i32)) as u32,
19 minimum_role_write: get!(x->5(i32)) as u32,
20 position: get!(x->6(i32)) as usize,
21 members: serde_json::from_str(&get!(x->7(String))).unwrap(),
22 title: get!(x->8(String)),
23 last_message: get!(x->9(i64)) as usize,
24 }
25 }
26
27 auto_method!(get_channel_by_id(usize as i64)@get_channel_from_row -> "SELECT * FROM channels WHERE id = $1" --name="channel" --returns=Channel --cache-key-tmpl="atto.channel:{}");
28
29 pub async fn fill_members(
31 &self,
32 members: &Vec<usize>,
33 ignore_users: Vec<usize>,
34 ) -> Result<Vec<User>> {
35 let mut out = Vec::new();
36
37 for member in members {
38 if ignore_users.contains(member) {
39 continue;
40 }
41
42 out.push(self.get_user_by_id(member.to_owned()).await?);
43 }
44
45 Ok(out)
46 }
47
48 pub async fn get_channels_by_community(&self, community: usize) -> Result<Vec<Channel>> {
53 let conn = match self.0.connect().await {
54 Ok(c) => c,
55 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
56 };
57
58 let res = query_rows!(
59 &conn,
60 "SELECT * FROM channels WHERE community = $1 ORDER BY position ASC",
61 &[&(community as i64)],
62 |x| { Self::get_channel_from_row(x) }
63 );
64
65 if res.is_err() {
66 return Err(Error::GeneralNotFound("channel".to_string()));
67 }
68
69 Ok(res.unwrap())
70 }
71
72 pub async fn get_channels_by_user(&self, user: usize) -> Result<Vec<Channel>> {
77 let conn = match self.0.connect().await {
78 Ok(c) => c,
79 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
80 };
81
82 let res = query_rows!(
83 &conn,
84 "SELECT * FROM channels WHERE (owner = $1 OR members LIKE $2) AND community = 0 ORDER BY last_message DESC",
85 params![&(user as i64), &format!("%{user}%")],
86 |x| { Self::get_channel_from_row(x) }
87 );
88
89 if res.is_err() {
90 return Err(Error::GeneralNotFound("channel".to_string()));
91 }
92
93 Ok(res.unwrap())
94 }
95
96 pub async fn get_channel_by_owner_member(
102 &self,
103 owner: usize,
104 member: usize,
105 ) -> Result<Channel> {
106 let conn = match self.0.connect().await {
107 Ok(c) => c,
108 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
109 };
110
111 let res = query_row!(
112 &conn,
113 "SELECT * FROM channels WHERE owner = $1 AND members = $2 AND community = 0 ORDER BY created DESC",
114 params![&(owner as i64), &format!("[{member}]")],
115 |x| { Ok(Self::get_channel_from_row(x)) }
116 );
117
118 if res.is_err() {
119 return Err(Error::GeneralNotFound("channel".to_string()));
120 }
121
122 Ok(res.unwrap())
123 }
124
125 pub async fn create_channel(&self, data: Channel) -> Result<()> {
130 let user = self.get_user_by_id(data.owner).await?;
131
132 if data.community != 0 {
134 let membership = self
135 .get_membership_by_owner_community(user.id, data.community)
136 .await?;
137
138 if !membership.role.check(CommunityPermission::MANAGE_CHANNELS)
139 && !user.permissions.check(FinePermission::MANAGE_CHANNELS)
140 {
141 return Err(Error::NotAllowed);
142 }
143 }
144 else {
146 for member in &data.members {
147 if self
148 .get_userblock_by_initiator_receiver(member.to_owned(), data.owner)
149 .await
150 .is_ok()
151 {
152 return Err(Error::NotAllowed);
153 }
154 }
155 }
156
157 let conn = match self.0.connect().await {
159 Ok(c) => c,
160 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
161 };
162
163 let res = execute!(
164 &conn,
165 "INSERT INTO channels VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
166 params![
167 &(data.id as i64),
168 &(data.community as i64),
169 &(data.owner as i64),
170 &(data.created as i64),
171 &(data.minimum_role_read as i32),
172 &(data.minimum_role_write as i32),
173 &(data.position as i32),
174 &serde_json::to_string(&data.members).unwrap(),
175 &data.title,
176 &(data.last_message as i64)
177 ]
178 );
179
180 if let Err(e) = res {
181 return Err(Error::DatabaseError(e.to_string()));
182 }
183
184 Ok(())
185 }
186
187 pub async fn delete_channel(&self, id: usize, user: &User) -> Result<()> {
188 let channel = self.get_channel_by_id(id).await?;
189
190 if user.id != channel.owner {
192 let membership = self
193 .get_membership_by_owner_community(user.id, channel.community)
194 .await?;
195
196 if !membership.role.check(CommunityPermission::MANAGE_CHANNELS) {
197 return Err(Error::NotAllowed);
198 }
199 }
200
201 let conn = match self.0.connect().await {
203 Ok(c) => c,
204 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
205 };
206
207 let res = execute!(&conn, "DELETE FROM channels WHERE id = $1", &[&(id as i64)]);
208
209 if let Err(e) = res {
210 return Err(Error::DatabaseError(e.to_string()));
211 }
212
213 let res = execute!(
215 &conn,
216 "DELETE FROM messages WHERE channel = $1",
217 &[&(id as i64)]
218 );
219
220 if let Err(e) = res {
221 return Err(Error::DatabaseError(e.to_string()));
222 }
223
224 self.0.1.remove(format!("atto.channel:{}", id)).await;
226 Ok(())
227 }
228
229 pub async fn add_channel_member(&self, id: usize, user: User, member: String) -> Result<()> {
230 let mut y = self.get_channel_by_id(id).await?;
231
232 if user.id != y.owner && member != user.username {
233 if !user.permissions.check(FinePermission::MANAGE_CHANNELS) {
234 return Err(Error::NotAllowed);
235 } else {
236 self.create_audit_log_entry(AuditLogEntry::new(
237 user.id,
238 format!("invoked `add_channel_member` with x value `{member}`"),
239 ))
240 .await?
241 }
242 }
243
244 let member = self.get_user_by_username(&member).await?;
246
247 if self
248 .get_userblock_by_initiator_receiver(member.id, user.id)
249 .await
250 .is_ok()
251 {
252 return Err(Error::NotAllowed);
253 }
254
255 y.members.push(member.id);
257
258 let conn = match self.0.connect().await {
259 Ok(c) => c,
260 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
261 };
262
263 let res = execute!(
264 &conn,
265 "UPDATE channels SET members = $1 WHERE id = $2",
266 params![&serde_json::to_string(&y.members).unwrap(), &(id as i64)]
267 );
268
269 if let Err(e) = res {
270 return Err(Error::DatabaseError(e.to_string()));
271 }
272
273 self.0.1.remove(format!("atto.channel:{}", id)).await;
274
275 Ok(())
276 }
277
278 pub async fn remove_channel_member(&self, id: usize, user: User, member: usize) -> Result<()> {
279 let mut y = self.get_channel_by_id(id).await?;
280
281 if user.id != y.owner && member != user.id {
282 if !user.permissions.check(FinePermission::MANAGE_CHANNELS) {
283 return Err(Error::NotAllowed);
284 } else {
285 self.create_audit_log_entry(AuditLogEntry::new(
286 user.id,
287 format!("invoked `remove_channel_member` with x value `{member}`"),
288 ))
289 .await?
290 }
291 }
292
293 y.members
294 .remove(match y.members.iter().position(|x| *x == member) {
295 Some(i) => i,
296 None => return Err(Error::GeneralNotFound("member".to_string())),
297 });
298
299 let conn = match self.0.connect().await {
300 Ok(c) => c,
301 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
302 };
303
304 let res = execute!(
305 &conn,
306 "UPDATE channels SET members = $1 WHERE id = $2",
307 params![&serde_json::to_string(&y.members).unwrap(), &(id as i64)]
308 );
309
310 if let Err(e) = res {
311 return Err(Error::DatabaseError(e.to_string()));
312 }
313
314 self.0.1.remove(format!("atto.channel:{}", id)).await;
315
316 Ok(())
317 }
318
319 auto_method!(update_channel_title(&str)@get_channel_by_id:FinePermission::MANAGE_CHANNELS; -> "UPDATE channels SET title = $1 WHERE id = $2" --cache-key-tmpl="atto.channel:{}");
320 auto_method!(update_channel_position(i32)@get_channel_by_id:FinePermission::MANAGE_CHANNELS; -> "UPDATE channels SET position = $1 WHERE id = $2" --cache-key-tmpl="atto.channel:{}");
321 auto_method!(update_channel_minimum_role_read(i32)@get_channel_by_id:FinePermission::MANAGE_CHANNELS; -> "UPDATE channels SET minimum_role_read = $1 WHERE id = $2" --cache-key-tmpl="atto.channel:{}");
322 auto_method!(update_channel_minimum_role_write(i32)@get_channel_by_id:FinePermission::MANAGE_CHANNELS; -> "UPDATE channels SET minimum_role_write = $1 WHERE id = $2" --cache-key-tmpl="atto.channel:{}");
323 auto_method!(update_channel_members(Vec<usize>)@get_channel_by_id:FinePermission::MANAGE_CHANNELS; -> "UPDATE channels SET members = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.channel:{}");
324 auto_method!(update_channel_last_message(i64) -> "UPDATE channels SET last_message = $1 WHERE id = $2" --cache-key-tmpl="atto.channel:{}");
325}