use futures::{Stream, TryStreamExt}; use uuid::Uuid; use crate::{db::permissions::PermissionRaw, Pool}; use super::permissions::PermissionType; pub async fn get_permissions( folder_id: Uuid, user_id: i32, pool: &Pool, ) -> sqlx::Result { let permission = sqlx::query_file!("sql/get_permissions_for_folder.sql", folder_id, user_id) .fetch_optional(pool) .await? .and_then(|record| record.permission_type); Ok(permission.into()) } pub fn get_names(folder_id: Uuid, pool: &Pool) -> impl Stream> + '_ { sqlx::query!("SELECT folder_name as name FROM folders WHERE parent_folder_id = $1 UNION SELECT file_name as name FROM files WHERE folder_id = $1", folder_id) .fetch(pool) .map_ok(|record| record.name.unwrap()) } pub async fn get_root(user_id: i32, pool: &Pool) -> sqlx::Result { sqlx::query!( "SELECT folder_id FROM folders WHERE owner_id = $1 AND parent_folder_id IS null", user_id ) .fetch_one(pool) .await .map(|row| row.folder_id) } pub async fn process_id(id: Option, user_id: i32, pool: &Pool) -> sqlx::Result> { match id { Some(id) => get_permissions(id, user_id, pool) .await .map(|permissions| permissions.can_read().then_some(id)), None => get_root(user_id, pool).await.map(Some), } } #[derive(Debug, serde::Serialize)] #[allow(clippy::struct_field_names, clippy::module_name_repetitions)] pub struct FolderWithoutParentId { pub folder_id: Uuid, pub owner_id: i32, pub folder_name: String, pub created_at: chrono::NaiveDateTime, } pub async fn get_by_id( folder_id: Uuid, pool: &Pool, ) -> sqlx::Result> { sqlx::query_as!( FolderWithoutParentId, "SELECT folder_id, owner_id, folder_name, created_at FROM folders WHERE folder_id = $1", folder_id ) .fetch_optional(pool) .await } /// Get folders that user can read /// /// # Warning /// /// This function doesn't check that the user can read the parent folder itself pub fn get_folders( parent_folder_id: Uuid, user_id: i32, pool: &Pool, ) -> impl Stream> + '_ { sqlx::query_file_as!( FolderWithoutParentId, "sql/get_folders.sql", parent_folder_id, user_id ) .fetch(pool) } pub async fn name_exists(parent_folder_id: Uuid, name: &str, pool: &Pool) -> sqlx::Result { sqlx::query_file!("sql/name_exists.sql", parent_folder_id, name) .fetch_one(pool) .await .map(|row| row.exists.unwrap_or(false)) } pub async fn insert( parent_folder_id: Uuid, user_id: i32, folder_name: &str, pool: &Pool, ) -> sqlx::Result { sqlx::query!("INSERT INTO folders(parent_folder_id, owner_id, folder_name) VALUES ($1, $2, $3) RETURNING folder_id", parent_folder_id, user_id, folder_name ) .fetch_one(pool) .await .map(|record| record.folder_id) } pub fn delete(folder_id: Uuid, pool: &Pool) -> impl Stream> + '_ { sqlx::query_file!("sql/delete_folder.sql", folder_id) .fetch(pool) .map_ok(|row| row.file_id) }