feat(drive): remove create_home_folder
remove create_home_folder() & ensure_home_folder()
now: on_user_created() and on_user_login both() call provision_if_needed()
which calls **create_personal_drive_atomic()**
add a helper to find Personal drive for a user and also it's root directorry
This commit is contained in:
@@ -88,6 +88,30 @@ pub trait DriveRepository: Send + Sync + 'static {
|
||||
user_id: Uuid,
|
||||
) -> Result<DriveWithRootName, DriveRepositoryError>;
|
||||
|
||||
/// Canonical "what is this user's home root folder id?" lookup.
|
||||
///
|
||||
/// Returns `Some(uuid)` for any internal user with a default personal
|
||||
/// drive (the lifecycle hook provisions one at registration), and
|
||||
/// `None` for users who have no default drive (external users; users
|
||||
/// created before the hook existed). The id identifies the user's
|
||||
/// home **by drive ownership** (`default_for_user == user_id`),
|
||||
/// never by folder name — users can rename their home, so any code
|
||||
/// that wants to ask "is this folder the user's home?" must compare
|
||||
/// folder ids, not names.
|
||||
///
|
||||
/// Storage errors (DB unreachable, etc.) bubble up as `Err`; the
|
||||
/// "user simply has no home" case is `Ok(None)`, not an error.
|
||||
async fn home_root_folder_id_for(
|
||||
&self,
|
||||
user_id: Uuid,
|
||||
) -> Result<Option<Uuid>, DriveRepositoryError> {
|
||||
match self.find_default_for_user(user_id).await {
|
||||
Ok(d) => Ok(Some(d.drive.root_folder_id)),
|
||||
Err(DriveRepositoryError::NotFound(_)) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// List drives the caller can read, resolved via `role_grants` for
|
||||
/// `resource_type='drive'`. The caller's group memberships are
|
||||
/// expanded by the engine's `subject_match_set`; that expanded set
|
||||
@@ -110,3 +134,40 @@ impl DriveKind {
|
||||
DriveKind::parse(s).ok_or_else(|| DriveRepositoryError::InvalidKind(s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate the user's home root folder within a generic list of items,
|
||||
/// identifying it by **drive ownership** (never by folder name — users
|
||||
/// can rename their home).
|
||||
///
|
||||
/// `id_fn` extracts a candidate `Uuid` from each item. The callsite
|
||||
/// commonly works with `FolderDto` (whose `id` is a `String`); the
|
||||
/// closure is `|f| Uuid::parse_str(&f.id).ok()`. Items whose ids can't
|
||||
/// be parsed are simply skipped — `position` ignores them.
|
||||
///
|
||||
/// Defined as a free function (not a trait method) so the
|
||||
/// `DriveRepository` trait stays `dyn`-compatible. Generic over both
|
||||
/// the repo (`R`) and the item shape (`T`); accepts both concrete repo
|
||||
/// types and `&dyn DriveRepository`.
|
||||
///
|
||||
/// Returns `None` when:
|
||||
/// * The user has no default drive (external users, pre-hook accounts).
|
||||
/// * The user's home root folder id isn't present in `items`.
|
||||
/// * The repo lookup errored (storage error is swallowed to None —
|
||||
/// callers wanting fail-loud semantics should call
|
||||
/// `home_root_folder_id_for` directly).
|
||||
pub async fn position_of_user_home_root_folder<R, T>(
|
||||
drive_repo: &R,
|
||||
user_id: Uuid,
|
||||
items: &[T],
|
||||
id_fn: impl Fn(&T) -> Option<Uuid>,
|
||||
) -> Option<usize>
|
||||
where
|
||||
R: DriveRepository + ?Sized,
|
||||
{
|
||||
let home_id = drive_repo
|
||||
.home_root_folder_id_for(user_id)
|
||||
.await
|
||||
.ok()
|
||||
.flatten()?;
|
||||
items.iter().position(|item| id_fn(item) == Some(home_id))
|
||||
}
|
||||
|
||||
@@ -136,18 +136,6 @@ pub trait FolderRepository: Send + Sync + 'static {
|
||||
/// Permanently deletes a folder (used by the trash)
|
||||
async fn delete_folder_permanently(&self, folder_id: &str) -> Result<(), DomainError>;
|
||||
|
||||
/// Creates a root-level home folder for a user inside their personal drive.
|
||||
/// Called during user registration / first login to maintain the wrapper-
|
||||
/// folder convention through the D0 dual-write window (the wrapper itself
|
||||
/// retires in a follow-up migration; for now it stays as a real folder
|
||||
/// row stamped with `drive_id`).
|
||||
async fn create_home_folder(
|
||||
&self,
|
||||
user_id: Uuid,
|
||||
drive_id: Uuid,
|
||||
name: String,
|
||||
) -> Result<Folder, DomainError>;
|
||||
|
||||
/// Lists every folder in a subtree rooted at `folder_id` (inclusive).
|
||||
///
|
||||
/// Uses ltree `<@` for a single GiST-indexed scan. The result is
|
||||
|
||||
Reference in New Issue
Block a user