Getting ready for 1.2.0 release: many smaller requests implemented
- Implements #7 - Implements #42 and therefore #64 - Improved #53 - Implements #59 - Implements #61 - Implements #63 - Implements #80 - Implements #84 - Added Info page - Removed Help page - Bumped version number to 1.2.0 - Fixed a bug where wide mode was still 720px wide - Created FUNDING.yml - Reorganised arguments in README.MD and documented new options - Updated SECURITY.MD - Added display of last read time and read count - Increased default width to 800px to make UI less cluttered - Reorganised index page - New, better attach file button I want to spend some time testing these changes and let everyone have a look at them before tagging and releasing new artifacts.
This commit is contained in:
parent
769901c895
commit
44b55ae08e
22 changed files with 977 additions and 327 deletions
|
@ -54,6 +54,9 @@ pub async fn create(
|
|||
private: false,
|
||||
editable: false,
|
||||
created: timenow,
|
||||
read_count: 0,
|
||||
burn_after_reads: 0,
|
||||
last_read: timenow,
|
||||
pasta_type: String::from(""),
|
||||
expiration: 0,
|
||||
};
|
||||
|
@ -78,9 +81,34 @@ pub async fn create(
|
|||
"1hour" => timenow + 60 * 60,
|
||||
"24hour" => timenow + 60 * 60 * 24,
|
||||
"1week" => timenow + 60 * 60 * 24 * 7,
|
||||
"never" => 0,
|
||||
"never" => {
|
||||
if ARGS.no_eternal_pasta {
|
||||
timenow + 60 * 60 * 24 * 7
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::error!("{}", "Unexpected expiration time!");
|
||||
timenow + 60 * 60 * 24 * 7
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
"burn_after" => {
|
||||
while let Some(chunk) = field.try_next().await? {
|
||||
new_pasta.burn_after_reads = match std::str::from_utf8(&chunk).unwrap() {
|
||||
// give an extra read because the user will be redirected to the pasta page automatically
|
||||
"1" => 2,
|
||||
"10" => 10,
|
||||
"100" => 100,
|
||||
"1000" => 1000,
|
||||
"10000" => 10000,
|
||||
"0" => 0,
|
||||
_ => {
|
||||
log::error!("{}", "Unexpected burn after value!");
|
||||
0
|
||||
}
|
||||
};
|
||||
|
@ -126,8 +154,11 @@ pub async fn create(
|
|||
}
|
||||
};
|
||||
|
||||
std::fs::create_dir_all(format!("./pasta_data/public/{}", &new_pasta.id_as_animals()))
|
||||
.unwrap();
|
||||
std::fs::create_dir_all(format!(
|
||||
"./pasta_data/public/{}",
|
||||
&new_pasta.id_as_animals()
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let filepath = format!(
|
||||
"./pasta_data/public/{}/{}",
|
||||
|
@ -158,6 +189,9 @@ pub async fn create(
|
|||
save_to_file(&pastas);
|
||||
|
||||
Ok(HttpResponse::Found()
|
||||
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, to_animal_names(id))))
|
||||
.append_header((
|
||||
"Location",
|
||||
format!("{}/pasta/{}", ARGS.public_path, to_animal_names(id)),
|
||||
))
|
||||
.finish())
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
use crate::args::{Args, ARGS};
|
||||
use actix_web::{get, HttpResponse};
|
||||
use askama::Template;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "help.html")]
|
||||
struct Help<'a> {
|
||||
args: &'a Args,
|
||||
_marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[get("/help")]
|
||||
pub async fn help() -> HttpResponse {
|
||||
HttpResponse::Ok().content_type("text/html").body(
|
||||
Help {
|
||||
args: &ARGS,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
42
src/endpoints/info.rs
Normal file
42
src/endpoints/info.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use crate::args::{Args, ARGS};
|
||||
use crate::pasta::Pasta;
|
||||
use crate::AppState;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use askama::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "info.html")]
|
||||
struct Info<'a> {
|
||||
args: &'a Args,
|
||||
pastas: &'a Vec<Pasta>,
|
||||
status: &'a String,
|
||||
version_string: &'a String,
|
||||
message: &'a String,
|
||||
}
|
||||
|
||||
#[get("/info")]
|
||||
pub async fn info(data: web::Data<AppState>) -> HttpResponse {
|
||||
// get access to the pasta collection
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
// todo status report more sophisticated
|
||||
let mut status = "OK";
|
||||
let mut message = "";
|
||||
|
||||
if ARGS.public_path.to_string() == "" {
|
||||
status = "WARNING";
|
||||
message = "Warning: No public URL set with --public-path parameter. QR code and URL Copying functions have been disabled"
|
||||
}
|
||||
|
||||
HttpResponse::Ok().content_type("text/html").body(
|
||||
Info {
|
||||
args: &ARGS,
|
||||
pastas: &pastas,
|
||||
status: &String::from(status),
|
||||
version_string: &String::from("1.2.0-20221029"),
|
||||
message: &String::from(message),
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
use actix_web::{get, web, HttpResponse};
|
||||
use askama::Template;
|
||||
|
||||
use crate::args::{Args, ARGS};
|
||||
use crate::dbio::save_to_file;
|
||||
use crate::endpoints::errors::ErrorTemplate;
|
||||
use crate::pasta::Pasta;
|
||||
use crate::util::animalnumbers::to_u64;
|
||||
use crate::util::misc::remove_expired;
|
||||
use crate::AppState;
|
||||
use actix_web::rt::time;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use askama::Template;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "pasta.html", escape = "none")]
|
||||
|
@ -17,27 +19,60 @@ struct PastaTemplate<'a> {
|
|||
|
||||
#[get("/pasta/{id}")]
|
||||
pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
// get access to the pasta collection
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
// get the u64 id from the animal names in the path
|
||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
||||
|
||||
println!("{}", id);
|
||||
|
||||
// remove expired pastas (including this one if needed)
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
// find the index of the pasta in the collection based on u64 id
|
||||
let mut index: usize = 0;
|
||||
let mut found: bool = false;
|
||||
for (i, pasta) in pastas.iter().enumerate() {
|
||||
if pasta.id == id {
|
||||
return HttpResponse::Ok().content_type("text/html").body(
|
||||
PastaTemplate {
|
||||
pasta: &pasta,
|
||||
args: &ARGS,
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
);
|
||||
index = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// increment read count
|
||||
pastas[index].read_count = pastas[index].read_count + 1;
|
||||
|
||||
// save the updated read count
|
||||
save_to_file(&pastas);
|
||||
|
||||
// serve pasta in template
|
||||
let response = HttpResponse::Ok().content_type("text/html").body(
|
||||
PastaTemplate {
|
||||
pasta: &pastas[index],
|
||||
args: &ARGS,
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// get current unix time in seconds
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => {
|
||||
log::error!("SystemTime before UNIX EPOCH!");
|
||||
0
|
||||
}
|
||||
} as i64;
|
||||
|
||||
// update last read time
|
||||
pastas[index].last_read = timenow;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// otherwise
|
||||
// send pasta not found error
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(ErrorTemplate { args: &ARGS }.render().unwrap())
|
||||
|
@ -45,26 +80,62 @@ pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
|
|||
|
||||
#[get("/url/{id}")]
|
||||
pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
// get access to the pasta collection
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
// get the u64 id from the animal names in the path
|
||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
||||
|
||||
// remove expired pastas (including this one if needed)
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
// find the index of the pasta in the collection based on u64 id
|
||||
let mut index: usize = 0;
|
||||
let mut found: bool = false;
|
||||
for (i, pasta) in pastas.iter().enumerate() {
|
||||
if pasta.id == id {
|
||||
if pasta.pasta_type == "url" {
|
||||
return HttpResponse::Found()
|
||||
.append_header(("Location", String::from(&pasta.content)))
|
||||
.finish();
|
||||
} else {
|
||||
return HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(ErrorTemplate { args: &ARGS }.render().unwrap());
|
||||
}
|
||||
index = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// increment read count
|
||||
pastas[index].read_count = pastas[index].read_count + 1;
|
||||
|
||||
// save the updated read count
|
||||
save_to_file(&pastas);
|
||||
|
||||
// send redirect if it's a url pasta
|
||||
if pastas[index].pasta_type == "url" {
|
||||
let response = HttpResponse::Found()
|
||||
.append_header(("Location", String::from(&pastas[index].content)))
|
||||
.finish();
|
||||
|
||||
// get current unix time in seconds
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => {
|
||||
log::error!("SystemTime before UNIX EPOCH!");
|
||||
0
|
||||
}
|
||||
} as i64;
|
||||
|
||||
// update last read time
|
||||
pastas[index].last_read = timenow;
|
||||
|
||||
return response;
|
||||
// send error if we're trying to open a non-url pasta as a redirect
|
||||
} else {
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(ErrorTemplate { args: &ARGS }.render().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise
|
||||
// send pasta not found error
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(ErrorTemplate { args: &ARGS }.render().unwrap())
|
||||
|
@ -72,17 +143,50 @@ pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> Ht
|
|||
|
||||
#[get("/raw/{id}")]
|
||||
pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> String {
|
||||
// get access to the pasta collection
|
||||
let mut pastas = data.pastas.lock().unwrap();
|
||||
|
||||
// get the u64 id from the animal names in the path
|
||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
||||
|
||||
// remove expired pastas (including this one if needed)
|
||||
remove_expired(&mut pastas);
|
||||
|
||||
for pasta in pastas.iter() {
|
||||
// find the index of the pasta in the collection based on u64 id
|
||||
let mut index: usize = 0;
|
||||
let mut found: bool = false;
|
||||
for (i, pasta) in pastas.iter().enumerate() {
|
||||
if pasta.id == id {
|
||||
return pasta.content.to_owned();
|
||||
index = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// increment read count
|
||||
pastas[index].read_count = pastas[index].read_count + 1;
|
||||
|
||||
// get current unix time in seconds
|
||||
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(n) => n.as_secs(),
|
||||
Err(_) => {
|
||||
log::error!("SystemTime before UNIX EPOCH!");
|
||||
0
|
||||
}
|
||||
} as i64;
|
||||
|
||||
// update last read time
|
||||
pastas[index].last_read = timenow;
|
||||
|
||||
// save the updated read count
|
||||
save_to_file(&pastas);
|
||||
|
||||
// send raw content of pasta
|
||||
return pastas[index].content.to_owned();
|
||||
}
|
||||
|
||||
// otherwise
|
||||
// send pasta not found error as raw text
|
||||
String::from("Pasta not found! :-(")
|
||||
}
|
||||
|
|
34
src/endpoints/qr.rs
Normal file
34
src/endpoints/qr.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use crate::args::{Args, ARGS};
|
||||
use crate::pasta::Pasta;
|
||||
use crate::util::misc::{self, remove_expired};
|
||||
use crate::AppState;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use askama::Template;
|
||||
use qrcode_generator::QrCodeEcc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "qr.html", escape = "none")]
|
||||
struct QRTemplate<'a> {
|
||||
qr: &'a String,
|
||||
args: &'a Args,
|
||||
}
|
||||
|
||||
#[get("/qr/{id}")]
|
||||
pub async fn getqr(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||
// find the index of the pasta in the collection based on u64 id
|
||||
|
||||
let svg: String = misc::string_to_qr_svg(
|
||||
format!("{}/pasta/{}", &ARGS.public_path, &*id.into_inner()).as_str(),
|
||||
);
|
||||
|
||||
// serve qr code in template
|
||||
HttpResponse::Ok().content_type("text/html").body(
|
||||
QRTemplate {
|
||||
qr: &svg,
|
||||
args: &ARGS,
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue