Implement cURL API #15
|
@ -1,8 +1,18 @@
|
||||||
use warp::{Filter, reply::Reply, reject::Rejection};
|
use askama::Template;
|
||||||
|
use warp::{Filter, reply::{Reply, html}, reject::Rejection};
|
||||||
|
|
||||||
use crate::web::state::SharedState;
|
use crate::web::{state::SharedState, pages::CurlHelpPage, rejection::HttpReject};
|
||||||
|
|
||||||
pub async fn help(state: SharedState) -> Result<String, Rejection> {
|
pub async fn help(state: SharedState, ua: String) -> Result<Box<dyn Reply>, Rejection> {
|
||||||
|
|
||||||
|
if ! ua.starts_with("curl/") {
|
||||||
|
let page = CurlHelpPage { conf: state.config.clone(), env: state.env.clone() };
|
||||||
|
return Ok(
|
||||||
|
Box::new(
|
||||||
|
html(page.render().map_err(|x| HttpReject::AskamaError(x))?)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let brand = format!(
|
let brand = format!(
|
||||||
"{} \x1b[1m{}\x1b[0m {}",
|
"{} \x1b[1m{}\x1b[0m {}",
|
||||||
|
@ -45,19 +55,20 @@ the HTML used at the regular web UI form wrapped into this URL
|
||||||
\x1b[1;32mIMPORTANT:\x1b[0m Read the terms of service \x1b[1mbefore\x1b[0m uploading the file!
|
\x1b[1;32mIMPORTANT:\x1b[0m Read the terms of service \x1b[1mbefore\x1b[0m uploading the file!
|
||||||
The ToS can be found here: \x1b[34m{instance}/tos\x1b[0m .
|
The ToS can be found here: \x1b[34m{instance}/tos\x1b[0m .
|
||||||
|
|
||||||
{warns}
|
{warns}"
|
||||||
"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(format!("
|
Ok(
|
||||||
|
Box::new(
|
||||||
|
format!("
|
||||||
\x1b[31m┓ ╻\x1b[0m \x1b[35m┏┓•┓ \x1b[0m
|
\x1b[31m┓ ╻\x1b[0m \x1b[35m┏┓•┓ \x1b[0m
|
||||||
\x1b[32m┣┓┃\x1b[0m \x1b[95m┣ ┓┃┏┓\x1b[0m
|
\x1b[32m┣┓┃\x1b[0m \x1b[95m┣ ┓┃┏┓\x1b[0m
|
||||||
\x1b[34m┗┛•\x1b[0m \x1b[35m┻ ┗┗┗━\x1b[0m
|
\x1b[34m┗┛•\x1b[0m \x1b[35m┻ ┗┗┗━\x1b[0m
|
||||||
|
|
||||||
{brand}
|
{brand}
|
||||||
|
|
||||||
{help}
|
{help}
|
||||||
").into())
|
").to_string())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_routes(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
pub fn get_routes(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
||||||
|
@ -67,5 +78,8 @@ pub fn get_routes(state: SharedState) -> impl Filter<Extract = impl Reply, Error
|
||||||
warp::any()
|
warp::any()
|
||||||
.map(move || state.clone())
|
.map(move || state.clone())
|
||||||
)
|
)
|
||||||
|
.and(
|
||||||
|
warp::header::<String>("user-agent")
|
||||||
|
)
|
||||||
.and_then(help)
|
.and_then(help)
|
||||||
}
|
}
|
|
@ -88,6 +88,14 @@ pub struct ErrorPage {
|
||||||
pub link_text: Option<String>
|
pub link_text: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template( path = "curlapi_help.html" )]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct CurlHelpPage {
|
||||||
|
pub env: Env,
|
||||||
|
pub conf: Config
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn uploaded(query: HashMap<String, String>, state: SharedState) -> Result<Html<String>, Rejection> {
|
pub async fn uploaded(query: HashMap<String, String>, state: SharedState) -> Result<Html<String>, Rejection> {
|
||||||
|
|
||||||
if ! query.contains_key("file") {
|
if ! query.contains_key("file") {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
.code {
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid var(--header-sec-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.code-inline {
|
||||||
|
display: inline;
|
||||||
|
font-family: monospace;
|
||||||
|
background: #00000010;
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<link rel='stylesheet' href="/code.css" />
|
||||||
|
<link rel='stylesheet' href="/alert.css" />
|
||||||
|
<link rel='stylesheet' href="/js-only.css" />
|
||||||
|
<style>
|
||||||
|
.copy-btn { font-size: 70%; transform: translateY(-25%); display: inline-block }
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div style="max-width:95vw;width:fit-content;margin:0 auto">
|
||||||
|
<h1 style="text-align:center">Curl API</h1>
|
||||||
|
<p>
|
||||||
|
blek! File has an API for uploading files via cURL.
|
||||||
|
To upload a file via cURL, follow these instructions:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To upload a file, POST it like this:
|
||||||
|
<a href="#" class="copy-btn" data-clipboard-text="curl -X POST {{env.instanceurl}}/curlapi/upload -F'file=@file.txt' -F'tos_consent=on'">
|
||||||
|
Copy!
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div class='code'>
|
||||||
|
curl -X POST {{env.instanceurl}}/curlapi/upload -F'file=@file.txt' -F'tos_consent=on'
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
To add a password, do it like this:
|
||||||
|
<a href="#" class="copy-btn" data-clipboard-text="curl -X POST {{env.instanceurl}}/curlapi/upload -F'file=@file.txt' -F'filename=uwu' -F'tos_consent=on' -F'named=on'">
|
||||||
|
Copy!
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div class='code'>
|
||||||
|
curl -X POST {{env.instanceurl}}/curlapi/upload -F'file=@file.txt' -F'filename=uwu' -F'tos_consent=on' -F'named=on'
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Note that the
|
||||||
|
<span class='code-inline'>named=on</span>
|
||||||
|
switch is required.
|
||||||
|
Its needed because the curl API is basically a wrapper of
|
||||||
|
<a href="/">this</a>
|
||||||
|
HTML form.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="alert danger">
|
||||||
|
<h1 class="alert-title">
|
||||||
|
Important
|
||||||
|
</h1>
|
||||||
|
<p class="alert-text">
|
||||||
|
Read the
|
||||||
|
<a href="/tos">Terms of Service</a>
|
||||||
|
<b>before</b>
|
||||||
|
uploading a file.
|
||||||
|
<br/>
|
||||||
|
You agree to them by adding the
|
||||||
|
<span class="code-inline">tos_consent=on</span>
|
||||||
|
switch.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='alert blue'>
|
||||||
|
<h1 class='alert-title'>Web UI</h1>
|
||||||
|
<div class='alert-text'>
|
||||||
|
<p>
|
||||||
|
Hey, it looks like you are viewing this page from a browser!<br/>
|
||||||
|
You can use the Web UI as well to upload a file!
|
||||||
|
</p>
|
||||||
|
<p style='margin:32px 0'>
|
||||||
|
<a href='/' role='button' class='btn'>
|
||||||
|
Go to the web UI
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="https://unpkg.com/clipboard@2/dist/clipboard.min.js"></script>
|
||||||
|
<script>
|
||||||
|
new ClipboardJS('.copy-btn');
|
||||||
|
{#- -#}
|
||||||
|
( {#- -#}
|
||||||
|
() => { {#- -#}
|
||||||
|
let btns = document.getElementsByClassName('copy-btn') {#- -#}
|
||||||
|
for (const button of btns) { {#- -#}
|
||||||
|
button.onclick = () => { {#- -#}
|
||||||
|
let old = button.innerHTML; {#- -#}
|
||||||
|
button.innerHTML = 'Copied!'; {#- -#}
|
||||||
|
setTimeout(() => { button.innerHTML = old }, 500); {#- -#}
|
||||||
|
} {#- -#}
|
||||||
|
} {#- -#}
|
||||||
|
} {#- -#}
|
||||||
|
)() {#- -#}
|
||||||
|
</script>
|
||||||
|
<script src='/js-only.js'></script>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue