feat: hashids
This commit is contained in:
parent
e258bcc2bd
commit
b5da40fbdc
10 changed files with 2165 additions and 16 deletions
2067
Cargo.lock
generated
Normal file
2067
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,7 @@ env_logger = "0.9.0"
|
||||||
actix-web-httpauth = "0.6.0"
|
actix-web-httpauth = "0.6.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
syntect = "5.0"
|
syntect = "5.0"
|
||||||
|
harsh = "0.2"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
|
@ -68,6 +68,9 @@ pub struct Args {
|
||||||
|
|
||||||
#[clap(short, long, env = "MICROBIN_NO_FILE_UPLOAD")]
|
#[clap(short, long, env = "MICROBIN_NO_FILE_UPLOAD")]
|
||||||
pub no_file_upload: bool,
|
pub no_file_upload: bool,
|
||||||
|
|
||||||
|
#[clap(long, env = "MICROBIN_HASH_IDS")]
|
||||||
|
pub hash_ids: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::dbio::save_to_file;
|
use crate::dbio::save_to_file;
|
||||||
use crate::pasta::PastaFile;
|
use crate::pasta::PastaFile;
|
||||||
use crate::util::animalnumbers::to_animal_names;
|
use crate::util::animalnumbers::to_animal_names;
|
||||||
|
use crate::util::hashids::to_hashids;
|
||||||
use crate::util::misc::is_valid_url;
|
use crate::util::misc::is_valid_url;
|
||||||
use crate::{AppState, Pasta, ARGS};
|
use crate::{AppState, Pasta, ARGS};
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
|
@ -126,8 +127,11 @@ pub async fn create(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::fs::create_dir_all(format!("./pasta_data/public/{}", &new_pasta.id_as_animals()))
|
std::fs::create_dir_all(format!(
|
||||||
.unwrap();
|
"./pasta_data/public/{}",
|
||||||
|
&new_pasta.id_as_animals()
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let filepath = format!(
|
let filepath = format!(
|
||||||
"./pasta_data/public/{}/{}",
|
"./pasta_data/public/{}/{}",
|
||||||
|
@ -157,7 +161,12 @@ pub async fn create(
|
||||||
|
|
||||||
save_to_file(&pastas);
|
save_to_file(&pastas);
|
||||||
|
|
||||||
|
let slug = if ARGS.hash_ids {
|
||||||
|
to_hashids(id)
|
||||||
|
} else {
|
||||||
|
to_animal_names(id)
|
||||||
|
};
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, to_animal_names(id))))
|
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, slug)))
|
||||||
.finish())
|
.finish())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::args::Args;
|
||||||
use crate::dbio::save_to_file;
|
use crate::dbio::save_to_file;
|
||||||
use crate::endpoints::errors::ErrorTemplate;
|
use crate::endpoints::errors::ErrorTemplate;
|
||||||
use crate::util::animalnumbers::to_u64;
|
use crate::util::animalnumbers::to_u64;
|
||||||
|
use crate::util::hashids::to_u64 as hashid_to_u64;
|
||||||
use crate::util::misc::remove_expired;
|
use crate::util::misc::remove_expired;
|
||||||
use crate::{AppState, Pasta, ARGS};
|
use crate::{AppState, Pasta, ARGS};
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
|
@ -20,7 +21,11 @@ struct EditTemplate<'a> {
|
||||||
pub async fn get_edit(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
pub async fn get_edit(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
remove_expired(&mut pastas);
|
remove_expired(&mut pastas);
|
||||||
|
|
||||||
|
@ -59,7 +64,11 @@ pub async fn post_edit(
|
||||||
.finish());
|
.finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
|
@ -85,7 +94,10 @@ pub async fn post_edit(
|
||||||
save_to_file(&pastas);
|
save_to_file(&pastas);
|
||||||
|
|
||||||
return Ok(HttpResponse::Found()
|
return Ok(HttpResponse::Found()
|
||||||
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, pastas[i].id_as_animals())))
|
.append_header((
|
||||||
|
"Location",
|
||||||
|
format!("{}/pasta/{}", ARGS.public_path, pastas[i].id_as_animals()),
|
||||||
|
))
|
||||||
.finish());
|
.finish());
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::args::{Args, ARGS};
|
||||||
use crate::endpoints::errors::ErrorTemplate;
|
use crate::endpoints::errors::ErrorTemplate;
|
||||||
use crate::pasta::Pasta;
|
use crate::pasta::Pasta;
|
||||||
use crate::util::animalnumbers::to_u64;
|
use crate::util::animalnumbers::to_u64;
|
||||||
|
use crate::util::hashids::to_u64 as hashid_to_u64;
|
||||||
use crate::util::misc::remove_expired;
|
use crate::util::misc::remove_expired;
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
|
@ -19,7 +20,13 @@ struct PastaTemplate<'a> {
|
||||||
pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
println!("{}", id);
|
||||||
|
|
||||||
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
println!("{}", id);
|
println!("{}", id);
|
||||||
|
|
||||||
|
@ -47,7 +54,11 @@ pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
|
||||||
pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> HttpResponse {
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
remove_expired(&mut pastas);
|
remove_expired(&mut pastas);
|
||||||
|
|
||||||
|
@ -74,7 +85,11 @@ pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> Ht
|
||||||
pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> String {
|
pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> String {
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
remove_expired(&mut pastas);
|
remove_expired(&mut pastas);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::args::ARGS;
|
||||||
use crate::endpoints::errors::ErrorTemplate;
|
use crate::endpoints::errors::ErrorTemplate;
|
||||||
use crate::pasta::PastaFile;
|
use crate::pasta::PastaFile;
|
||||||
use crate::util::animalnumbers::to_u64;
|
use crate::util::animalnumbers::to_u64;
|
||||||
|
use crate::util::hashids::to_u64 as hashid_to_u64;
|
||||||
use crate::util::misc::remove_expired;
|
use crate::util::misc::remove_expired;
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
@ -19,20 +20,30 @@ pub async fn remove(data: web::Data<AppState>, id: web::Path<String>) -> HttpRes
|
||||||
|
|
||||||
let mut pastas = data.pastas.lock().unwrap();
|
let mut pastas = data.pastas.lock().unwrap();
|
||||||
|
|
||||||
let id = to_u64(&*id.into_inner()).unwrap_or(0);
|
let id = if ARGS.hash_ids {
|
||||||
|
hashid_to_u64(&*id).unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
to_u64(&*id.into_inner()).unwrap_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
for (i, pasta) in pastas.iter().enumerate() {
|
for (i, pasta) in pastas.iter().enumerate() {
|
||||||
if pasta.id == id {
|
if pasta.id == id {
|
||||||
// remove the file itself
|
// remove the file itself
|
||||||
if let Some(PastaFile { name, .. }) = &pasta.file {
|
if let Some(PastaFile { name, .. }) = &pasta.file {
|
||||||
if fs::remove_file(format!("./pasta_data/public/{}/{}", pasta.id_as_animals(), name))
|
if fs::remove_file(format!(
|
||||||
.is_err()
|
"./pasta_data/public/{}/{}",
|
||||||
|
pasta.id_as_animals(),
|
||||||
|
name
|
||||||
|
))
|
||||||
|
.is_err()
|
||||||
{
|
{
|
||||||
log::error!("Failed to delete file {}!", name)
|
log::error!("Failed to delete file {}!", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// and remove the containing directory
|
// and remove the containing directory
|
||||||
if fs::remove_dir(format!("./pasta_data/public/{}/", pasta.id_as_animals())).is_err() {
|
if fs::remove_dir(format!("./pasta_data/public/{}/", pasta.id_as_animals()))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
log::error!("Failed to delete directory {}!", name)
|
log::error!("Failed to delete directory {}!", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -23,6 +23,7 @@ pub mod util {
|
||||||
pub mod animalnumbers;
|
pub mod animalnumbers;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod dbio;
|
pub mod dbio;
|
||||||
|
pub mod hashids;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod syntaxhighlighter;
|
pub mod syntaxhighlighter;
|
||||||
}
|
}
|
||||||
|
@ -66,8 +67,14 @@ async fn main() -> std::io::Result<()> {
|
||||||
match fs::create_dir_all("./pasta_data/public") {
|
match fs::create_dir_all("./pasta_data/public") {
|
||||||
Ok(dir) => dir,
|
Ok(dir) => dir,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("Couldn't create data directory ./pasta_data/public/: {:?}", error);
|
log::error!(
|
||||||
panic!("Couldn't create data directory ./pasta_data/public/: {:?}", error);
|
"Couldn't create data directory ./pasta_data/public/: {:?}",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
panic!(
|
||||||
|
"Couldn't create data directory ./pasta_data/public/: {:?}",
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::args::ARGS;
|
||||||
use crate::util::animalnumbers::to_animal_names;
|
use crate::util::animalnumbers::to_animal_names;
|
||||||
|
use crate::util::hashids::to_hashids;
|
||||||
use crate::util::syntaxhighlighter::html_highlight;
|
use crate::util::syntaxhighlighter::html_highlight;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
@ -44,7 +46,11 @@ pub struct Pasta {
|
||||||
|
|
||||||
impl Pasta {
|
impl Pasta {
|
||||||
pub fn id_as_animals(&self) -> String {
|
pub fn id_as_animals(&self) -> String {
|
||||||
to_animal_names(self.id)
|
if ARGS.hash_ids {
|
||||||
|
to_hashids(self.id)
|
||||||
|
} else {
|
||||||
|
to_animal_names(self.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn created_as_string(&self) -> String {
|
pub fn created_as_string(&self) -> String {
|
||||||
|
|
18
src/util/hashids.rs
Normal file
18
src/util/hashids.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use harsh::Harsh;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref HARSH: Harsh = Harsh::builder().length(6).build().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_hashids(number: u64) -> String {
|
||||||
|
HARSH.encode(&[number])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_u64(hash_id: &str) -> Result<u64, &str> {
|
||||||
|
let ids = HARSH
|
||||||
|
.decode(hash_id)
|
||||||
|
.map_err(|_e| "Failed to decode hash ID")?;
|
||||||
|
let id = ids.get(0).ok_or("No ID found in hash ID")?;
|
||||||
|
Ok(*id)
|
||||||
|
}
|
Loading…
Reference in a new issue