Add curl instructions, extract copy into own file

master
neri 2 years ago
parent 83ea1a15c7
commit 12544034af
  1. 43
      src/main.rs
  2. 21
      src/multipart.rs
  3. 16
      static/copy.js
  4. 4
      static/index.css
  5. 27
      template/index.html
  6. 23
      template/upload.html
  7. 23
      template/view.html

@ -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;
}

@ -12,20 +12,15 @@
<h1>datatrash</h1>
<form action="/upload" method="POST" enctype="multipart/form-data">
<label for="file-upload">datei</label>
<br/>
<input id="file-upload" type="file" name="content" />
<br />
<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>
<br />
<label for="validity_secs">gültig für</label>
<select id="validity_secs" name="validity_secs">
<textarea id="text-upload" name="text" rows="20" cols="120"></textarea>
<br />
<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…
Cancel
Save