2026-05-20 15:39:53 +02:00
|
|
|
/// Primary port for folder operations
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
|
|
use crate::application::dtos::folder_dto::{
|
|
|
|
|
CreateFolderDto, FolderDto, MoveFolderDto, RenameFolderDto,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::common::errors::DomainError;
|
2026-05-21 11:07:04 +02:00
|
|
|
use crate::domain::services::authorization::Permission;
|
2026-05-20 15:39:53 +02:00
|
|
|
|
|
|
|
|
pub trait FolderUseCase: Send + Sync + 'static {
|
2026-05-21 21:50:42 +02:00
|
|
|
async fn require_permission(
|
2026-05-21 11:07:04 +02:00
|
|
|
&self,
|
|
|
|
|
caller_id: Uuid,
|
|
|
|
|
permission: Permission,
|
|
|
|
|
folder_id: &str,
|
|
|
|
|
) -> Result<(), DomainError>;
|
|
|
|
|
|
2026-05-20 15:39:53 +02:00
|
|
|
/// Creates a new folder
|
|
|
|
|
async fn create_folder_with_perms(
|
|
|
|
|
&self,
|
|
|
|
|
dto: CreateFolderDto,
|
|
|
|
|
caller_id: Uuid,
|
|
|
|
|
) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Gets a folder by its ID
|
|
|
|
|
async fn get_folder(&self, id: &str) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Gets a folder by its ID, enforcing that `caller_id` is the owner.
|
|
|
|
|
///
|
|
|
|
|
/// Returns `NotFound` if the folder does not exist **or** belongs to
|
|
|
|
|
/// another user. All user-facing handlers should use this method.
|
|
|
|
|
async fn get_folder_with_perms(
|
|
|
|
|
&self,
|
|
|
|
|
id: &str,
|
|
|
|
|
caller_id: Uuid,
|
|
|
|
|
) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
2026-06-18 23:02:17 +02:00
|
|
|
/// Gets a folder by its path within the caller's tree.
|
|
|
|
|
///
|
|
|
|
|
/// Scoped by `user_id` because `storage.folders.path` is unique
|
|
|
|
|
/// only within a single user's drive after D0 — multiple users
|
|
|
|
|
/// share names like `"Personal"` for their default-drive root
|
|
|
|
|
/// folder (docs/plan/drive.md §10). Pre-D0 the wrapper name
|
|
|
|
|
/// embedded the username and made the path globally unique;
|
|
|
|
|
/// post-D0 the caller_id filter is required.
|
2026-06-19 01:08:07 +02:00
|
|
|
async fn get_folder_by_path(&self, path: &str, user_id: Uuid)
|
|
|
|
|
-> Result<FolderDto, DomainError>;
|
2026-05-20 15:39:53 +02:00
|
|
|
|
|
|
|
|
/// Lists folders within a parent folder
|
|
|
|
|
async fn list_folders(&self, parent_id: Option<&str>) -> Result<Vec<FolderDto>, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Lists folders scoped to a specific owner (for user-facing endpoints).
|
|
|
|
|
/// At root level, only returns folders belonging to this user.
|
2026-05-21 11:07:04 +02:00
|
|
|
async fn list_folders_with_perms(
|
2026-05-20 15:39:53 +02:00
|
|
|
&self,
|
|
|
|
|
parent_id: Option<&str>,
|
|
|
|
|
owner_id: Uuid,
|
|
|
|
|
) -> Result<Vec<FolderDto>, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Lists folders with pagination
|
|
|
|
|
async fn list_folders_paginated(
|
|
|
|
|
&self,
|
|
|
|
|
parent_id: Option<&str>,
|
|
|
|
|
pagination: &crate::application::dtos::pagination::PaginationRequestDto,
|
|
|
|
|
) -> Result<crate::application::dtos::pagination::PaginatedResponseDto<FolderDto>, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Lists folders with pagination, scoped to a specific owner.
|
2026-05-21 11:07:04 +02:00
|
|
|
async fn list_folders_paginated_with_perms(
|
2026-05-20 15:39:53 +02:00
|
|
|
&self,
|
|
|
|
|
parent_id: Option<&str>,
|
|
|
|
|
owner_id: Uuid,
|
|
|
|
|
pagination: &crate::application::dtos::pagination::PaginationRequestDto,
|
|
|
|
|
) -> Result<crate::application::dtos::pagination::PaginatedResponseDto<FolderDto>, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Renames a folder (ownership verified against caller_id)
|
|
|
|
|
async fn rename_folder_with_perms(
|
|
|
|
|
&self,
|
|
|
|
|
id: &str,
|
|
|
|
|
dto: RenameFolderDto,
|
|
|
|
|
caller_id: Uuid,
|
|
|
|
|
) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Moves a folder to another parent (ownership verified against caller_id)
|
|
|
|
|
async fn move_folder_with_perms(
|
|
|
|
|
&self,
|
|
|
|
|
id: &str,
|
|
|
|
|
dto: MoveFolderDto,
|
|
|
|
|
caller_id: Uuid,
|
|
|
|
|
) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Deletes a folder (ownership verified against caller_id)
|
|
|
|
|
async fn delete_folder_with_perms(&self, id: &str, caller_id: Uuid) -> Result<(), DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Creates a root-level home folder for a user during registration.
|
2026-06-18 13:29:41 +02:00
|
|
|
/// `drive_id` is the user's personal drive; the wrapper folder stays
|
|
|
|
|
/// during the D0 dual-write window (retires in M2b later).
|
2026-05-20 15:39:53 +02:00
|
|
|
async fn create_home_folder(
|
|
|
|
|
&self,
|
|
|
|
|
user_id: Uuid,
|
2026-06-18 13:29:41 +02:00
|
|
|
drive_id: Uuid,
|
2026-05-20 15:39:53 +02:00
|
|
|
name: String,
|
|
|
|
|
) -> Result<FolderDto, DomainError>;
|
|
|
|
|
|
|
|
|
|
/// Lists every folder in a subtree rooted at `folder_id` (inclusive),
|
|
|
|
|
/// ordered by path. Uses ltree `<@` — single GiST-indexed query.
|
|
|
|
|
///
|
|
|
|
|
/// Default: returns an empty vec (stubs / mocks).
|
|
|
|
|
async fn list_subtree_folders(&self, folder_id: &str) -> Result<Vec<FolderDto>, DomainError> {
|
|
|
|
|
let _ = folder_id;
|
|
|
|
|
Ok(Vec::new())
|
|
|
|
|
}
|
|
|
|
|
}
|