46 lines
1.3 KiB
Rust
46 lines
1.3 KiB
Rust
use axum::{body::Body, http::header, response::IntoResponse};
|
|
use tokio_util::io::ReaderStream;
|
|
|
|
use crate::prelude::*;
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Params {
|
|
file_id: Uuid,
|
|
}
|
|
|
|
pub async fn download(
|
|
Query(params): Query<Params>,
|
|
State(state): State<AppState>,
|
|
claims: Claims,
|
|
) -> GeneralResult<impl IntoResponse> {
|
|
db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
|
|
.await
|
|
.map_err(GeneralError::permissions)?
|
|
.can_read_guard()?;
|
|
|
|
let mut name = db::file::get_name(params.file_id, &state.pool)
|
|
.await
|
|
.handle_internal("Error getting file info")?
|
|
.ok_or_else(GeneralError::item_not_found)?;
|
|
name = name
|
|
.chars()
|
|
.fold(String::with_capacity(name.len()), |mut result, char| {
|
|
if ['\\', '"'].contains(&char) {
|
|
result.push('\\');
|
|
}
|
|
result.push(char);
|
|
result
|
|
});
|
|
|
|
let file = state
|
|
.storage
|
|
.read(params.file_id)
|
|
.await
|
|
.handle_internal("Error reading the file")?;
|
|
let body = Body::from_stream(ReaderStream::new(file));
|
|
let disposition = format!("attachment; filename=\"{name}\"");
|
|
let headers = [(header::CONTENT_DISPOSITION, disposition)];
|
|
|
|
Ok((headers, body))
|
|
}
|