added support for use of a custom names file
This commit is contained in:
parent
7d5c70ddd6
commit
7abb3c5d11
10 changed files with 120 additions and 69 deletions
|
@ -3,6 +3,7 @@ use lazy_static::lazy_static;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -124,6 +125,11 @@ pub struct Args {
|
||||||
#[clap(long, env = "MICROBIN_CUSTOM_CSS")]
|
#[clap(long, env = "MICROBIN_CUSTOM_CSS")]
|
||||||
pub custom_css: Option<String>,
|
pub custom_css: Option<String>,
|
||||||
|
|
||||||
|
/// Replace built-in animal names file with custom names file for pasta links.
|
||||||
|
/// The file must be newline seperated.
|
||||||
|
#[clap(long, env = "MICROBIN_CUSTOM_NAMES")]
|
||||||
|
pub custom_names: Option<PathBuf>,
|
||||||
|
|
||||||
/// Enable the use of Hash IDs for shorter URLs instead of animal names.
|
/// Enable the use of Hash IDs for shorter URLs instead of animal names.
|
||||||
#[clap(long, env = "MICROBIN_HASH_IDS")]
|
#[clap(long, env = "MICROBIN_HASH_IDS")]
|
||||||
pub hash_ids: bool,
|
pub hash_ids: bool,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
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::hashids::to_hashids;
|
use crate::util::hashids::to_hashids;
|
||||||
use crate::util::misc::is_valid_url;
|
use crate::util::misc::is_valid_url;
|
||||||
|
use crate::util::pasta_id_converter::CONVERTER;
|
||||||
use crate::{AppState, Pasta, ARGS};
|
use crate::{AppState, Pasta, ARGS};
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
use actix_web::{get, web, Error, HttpResponse, Responder};
|
use actix_web::{get, web, Error, HttpResponse, Responder};
|
||||||
|
@ -194,7 +194,7 @@ pub async fn create(
|
||||||
let slug = if ARGS.hash_ids {
|
let slug = if ARGS.hash_ids {
|
||||||
to_hashids(id)
|
to_hashids(id)
|
||||||
} else {
|
} else {
|
||||||
to_animal_names(id)
|
CONVERTER.to_names(id)
|
||||||
};
|
};
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, slug)))
|
.append_header(("Location", format!("{}/pasta/{}", ARGS.public_path, slug)))
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::args::Args;
|
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::hashids::to_u64 as hashid_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::util::pasta_id_converter::CONVERTER;
|
||||||
use crate::{AppState, Pasta, ARGS};
|
use crate::{AppState, Pasta, ARGS};
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
use actix_web::{get, post, web, Error, HttpResponse};
|
use actix_web::{get, post, web, Error, HttpResponse};
|
||||||
|
@ -24,7 +24,7 @@ pub async fn get_edit(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
remove_expired(&mut pastas);
|
remove_expired(&mut pastas);
|
||||||
|
@ -62,7 +62,7 @@ pub async fn post_edit(
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pastas = data.pastas.lock().await;
|
let mut pastas = data.pastas.lock().await;
|
||||||
|
|
|
@ -2,10 +2,10 @@ use crate::args::{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::pasta::Pasta;
|
use crate::pasta::Pasta;
|
||||||
use crate::util::animalnumbers::to_u64;
|
|
||||||
use crate::util::hashids::to_u64 as hashid_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 crate::util::pasta_id_converter::CONVERTER;
|
||||||
|
|
||||||
use actix_web::{get, web, HttpResponse};
|
use actix_web::{get, web, HttpResponse};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
@ -27,7 +27,7 @@ pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove expired pastas (including this one if needed)
|
// remove expired pastas (including this one if needed)
|
||||||
|
@ -92,7 +92,7 @@ pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> Ht
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove expired pastas (including this one if needed)
|
// remove expired pastas (including this one if needed)
|
||||||
|
@ -160,7 +160,7 @@ pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> St
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove expired pastas (including this one if needed)
|
// remove expired pastas (including this one if needed)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::args::{Args, ARGS};
|
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::hashids::to_u64 as hashid_to_u64;
|
use crate::util::hashids::to_u64 as hashid_to_u64;
|
||||||
use crate::util::misc::{self, remove_expired};
|
use crate::util::misc::{self, remove_expired};
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
use crate::util::pasta_id_converter::CONVERTER;
|
||||||
use actix_web::{get, web, HttpResponse};
|
use actix_web::{get, web, HttpResponse};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ pub async fn getqr(data: web::Data<AppState>, id: web::Path<String>) -> HttpResp
|
||||||
let u64_id = if ARGS.hash_ids {
|
let u64_id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id).unwrap_or(0)
|
CONVERTER.to_u64(&id).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove expired pastas (including this one if needed)
|
// remove expired pastas (including this one if needed)
|
||||||
|
|
|
@ -3,10 +3,10 @@ use actix_web::{get, web, HttpResponse};
|
||||||
use crate::args::ARGS;
|
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::hashids::to_u64 as hashid_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 crate::util::pasta_id_converter::CONVERTER;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub async fn remove(data: web::Data<AppState>, id: web::Path<String>) -> HttpRes
|
||||||
let id = if ARGS.hash_ids {
|
let id = if ARGS.hash_ids {
|
||||||
hashid_to_u64(&id).unwrap_or(0)
|
hashid_to_u64(&id).unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
to_u64(&id.into_inner()).unwrap_or(0)
|
CONVERTER.to_u64(&id.into_inner()).unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, pasta) in pastas.iter().enumerate() {
|
for (i, pasta) in pastas.iter().enumerate() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub mod args;
|
||||||
pub mod pasta;
|
pub mod pasta;
|
||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
pub mod animalnumbers;
|
pub mod pasta_id_converter;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod dbio;
|
pub mod dbio;
|
||||||
pub mod hashids;
|
pub mod hashids;
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::path::Path;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use crate::args::ARGS;
|
use crate::args::ARGS;
|
||||||
use crate::util::animalnumbers::to_animal_names;
|
|
||||||
use crate::util::hashids::to_hashids;
|
use crate::util::hashids::to_hashids;
|
||||||
|
use crate::util::pasta_id_converter::CONVERTER;
|
||||||
use crate::util::syntaxhighlighter::html_highlight;
|
use crate::util::syntaxhighlighter::html_highlight;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
@ -55,7 +55,7 @@ impl Pasta {
|
||||||
if ARGS.hash_ids {
|
if ARGS.hash_ids {
|
||||||
to_hashids(self.id)
|
to_hashids(self.id)
|
||||||
} else {
|
} else {
|
||||||
to_animal_names(self.id)
|
CONVERTER.to_names(self.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
const ANIMAL_NAMES: &[&str] = &[
|
|
||||||
"ant", "eel", "mole", "sloth", "ape", "emu", "monkey", "snail", "bat", "falcon", "mouse",
|
|
||||||
"snake", "bear", "fish", "otter", "spider", "bee", "fly", "parrot", "squid", "bird", "fox",
|
|
||||||
"panda", "swan", "bison", "frog", "pig", "tiger", "camel", "gecko", "pigeon", "toad", "cat",
|
|
||||||
"goat", "pony", "turkey", "cobra", "goose", "pug", "turtle", "crow", "hawk", "rabbit", "viper",
|
|
||||||
"deer", "horse", "rat", "wasp", "dog", "jaguar", "raven", "whale", "dove", "koala", "seal",
|
|
||||||
"wolf", "duck", "lion", "shark", "worm", "eagle", "lizard", "sheep", "zebra",
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn to_animal_names(mut number: u64) -> String {
|
|
||||||
let mut result: Vec<&str> = Vec::new();
|
|
||||||
|
|
||||||
if number == 0 {
|
|
||||||
return ANIMAL_NAMES[0].parse().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut power = 6;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let digit = number / ANIMAL_NAMES.len().pow(power) as u64;
|
|
||||||
if !(result.is_empty() && digit == 0) {
|
|
||||||
result.push(ANIMAL_NAMES[digit as usize]);
|
|
||||||
}
|
|
||||||
number -= digit * ANIMAL_NAMES.len().pow(power) as u64;
|
|
||||||
if power > 0 {
|
|
||||||
power -= 1;
|
|
||||||
} else if power == 0 || number == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.join("-")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_u64(animal_names: &str) -> Result<u64, &str> {
|
|
||||||
let mut result: u64 = 0;
|
|
||||||
|
|
||||||
let animals: Vec<&str> = animal_names.split('-').collect();
|
|
||||||
|
|
||||||
let mut pow = animals.len();
|
|
||||||
for animal in animals {
|
|
||||||
pow -= 1;
|
|
||||||
let animal_index = ANIMAL_NAMES.iter().position(|&r| r == animal);
|
|
||||||
match animal_index {
|
|
||||||
None => return Err("Failed to convert animal name to u64!"),
|
|
||||||
Some(_) => {
|
|
||||||
result += (animal_index.unwrap() * ANIMAL_NAMES.len().pow(pow as u32)) as u64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
98
src/util/pasta_id_converter.rs
Normal file
98
src/util/pasta_id_converter.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::args::ARGS;
|
||||||
|
|
||||||
|
const ANIMAL_NAMES: &[&str] = &[
|
||||||
|
"ant", "eel", "mole", "sloth", "ape", "emu", "monkey", "snail", "bat", "falcon", "mouse",
|
||||||
|
"snake", "bear", "fish", "otter", "spider", "bee", "fly", "parrot", "squid", "bird", "fox",
|
||||||
|
"panda", "swan", "bison", "frog", "pig", "tiger", "camel", "gecko", "pigeon", "toad", "cat",
|
||||||
|
"goat", "pony", "turkey", "cobra", "goose", "pug", "turtle", "crow", "hawk", "rabbit", "viper",
|
||||||
|
"deer", "horse", "rat", "wasp", "dog", "jaguar", "raven", "whale", "dove", "koala", "seal",
|
||||||
|
"wolf", "duck", "lion", "shark", "worm", "eagle", "lizard", "sheep", "zebra",
|
||||||
|
];
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
pub static ref CONVERTER: PastaIdConverter = PastaIdConverter::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert pasta IDs to names and vice versa
|
||||||
|
pub struct PastaIdConverter {
|
||||||
|
names: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PastaIdConverter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let names;
|
||||||
|
if let Some(names_path) = &ARGS.custom_names {
|
||||||
|
let names_data = fs::read_to_string(names_path)
|
||||||
|
.expect("path for the names file should contain a names file");
|
||||||
|
names = names_data
|
||||||
|
.split('\n')
|
||||||
|
.map(ToOwned::to_owned)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
} else {
|
||||||
|
names = ANIMAL_NAMES
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(ToOwned::to_owned)
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { names }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_names(&self, mut number: u64) -> String {
|
||||||
|
let mut result: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
|
if number == 0 {
|
||||||
|
return self.names[0].parse().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut power = 6;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let digit = number / self.names.len().pow(power) as u64;
|
||||||
|
if !(result.is_empty() && digit == 0) {
|
||||||
|
result.push(&self.names[digit as usize]);
|
||||||
|
}
|
||||||
|
number -= digit * self.names.len().pow(power) as u64;
|
||||||
|
if power > 0 {
|
||||||
|
power -= 1;
|
||||||
|
} else if power == 0 || number == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.join("-")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_u64(&self, pasta_id: &str) -> Result<u64, &str> {
|
||||||
|
let mut result: u64 = 0;
|
||||||
|
|
||||||
|
let names: Vec<&str> = pasta_id.split('-').collect();
|
||||||
|
|
||||||
|
let mut pow = names.len();
|
||||||
|
for name in names {
|
||||||
|
pow -= 1;
|
||||||
|
let name_index = self.names.iter().position(|r| r == name);
|
||||||
|
match name_index {
|
||||||
|
None => return Err("Failed to convert animal name to u64!"),
|
||||||
|
Some(_) => {
|
||||||
|
result += (name_index.unwrap() * self.names.len().pow(pow as u32)) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PastaIdConverter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue