cognee_delete/
authorized.rs1use std::sync::Arc;
9
10use cognee_database::{AclDb, DeleteDb};
11use uuid::Uuid;
12
13use crate::{DeleteError, DeletePreview, DeleteRequest, DeleteResult, DeleteScope, DeleteService};
14
15pub struct AuthorizedDeleteService {
21 inner: DeleteService,
22 acl_db: Arc<dyn AclDb>,
23 database: Arc<dyn DeleteDb>,
24}
25
26impl AuthorizedDeleteService {
27 pub fn new(inner: DeleteService, acl_db: Arc<dyn AclDb>, database: Arc<dyn DeleteDb>) -> Self {
32 Self {
33 inner,
34 acl_db,
35 database,
36 }
37 }
38
39 pub async fn preview(
41 &self,
42 request: &DeleteRequest,
43 principal_id: Uuid,
44 ) -> Result<DeletePreview, DeleteError> {
45 self.check_authorization(request, principal_id).await?;
46 self.inner.preview(request).await
47 }
48
49 pub async fn execute(
51 &self,
52 request: &DeleteRequest,
53 principal_id: Uuid,
54 ) -> Result<DeleteResult, DeleteError> {
55 self.check_authorization(request, principal_id).await?;
56 self.inner.execute(request).await
57 }
58
59 async fn check_authorization(
62 &self,
63 request: &DeleteRequest,
64 principal_id: Uuid,
65 ) -> Result<(), DeleteError> {
66 match &request.scope {
67 DeleteScope::Data {
68 owner_id,
69 data_id,
70 dataset_name,
71 ..
72 } => {
73 if let Some(ds_name) = dataset_name {
74 let dataset_id = self.resolve_dataset_id(*owner_id, ds_name).await?;
75 self.require_delete_permission(principal_id, dataset_id)
76 .await?;
77 } else {
78 let datasets = self
83 .database
84 .list_datasets_for_data(*data_id)
85 .await
86 .map_err(|e| {
87 DeleteError::Runtime(format!(
88 "Failed to list datasets for data {data_id}: {e}"
89 ))
90 })?;
91
92 for ds in &datasets {
93 if ds.owner_id == *owner_id {
94 self.require_delete_permission(principal_id, ds.id).await?;
95 }
96 }
97 }
98 }
99 DeleteScope::Dataset {
100 owner_id,
101 dataset_name,
102 } => {
103 let dataset_id = self.resolve_dataset_id(*owner_id, dataset_name).await?;
104 self.require_delete_permission(principal_id, dataset_id)
105 .await?;
106 }
107 DeleteScope::User { owner_id } => {
108 let authorized = self
113 .acl_db
114 .authorized_dataset_ids(principal_id, "delete")
115 .await
116 .map_err(|e| DeleteError::Runtime(format!("ACL query failed: {e}")))?;
117
118 let owner_datasets = self
119 .database
120 .list_datasets_by_owner(*owner_id)
121 .await
122 .map_err(|e| {
123 DeleteError::Runtime(format!("Failed to list owner datasets: {e}"))
124 })?;
125
126 for ds in &owner_datasets {
127 if !authorized.contains(&ds.id) {
128 return Err(DeleteError::PermissionDenied(format!(
129 "Principal {} does not have 'delete' permission on dataset '{}'",
130 principal_id, ds.name
131 )));
132 }
133 }
134 }
135 DeleteScope::All => {
136 let authorized = self
140 .acl_db
141 .authorized_dataset_ids(principal_id, "delete")
142 .await
143 .map_err(|e| DeleteError::Runtime(format!("ACL query failed: {e}")))?;
144
145 let all_datasets = self.database.list_datasets().await.map_err(|e| {
146 DeleteError::Runtime(format!("Failed to list all datasets: {e}"))
147 })?;
148
149 for ds in &all_datasets {
150 if !authorized.contains(&ds.id) {
151 return Err(DeleteError::PermissionDenied(format!(
152 "Principal {} does not have 'delete' permission on dataset '{}'",
153 principal_id, ds.name
154 )));
155 }
156 }
157 }
158 }
159
160 Ok(())
161 }
162
163 async fn resolve_dataset_id(
165 &self,
166 owner_id: Uuid,
167 dataset_name: &str,
168 ) -> Result<Uuid, DeleteError> {
169 let dataset = self
170 .database
171 .get_dataset_by_name(dataset_name, owner_id, None)
172 .await
173 .map_err(|e| {
174 DeleteError::Runtime(format!("Failed to resolve dataset '{dataset_name}': {e}"))
175 })?
176 .ok_or_else(|| {
177 DeleteError::Validation(format!(
178 "Dataset '{dataset_name}' was not found for owner {owner_id}"
179 ))
180 })?;
181
182 Ok(dataset.id)
183 }
184
185 async fn require_delete_permission(
187 &self,
188 principal_id: Uuid,
189 dataset_id: Uuid,
190 ) -> Result<(), DeleteError> {
191 let has_perm = self
192 .acl_db
193 .has_permission(principal_id, dataset_id, "delete")
194 .await
195 .map_err(|e| DeleteError::Runtime(format!("ACL check failed: {e}")))?;
196
197 if !has_perm {
198 return Err(DeleteError::PermissionDenied(format!(
199 "Principal {principal_id} does not have 'delete' permission on dataset {dataset_id}"
200 )));
201 }
202
203 Ok(())
204 }
205}