diff --git a/fluxer_admin/src/api/archives.rs b/fluxer_admin/src/api/archives.rs index 939604a7f..71676c9de 100644 --- a/fluxer_admin/src/api/archives.rs +++ b/fluxer_admin/src/api/archives.rs @@ -2,7 +2,7 @@ use crate::api::generated::types as generated_types; -use super::client::{AdminApiClient, ApiResult}; +use super::client::{AdminApiClient, ApiError, ApiResult}; use super::types::{Archive, ArchiveDownloadUrlResponse, ListArchivesResponse}; impl AdminApiClient { @@ -45,16 +45,31 @@ impl AdminApiClient { include_expired: bool, requested_by: Option<&str>, ) -> ApiResult { - let query_params = [ - ("subject_type", subject_type), - ("subject_id", subject_id.unwrap_or_default()), - ("requested_by", requested_by.unwrap_or_default()), - ( - "include_expired", - if include_expired { "true" } else { "false" }, - ), - ]; - self.get("/admin/archives", Some(&query_params)).await + let subject_id = subject_id.filter(|id| !id.is_empty()); + let search_every_subject_type = subject_type == "all" && subject_id.is_some(); + let subject_types: &[&str] = if search_every_subject_type { + &["user", "guild"] + } else { + std::slice::from_ref(&subject_type) + }; + let mut archives = Vec::new(); + for &subject_type in subject_types { + let query_params = [ + ("subject_type", subject_type), + ("subject_id", subject_id.unwrap_or_default()), + ("requested_by", requested_by.unwrap_or_default()), + ( + "include_expired", + if include_expired { "true" } else { "false" }, + ), + ]; + match self.get("/admin/archives", Some(&query_params)).await { + Ok(ListArchivesResponse { archives: page }) => archives.extend(page), + Err(ApiError::Http { status: 403, .. }) if search_every_subject_type => {} + Err(error) => return Err(error), + } + } + Ok(ListArchivesResponse { archives }) } pub async fn get_archive_download_url( diff --git a/fluxer_api/src/api/admin/controllers/ArchiveAdminController.ts b/fluxer_api/src/api/admin/controllers/ArchiveAdminController.ts index 11a914e90..b9b10146a 100644 --- a/fluxer_api/src/api/admin/controllers/ArchiveAdminController.ts +++ b/fluxer_api/src/api/admin/controllers/ArchiveAdminController.ts @@ -30,6 +30,19 @@ function requireArchiveSubjectAccess(adminAcls: Set, subjectType: 'user' throw new MissingACLError(subjectType === 'user' ? AdminACLs.ARCHIVE_TRIGGER_USER : AdminACLs.ARCHIVE_TRIGGER_GUILD); } +function resolveListSubjectType(adminAcls: Set, requested: 'all' | 'user' | 'guild'): 'all' | 'user' | 'guild' { + if (requested !== 'all') { + requireArchiveSubjectAccess(adminAcls, requested); + return requested; + } + const viewUser = canViewArchive(adminAcls, 'user'); + const viewGuild = canViewArchive(adminAcls, 'guild'); + if (viewUser && viewGuild) return 'all'; + if (viewUser) return 'user'; + if (viewGuild) return 'guild'; + throw new MissingACLError(AdminACLs.ARCHIVE_VIEW_ALL); +} + export function ArchiveAdminController(app: HonoApp) { app.post( '/admin/users/:user_id/archives', @@ -104,18 +117,8 @@ export function ArchiveAdminController(app: HonoApp) { const adminArchiveService = ctx.get('adminArchiveService'); const adminAcls = ctx.get('adminUserAcls'); const query = ctx.req.valid('query'); - if ( - query.subject_type === 'all' && - !adminAcls.has(AdminACLs.ARCHIVE_VIEW_ALL) && - !adminAcls.has(AdminACLs.WILDCARD) - ) { - throw new MissingACLError(AdminACLs.ARCHIVE_VIEW_ALL); - } - if (query.subject_type !== 'all') { - requireArchiveSubjectAccess(adminAcls, query.subject_type); - } const result = await adminArchiveService.listArchives({ - subjectType: query.subject_type, + subjectType: resolveListSubjectType(adminAcls, query.subject_type), subjectId: query.subject_id ?? undefined, requestedBy: query.requested_by ?? undefined, limit: query.limit,