forked from neri/datatrash
Add curl instructions, extract copy into own file
This commit is contained in:
parent
83ea1a15c7
commit
12544034af
43
src/main.rs
43
src/main.rs
|
@ -6,7 +6,7 @@ use actix_files::{Files, NamedFile};
|
|||
use actix_multipart::Multipart;
|
||||
use actix_web::{
|
||||
error,
|
||||
http::header::{ContentDisposition, DispositionParam, DispositionType},
|
||||
http::header::{ContentDisposition, DispositionParam, DispositionType, ACCEPT},
|
||||
middleware,
|
||||
web::{self, Bytes},
|
||||
App, Error, FromRequest, HttpRequest, HttpResponse, HttpServer,
|
||||
|
@ -24,16 +24,23 @@ use sqlx::{
|
|||
};
|
||||
use std::env;
|
||||
|
||||
const INDEX_HTML: &str = include_str!("../template/index.html");
|
||||
const UPLOAD_HTML: &str = include_str!("../template/upload.html");
|
||||
const VIEW_HTML: &str = include_str!("../template/view.html");
|
||||
|
||||
async fn index() -> Result<NamedFile, Error> {
|
||||
Ok(NamedFile::open("./static/index.html")
|
||||
.map_err(|_| error::ErrorNotFound(""))?
|
||||
.disable_content_disposition())
|
||||
async fn index(req: web::HttpRequest) -> Result<HttpResponse, Error> {
|
||||
let upload_url = format!("{}/upload", get_host_url(&req));
|
||||
let index_html = INDEX_HTML.replace("{upload_url}", upload_url.as_str());
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(index_html))
|
||||
}
|
||||
|
||||
// multipart data
|
||||
// required: either 'file' or 'text'
|
||||
// optional: 'keep_for' default to 30 minutes
|
||||
async fn upload(
|
||||
req: web::HttpRequest,
|
||||
payload: Multipart,
|
||||
db: web::Data<PgPool>,
|
||||
expiry_watch_sender: web::Data<Sender<()>>,
|
||||
|
@ -88,24 +95,34 @@ async fn upload(
|
|||
expiry_watch_sender.send(()).await;
|
||||
|
||||
let redirect = if kind == FileKind::BINARY && original_name.is_some() {
|
||||
format!("/upload/{}/{}", file_id, original_name.unwrap())
|
||||
format!("/upload/{}/{}", file_id, original_name.as_ref().unwrap())
|
||||
} else {
|
||||
format!("/upload/{}", file_id)
|
||||
};
|
||||
|
||||
let url = get_file_url(&req, &file_id, original_name.as_deref());
|
||||
Ok(HttpResponse::SeeOther()
|
||||
.header("location", redirect)
|
||||
.finish())
|
||||
.body(format!("{}\n", url)))
|
||||
}
|
||||
|
||||
fn get_host_url(req: &web::HttpRequest) -> String {
|
||||
let conn = req.connection_info();
|
||||
format!("{}://{}", conn.scheme(), conn.host())
|
||||
}
|
||||
|
||||
fn get_file_url(req: &web::HttpRequest, id: &str, name: Option<&str>) -> String {
|
||||
if let Some(name) = name {
|
||||
format!("{}/file/{}/{}", get_host_url(req), id, name)
|
||||
} else {
|
||||
format!("{}/file/{}", get_host_url(req), id)
|
||||
}
|
||||
}
|
||||
|
||||
async fn uploaded(req: web::HttpRequest) -> Result<HttpResponse, Error> {
|
||||
let id = req.match_info().query("id");
|
||||
let name = req.match_info().get("name");
|
||||
let conn = req.connection_info();
|
||||
let url = if let Some(name) = name {
|
||||
format!("{}://{}/file/{}/{}", conn.scheme(), conn.host(), id, name)
|
||||
} else {
|
||||
format!("{}://{}/file/{}", conn.scheme(), conn.host(), id)
|
||||
};
|
||||
let url = get_file_url(&req, id, name);
|
||||
let upload_html = UPLOAD_HTML.replace("{url}", url.as_str());
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
|
|
|
@ -11,17 +11,17 @@ pub(crate) async fn parse_multipart(
|
|||
filename: &Path,
|
||||
) -> Result<(Option<String>, DateTime<Local>, FileKind), error::Error> {
|
||||
let mut original_name: Option<String> = None;
|
||||
let mut timeout: Option<String> = None;
|
||||
let mut keep_for: Option<String> = None;
|
||||
let mut kind: Option<FileKind> = None;
|
||||
|
||||
while let Ok(Some(field)) = payload.try_next().await {
|
||||
let name = get_field_name(&field)?;
|
||||
let name = name.as_str();
|
||||
match name {
|
||||
"validity_secs" => {
|
||||
timeout = Some(parse_string(name, field).await?);
|
||||
"keep_for" => {
|
||||
keep_for = Some(parse_string(name, field).await?);
|
||||
}
|
||||
"content" => {
|
||||
"file" => {
|
||||
let file_original_name = get_original_filename(&field);
|
||||
if file_original_name == None || file_original_name.as_deref() == Some("") {
|
||||
continue;
|
||||
|
@ -35,7 +35,7 @@ pub(crate) async fn parse_multipart(
|
|||
.await
|
||||
.map_err(|_| error::ErrorInternalServerError("could not write file"))?;
|
||||
}
|
||||
"text_content" => {
|
||||
"text" => {
|
||||
if original_name.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
@ -58,12 +58,11 @@ pub(crate) async fn parse_multipart(
|
|||
}
|
||||
}
|
||||
|
||||
let validity_secs = timeout
|
||||
.ok_or_else(|| error::ErrorBadRequest("field validity_secs not set"))?
|
||||
.parse()
|
||||
.map_err(|e| {
|
||||
error::ErrorBadRequest(format!("field validity_secs is not a number: {}", e))
|
||||
})?;
|
||||
let validity_secs = keep_for
|
||||
.map(|timeout| timeout.parse())
|
||||
.transpose()
|
||||
.map_err(|e| error::ErrorBadRequest(format!("field validity_secs is not a number: {}", e)))?
|
||||
.unwrap_or(1800); // default to 30 minutes
|
||||
let max_validity_secs = Duration::days(31).num_seconds();
|
||||
if validity_secs > max_validity_secs {
|
||||
return Err(error::ErrorBadRequest(format!(
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
const button = document.getElementById("copy");
|
||||
button.onclick = () => {
|
||||
if (!navigator.clipboard) {
|
||||
button.innerText = "nicht unterstützt";
|
||||
return;
|
||||
}
|
||||
const content = document.getElementsByClassName("copy-content")[0];
|
||||
navigator.clipboard.writeText(content.textContent).then(
|
||||
(_) => {
|
||||
button.innerText = "kopiert!";
|
||||
},
|
||||
(_) => {
|
||||
button.innerText = "nicht unterstützt";
|
||||
}
|
||||
);
|
||||
};
|
|
@ -71,3 +71,7 @@ a.button:visited {
|
|||
.button.main:hover {
|
||||
background-color: forestgreen;
|
||||
}
|
||||
|
||||
.usage {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
|
|
@ -13,19 +13,14 @@
|
|||
<form action="/upload" method="POST" enctype="multipart/form-data">
|
||||
<label for="file-upload">datei</label>
|
||||
<br />
|
||||
<input id="file-upload" type="file" name="content" />
|
||||
<input id="file-upload" type="file" name="file" />
|
||||
<br />
|
||||
<label for="text-upload">oder asciitrash</label>
|
||||
<br />
|
||||
<textarea
|
||||
id="text-upload"
|
||||
name="text_content"
|
||||
rows="20"
|
||||
cols="120"
|
||||
></textarea>
|
||||
<textarea id="text-upload" name="text" rows="20" cols="120"></textarea>
|
||||
<br />
|
||||
<label for="validity_secs">gültig für</label>
|
||||
<select id="validity_secs" name="validity_secs">
|
||||
<label for="keep_for">gültig für</label>
|
||||
<select id="keep_for" name="keep_for">
|
||||
<option value="1800">30 minuten</option>
|
||||
<option value="3600">60 minuten</option>
|
||||
<option value="43200">12 stunden</option>
|
||||
|
@ -36,6 +31,16 @@
|
|||
<br />
|
||||
<input class="main button" type="submit" value="hochladen" />
|
||||
</form>
|
||||
<section class="usage">
|
||||
<pre>
|
||||
file upload
|
||||
curl -F 'file=@yourfile.rs' {upload_url}
|
||||
text upload
|
||||
curl -F 'text=your text' {upload_url}
|
||||
including time
|
||||
curl -F 'text=your text' -F 'keep_for=1800' {upload_url}
|
||||
</pre>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -11,27 +11,10 @@
|
|||
<h1><a href="/">datatrash</a></h1>
|
||||
<p>
|
||||
datei-link:
|
||||
<a id="link" href="{url}">
|
||||
{url}
|
||||
</a>
|
||||
<a id="link" class="copy-content" href="{url}">{url}</a>
|
||||
</p>
|
||||
<button id="copy" class="main button" onclick="copyToClipboard()">
|
||||
link kopieren
|
||||
</button>
|
||||
<button id="copy" class="main button">link kopieren</button>
|
||||
</main>
|
||||
<script lang="javascript">
|
||||
function copyToClipboard() {
|
||||
const button = document.getElementById("copy");
|
||||
if (!navigator.clipboard) {
|
||||
button.innerText = "nicht unterstützt";
|
||||
return;
|
||||
}
|
||||
const anchor = document.getElementById("link");
|
||||
navigator.clipboard.writeText(anchor.href).then(
|
||||
_ => { button.innerText = "kopiert!"; },
|
||||
_ => { button.innerText = "nicht unterstützt"; },
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<script src="/static/copy.js" lang="javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -9,26 +9,13 @@
|
|||
<body>
|
||||
<main>
|
||||
<h1><a href="/">datatrash</a></h1>
|
||||
<textarea id="text" rows="20" cols="120" readonly>{text}</textarea>
|
||||
<textarea id="text" rows="20" cols="120" class="copy-content" readonly>
|
||||
{text}</textarea
|
||||
>
|
||||
<br />
|
||||
<a class="main button" href="?raw">herunterladen</a>
|
||||
<button id="copy" class="button" onclick="copyToClipboard()">
|
||||
text kopieren
|
||||
</button>
|
||||
<button id="copy" class="button">text kopieren</button>
|
||||
</main>
|
||||
<script lang="javascript">
|
||||
function copyToClipboard() {
|
||||
const button = document.getElementById("copy");
|
||||
if (!navigator.clipboard) {
|
||||
button.innerText = "nicht unterstützt";
|
||||
return;
|
||||
}
|
||||
const textarea = document.getElementById("text");
|
||||
navigator.clipboard.writeText(textarea.value).then(
|
||||
_ => { button.innerText = "kopiert!"; },
|
||||
_ => { button.innerText = "nicht unterstützt"; },
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<script src="/static/copy.js" lang="javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue