autter_core/database/
organizations.rs1use std::collections::HashMap;
2
3use crate::{
4 DataManager,
5 model::{
6 Error, Result, User, UserPermission,
7 organizations::{Organization, OrganizationMembership, OrganizationRole},
8 },
9};
10use oiseau::{PostgresRow, cache::Cache, execute, get, params, query_rows};
11use tetratto_core::auto_method;
12
13impl DataManager {
14 pub(crate) fn get_organization_from_row(x: &PostgresRow) -> Organization {
16 Organization {
17 id: get!(x->0(i64)) as usize,
18 created: get!(x->1(i64)) as usize,
19 owner: get!(x->2(i64)) as usize,
20 name: get!(x->3(String)),
21 members: get!(x->4(i32)),
22 roles: serde_json::from_str(&get!(x->5(String))).unwrap(),
23 }
24 }
25
26 auto_method!(get_organization_by_id(usize as i64)@get_organization_from_row -> "SELECT * FROM a_organizations WHERE id = $1" --name="organization" --returns=Organization --cache-key-tmpl="srmp.organization:{}");
27 auto_method!(get_organization_by_name(&str)@get_organization_from_row -> "SELECT * FROM a_organizations WHERE name = $1" --name="organization" --returns=Organization);
28
29 pub async fn get_organizations_by_user(&self, user: usize) -> Result<Vec<Organization>> {
34 let conn = match self.0.connect().await {
35 Ok(c) => c,
36 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
37 };
38
39 let res = query_rows!(
40 &conn,
41 "SELECT * FROM a_organizations WHERE owner = $1 ORDER BY created",
42 &[&(user as i64)],
43 |x| { Self::get_organization_from_row(x) }
44 );
45
46 if res.is_err() {
47 return Err(Error::GeneralNotFound("organization".to_string()));
48 }
49
50 Ok(res.unwrap())
51 }
52
53 pub async fn create_organization(&self, data: Organization) -> Result<usize> {
58 if self.get_organization_by_name(&data.name).await.is_ok() {
59 return Err(Error::MiscError("Name already in use".to_string()));
60 }
61
62 let conn = match self.0.connect().await {
64 Ok(c) => c,
65 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
66 };
67
68 let res = execute!(
69 &conn,
70 "INSERT INTO a_organizations VALUES ($1, $2, $3, $4, $5, $6)",
71 params![
72 &(data.id as i64),
73 &(data.created as i64),
74 &(data.owner as i64),
75 &data.name,
76 &data.members,
77 &serde_json::to_string(&data.roles).unwrap()
78 ]
79 );
80
81 if let Err(e) = res {
82 return Err(Error::DatabaseError(e.to_string()));
83 }
84
85 let mut membership = OrganizationMembership::new(data.id, data.owner);
87 membership.role = OrganizationRole::Owner;
88 self.create_organization_membership(membership).await?;
89
90 Ok(data.id)
92 }
93
94 pub async fn delete_organization(&self, id: usize, user: User) -> Result<()> {
95 let organization = self.get_organization_by_id(id).await?;
96
97 if user.id != organization.owner
98 && !user
99 .permissions
100 .contains(&UserPermission::ManageOrganizations)
101 {
102 return Err(Error::NotAllowed);
103 }
104
105 if let Ok(u) = self.1.get_upload_by_id(organization.id).await {
106 self.1
107 .delete_upload(u.id)
108 .await
109 .expect("failed to delete organization avatar");
110 }
111
112 let conn = match self.0.connect().await {
113 Ok(c) => c,
114 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
115 };
116
117 let res = execute!(
118 &conn,
119 "DELETE FROM a_organizations WHERE id = $1",
120 &[&(id as i64)]
121 );
122
123 if let Err(e) = res {
124 return Err(Error::DatabaseError(e.to_string()));
125 }
126
127 self.0.1.remove(format!("srmp.organization:{}", id)).await;
128
129 Ok(())
131 }
132
133 auto_method!(update_organization_name(&str) -> "UPDATE a_organizations SET name = $1 WHERE id = $2" --cache-key-tmpl="srmp.organization:{}");
134 auto_method!(update_organization_roles(HashMap<usize, String>) -> "UPDATE a_organizations SET roles = $1 WHERE id = $2" --serde --cache-key-tmpl="srmp.organization:{}");
135
136 auto_method!(incr_organization_members() -> "UPDATE a_organizations SET members = members + 1 WHERE id = $2" --cache-key-tmpl="srmp.organization:{}" --incr);
137 auto_method!(decr_organization_members() -> "UPDATE a_organizations SET members = members + 1 WHERE id = $2" --cache-key-tmpl="srmp.organization:{}" --decr);
138}