docbox_core/folders/
delete_folder.rs1use crate::events::{TenantEventMessage, TenantEventPublisher};
2use crate::files::delete_file::delete_file;
3use crate::links::delete_link::delete_link;
4use docbox_database::{
5 DbPool,
6 models::{
7 document_box::WithScope,
8 file::File,
9 folder::{Folder, ResolvedFolder},
10 link::Link,
11 },
12};
13use docbox_search::TenantSearchIndex;
14use docbox_storage::TenantStorageLayer;
15use std::collections::VecDeque;
16
17pub enum RemoveStackItem {
19 Folder(Folder),
21 EmptyFolder(Folder),
24 File(File),
26 Link(Link),
28}
29
30pub async fn delete_folder(
31 db: &DbPool,
32 storage: &TenantStorageLayer,
33 search: &TenantSearchIndex,
34 events: &TenantEventPublisher,
35 folder: Folder,
36) -> anyhow::Result<()> {
37 let mut stack = VecDeque::new();
39
40 let document_box = folder.document_box.clone();
41
42 stack.push_back(RemoveStackItem::Folder(folder));
44
45 while let Some(item) = stack.pop_front() {
46 match item {
47 RemoveStackItem::Folder(folder) => {
48 let resolved = ResolvedFolder::resolve(db, &folder).await?;
50
51 stack.push_front(RemoveStackItem::EmptyFolder(folder));
53
54 for item in resolved.folders {
56 stack.push_front(RemoveStackItem::Folder(item));
57 }
58
59 for item in resolved.files {
60 stack.push_front(RemoveStackItem::File(item));
61 }
62
63 for item in resolved.links {
64 stack.push_front(RemoveStackItem::Link(item));
65 }
66 }
67 RemoveStackItem::EmptyFolder(folder) => {
68 internal_delete_folder(db, search, events, folder).await?;
69 }
70 RemoveStackItem::File(file) => {
71 delete_file(db, storage, search, events, file, document_box.clone()).await?;
72 }
73 RemoveStackItem::Link(link) => {
74 delete_link(db, search, events, link, document_box.clone()).await?;
75 }
76 }
77 }
78
79 Ok(())
80}
81
82async fn internal_delete_folder(
85 db: &DbPool,
86 search: &TenantSearchIndex,
87 events: &TenantEventPublisher,
88 folder: Folder,
89) -> anyhow::Result<()> {
90 search.delete_data(folder.id).await?;
92
93 let result = folder
94 .delete(db)
95 .await
96 .inspect_err(|error| tracing::error!(?error, "failed to delete folder"))?;
97
98 let document_box = folder.document_box.clone();
99
100 if result.rows_affected() < 1 {
102 return Ok(());
103 }
104
105 events.publish_event(TenantEventMessage::FolderDeleted(WithScope::new(
107 folder,
108 document_box,
109 )));
110
111 Ok(())
112}