headless_lms_models/
organizations.rs1use std::path::PathBuf;
2
3use headless_lms_utils::{ApplicationConfiguration, file_store::FileStore};
4
5use crate::prelude::*;
6
7#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
8pub struct DatabaseOrganization {
9 pub id: Uuid,
10 pub slug: String,
11 pub created_at: DateTime<Utc>,
12 pub updated_at: DateTime<Utc>,
13 pub name: String,
14 pub description: Option<String>,
15 pub organization_image_path: Option<String>,
16 pub deleted_at: Option<DateTime<Utc>>,
17}
18
19#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
20#[cfg_attr(feature = "ts_rs", derive(TS))]
21pub struct Organization {
22 pub id: Uuid,
23 pub slug: String,
24 pub created_at: DateTime<Utc>,
25 pub updated_at: DateTime<Utc>,
26 pub name: String,
27 pub description: Option<String>,
28 pub organization_image_url: Option<String>,
29 pub deleted_at: Option<DateTime<Utc>>,
30}
31
32impl Organization {
33 pub fn from_database_organization(
34 organization: DatabaseOrganization,
35 file_store: &dyn FileStore,
36 app_conf: &ApplicationConfiguration,
37 ) -> Self {
38 let organization_image_url = organization.organization_image_path.as_ref().map(|image| {
39 let path = PathBuf::from(image);
40 file_store.get_download_url(path.as_path(), app_conf)
41 });
42 Self {
43 id: organization.id,
44 created_at: organization.created_at,
45 updated_at: organization.updated_at,
46 name: organization.name,
47 slug: organization.slug,
48 deleted_at: organization.deleted_at,
49 organization_image_url,
50 description: organization.description,
51 }
52 }
53}
54
55pub async fn insert(
56 conn: &mut PgConnection,
57 pkey_policy: PKeyPolicy<Uuid>,
58 name: &str,
59 slug: &str,
60 description: &str,
61) -> ModelResult<Uuid> {
62 let res = sqlx::query!(
63 "
64INSERT INTO organizations (id, name, slug, description)
65VALUES ($1, $2, $3, $4)
66RETURNING id
67",
68 pkey_policy.into_uuid(),
69 name,
70 slug,
71 description
72 )
73 .fetch_one(conn)
74 .await?;
75 Ok(res.id)
76}
77
78pub async fn all_organizations(conn: &mut PgConnection) -> ModelResult<Vec<DatabaseOrganization>> {
79 let organizations = sqlx::query_as!(
80 DatabaseOrganization,
81 "SELECT * FROM organizations WHERE deleted_at IS NULL ORDER BY name;"
82 )
83 .fetch_all(conn)
84 .await?;
85 Ok(organizations)
86}
87
88pub async fn get_organization(
89 conn: &mut PgConnection,
90 organization_id: Uuid,
91) -> ModelResult<DatabaseOrganization> {
92 let org = sqlx::query_as!(
93 DatabaseOrganization,
94 "
95SELECT *
96from organizations
97where id = $1;",
98 organization_id,
99 )
100 .fetch_one(conn)
101 .await?;
102 Ok(org)
103}
104
105pub async fn get_organization_by_slug(
106 conn: &mut PgConnection,
107 organization_slug: &str,
108) -> ModelResult<DatabaseOrganization> {
109 let organization = sqlx::query_as!(
110 DatabaseOrganization,
111 "
112SELECT *
113FROM organizations
114WHERE slug = $1;
115 ",
116 organization_slug
117 )
118 .fetch_one(conn)
119 .await?;
120 Ok(organization)
121}
122
123pub async fn update_organization_image_path(
124 conn: &mut PgConnection,
125 organization_id: Uuid,
126 organization_image_path: Option<String>,
127) -> ModelResult<DatabaseOrganization> {
128 let updated_organization = sqlx::query_as!(
129 DatabaseOrganization,
130 "
131UPDATE organizations
132SET organization_image_path = $1
133WHERE id = $2
134RETURNING *;",
135 organization_image_path,
136 organization_id
137 )
138 .fetch_one(conn)
139 .await?;
140 Ok(updated_organization)
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::test_helper::Conn;
147
148 #[tokio::test]
149 async fn gets_organizations() {
150 let mut conn = Conn::init().await;
151 let mut tx = conn.begin().await;
152 let orgs_before = all_organizations(tx.as_mut()).await.unwrap();
153 insert(
154 tx.as_mut(),
155 PKeyPolicy::Fixed(Uuid::parse_str("8c34e601-b5db-4b33-a588-57cb6a5b1669").unwrap()),
156 "org",
157 "slug",
158 "description",
159 )
160 .await
161 .unwrap();
162 let orgs_after = all_organizations(tx.as_mut()).await.unwrap();
163 assert_eq!(orgs_before.len() + 1, orgs_after.len());
164 }
165}