bfile/filed/src/web/forms.rs

171 lines
5.2 KiB
Rust
Raw Normal View History

2023-09-30 11:26:47 +02:00
/*
forms.rs - All the forms
*/
2023-10-01 10:41:34 +02:00
use std::collections::HashMap;
2023-09-30 11:26:47 +02:00
2023-10-01 04:05:08 +02:00
use askama::Template;
2023-10-01 04:05:39 +02:00
use warp::{Filter, reply::Reply, reject::Rejection, filters::multipart::FormData, http::StatusCode};
2023-09-30 11:26:47 +02:00
use futures_util::TryStreamExt;
use bytes::BufMut;
2023-10-01 06:44:19 +02:00
use serde::Serialize;
2023-10-13 01:25:51 +02:00
use crate::files::{File, lookup::LookupKind, DeleteMode};
2023-09-30 11:26:47 +02:00
2023-10-13 15:37:18 +02:00
use super::{state::SharedState, pages::{BadActionReq, UploadSuccessPage, self}, rejection::HttpReject};
2023-10-01 02:14:35 +02:00
2023-10-13 15:37:18 +02:00
#[derive(Debug, Serialize, Clone)]
2023-10-01 06:44:19 +02:00
struct FormElement {
data: Vec<u8>,
mime: String
}
2023-10-01 10:40:37 +02:00
impl FormElement {
pub fn as_str_or_reject(self: &Self) -> Result<String, Rejection> {
Ok(String::from_utf8(self.data.clone()).map_err(|err| warp::reject::custom(HttpReject::FromUtf8Error(err)))?)
}
}
2023-10-01 06:44:19 +02:00
2023-10-01 10:40:37 +02:00
pub async fn upload(form: FormData, state: SharedState) -> Result<Box<dyn Reply>, Rejection> {
2023-09-30 11:26:47 +02:00
2023-10-01 06:44:19 +02:00
let params: HashMap<String, FormElement> = form.and_then(|mut field| async move {
2023-09-30 11:26:47 +02:00
let mut bytes: Vec<u8> = vec![];
while let Some(byte) = field.data().await {
bytes.put(byte.unwrap())
}
2023-10-01 06:44:19 +02:00
Ok((field.name().into(), FormElement { data: bytes, mime: field.content_type().unwrap_or("text/plain").to_string() }))
2023-10-01 04:05:08 +02:00
}).try_collect()
.await
.map_err(|err| warp::reject::custom(HttpReject::WarpError(err.into())))?;
// check that required fields exist
let mut all_exist = true;
2023-10-01 06:44:19 +02:00
let _ = vec!["delmode", "file", "filename", "password"].iter().for_each(|x| {
2023-10-01 04:05:08 +02:00
let field = x.to_string();
if ! params.contains_key(&field) {
all_exist = false;
}
});
if ! all_exist {
return Ok(Box::new(
warp::reply::with_status(
warp::reply::html(
2023-10-01 13:45:12 +02:00
BadActionReq {
2023-10-20 17:49:36 +02:00
env: state.env.clone(),
conf: state.config.clone()
2023-10-01 13:45:12 +02:00
}
2023-10-01 04:05:08 +02:00
.render()
.map_err(|err| warp::reject::custom(HttpReject::AskamaError(err.into())))?
),
StatusCode::BAD_REQUEST
)
))
}
2023-09-30 11:26:47 +02:00
let check_off = FormElement { data: "off".as_bytes().to_vec(), mime: "text/plain".into() };
2023-10-01 06:44:19 +02:00
let data = params.get("file").unwrap();
2023-10-13 01:25:51 +02:00
let delmode = params.get("delmode").unwrap();
2023-10-01 06:44:19 +02:00
let named = params.get("named");
let filename = params.get("filename").unwrap();
2023-10-13 15:37:18 +02:00
let tos_check = match params.get("tos_consent") {
Some(v) => (*v).clone(),
None => check_off.clone()
};
let protected = params.get("passworded").unwrap_or(&check_off.clone()).as_str_or_reject()?;
let protected = protected == "on";
let password: Option<String> = {
let pass = params.get("password");
if protected && pass.is_some() {
Some(pass.unwrap().as_str_or_reject()?)
} else {
None
}
2023-10-13 15:37:18 +02:00
};
2023-10-01 10:40:37 +02:00
let mut is_named = named.is_none();
2023-10-13 15:37:18 +02:00
let tos_check = tos_check.as_str_or_reject()?;
if tos_check != "on" {
return Ok(
Box::new(
warp::reply::html(
pages::ErrorPage {
env: state.env,
2023-10-20 17:49:36 +02:00
conf: state.config.clone(),
2023-10-13 15:37:18 +02:00
error_text: "You must consent to the terms and conditions!".into(),
link: Some("/".into()),
link_text: Some("Go back".into())
}
.render()
.map_err(
|err|
warp::reject::custom(HttpReject::AskamaError(err))
)?
)
)
)
}
2023-10-13 01:25:51 +02:00
let delmode = delmode.as_str_or_reject()?;
if delmode != "30" && delmode != "dl" {
return Err(warp::reject::custom(HttpReject::StringError("delmode is neither 30 or dl!".into())));
}
2023-10-01 10:40:37 +02:00
if named.is_some() {
is_named = named.unwrap().as_str_or_reject()? == "on";
}
2023-10-01 06:44:19 +02:00
let file = File::create(
data.data.clone(),
data.mime.clone(),
match named {
Some(named) => {
2023-10-01 10:40:37 +02:00
if named.as_str_or_reject()?
2023-10-01 06:44:19 +02:00
.to_string() == "on" {
2023-10-01 10:40:37 +02:00
Some(filename.as_str_or_reject()?)
2023-10-01 06:44:19 +02:00
} else {
None
}
},
None => None
},
2023-10-13 01:25:51 +02:00
state.env.clone(),
{
if delmode == "30" {
DeleteMode::Time
} else {
DeleteMode::TimeOrDownload
}
},
password
2023-10-01 10:40:37 +02:00
).await
.map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
state.file_mgr.save(&file, {
if is_named {
LookupKind::ByName
} else {
LookupKind::ByHash
}
}).map_err(|err| warp::reject::custom(HttpReject::StringError(err.to_string())))?;
2023-10-01 06:44:19 +02:00
2023-10-10 13:56:28 +02:00
let uploaded = UploadSuccessPage {
env: state.env.clone(),
2023-10-20 17:49:36 +02:00
conf: state.config.clone(),
2023-10-11 15:34:19 +02:00
link: file.leftmost_link()
2023-10-10 13:56:28 +02:00
};
Ok(Box::new(warp::reply::html(uploaded.render().unwrap())))
2023-09-30 11:26:47 +02:00
}
2023-10-01 02:14:35 +02:00
pub fn get_routes(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
2023-09-30 11:26:47 +02:00
warp::post().and(
2023-10-01 02:14:35 +02:00
warp::multipart::form()
.and(warp::any().map(move || state.clone()))
.and_then(upload)
2023-09-30 11:26:47 +02:00
)
}