1use crate::prelude::*;
4use cloudillo_core::abac::can_view_item;
5use cloudillo_core::file_access;
6use cloudillo_types::meta_adapter::FileView;
7use cloudillo_types::types::AccessLevel;
8
9pub async fn filter_files_by_visibility(
18 app: &App,
19 tn_id: TnId,
20 subject_id_tag: &str,
21 is_authenticated: bool,
22 tenant_id_tag: &str,
23 subject_roles: &[Box<str>],
24 files: Vec<FileView>,
25) -> ClResult<Vec<FileView>> {
26 if files.is_empty() {
28 return Ok(files);
29 }
30
31 let rels = app.meta_adapter.get_relationships(tn_id, &[subject_id_tag]).await?;
33 let (following, connected) = rels.get(subject_id_tag).copied().unwrap_or((false, false));
34
35 let visible_files: Vec<FileView> = files
37 .into_iter()
38 .filter(|file| {
39 let owner_tag = file
41 .owner
42 .as_ref()
43 .and_then(|o| if o.id_tag.is_empty() { None } else { Some(o.id_tag.as_ref()) })
44 .unwrap_or(tenant_id_tag);
45
46 can_view_item(
48 subject_id_tag,
49 is_authenticated,
50 owner_tag,
51 tenant_id_tag,
52 file.visibility,
53 following,
54 connected,
55 None,
56 )
57 })
58 .collect();
59
60 if !is_authenticated || subject_id_tag.is_empty() {
62 return Ok(visible_files
63 .into_iter()
64 .map(|mut file| {
65 file.access_level = Some(AccessLevel::Read);
66 file
67 })
68 .collect());
69 }
70
71 let mut result = Vec::with_capacity(visible_files.len());
73 for mut file in visible_files {
74 let owner_tag = file
76 .owner
77 .as_ref()
78 .and_then(|o| if o.id_tag.is_empty() { None } else { Some(o.id_tag.as_ref()) })
79 .unwrap_or(tenant_id_tag);
80
81 let ctx = file_access::FileAccessCtx {
82 user_id_tag: subject_id_tag,
83 tenant_id_tag,
84 user_roles: subject_roles,
85 };
86 let access_level =
87 file_access::get_access_level(app, tn_id, &file.file_id, owner_tag, &ctx).await;
88
89 file.access_level = Some(access_level);
90 result.push(file);
91 }
92
93 Ok(result)
94}
95
96