forked from Maurice/pastabble
Added URL shortener
This commit is contained in:
parent
1d32fb0365
commit
e874e4e473
@ -5,6 +5,8 @@ Welcome at PASTABBLE!
|
||||
## About
|
||||
Pastable is a lightweight and fast pastebin alternative and URL-shortener made by Plabble and written in Rust.
|
||||
|
||||
For usage, see `about.html`
|
||||
|
||||
## Environment variables
|
||||
| Variable | Default |
|
||||
| -------- | ------- |
|
||||
|
13
about.html
13
about.html
@ -17,12 +17,19 @@
|
||||
Get /: Show this page
|
||||
Get /{id}: Get paste by ID and return in plain text
|
||||
Post /: Create new paste (plain text raw body or form parameter 'content') and return random generated key
|
||||
Post /{id}: Create new paste (plain text raw body) and return requested key if available, else random generated key
|
||||
Post /{id}: Create new paste (plain text raw body) and return requested key if available, else random generated key
|
||||
|
||||
Get /to/{id}: Navigate to shortcut link (browser redirect)
|
||||
Post /to: Create new link (plain text raw body or form parameter 'link') and return random generated key
|
||||
Post /to/{id}: Create new link (plain text raw body) and return requested key if available, else random generated key
|
||||
|
||||
FROM TERMINAL
|
||||
Pipe your input into: curl -F 'content=<-' paste.plabble.org -w "\n"
|
||||
Or post it as raw data like: curl paste.plabble.org -H "Content-Type: text/plain" -d @- -w "\n"
|
||||
Pipe your input into: curl -F 'content=<-' paste.plabble.org -w '\n'
|
||||
Or post it as raw data like: curl paste.plabble.org -H 'Content-Type: text/plain' -d @- -w '\n'
|
||||
You can create an alias for this! To get the result: curl paste.plabble.org/YOURID
|
||||
|
||||
For links:
|
||||
Pipe your input into: curl -F 'link=<-' paste.plabble.org/to -w '\n'
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
135
src/main.rs
135
src/main.rs
@ -1,15 +1,15 @@
|
||||
use std::{env, fs};
|
||||
|
||||
use chrono::Utc;
|
||||
use kv::{Config, Store, Json};
|
||||
use kv::{Config, Store, Json, Bucket, Value};
|
||||
use paste::Paste;
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use rouille::{Response, router, try_or_400, post_input};
|
||||
use rouille::{Response, router, try_or_400, post_input, Request};
|
||||
|
||||
mod paste;
|
||||
|
||||
// Generate random key function
|
||||
fn new_key() -> String {
|
||||
fn random_string() -> String {
|
||||
rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(5)
|
||||
@ -17,6 +17,18 @@ fn new_key() -> String {
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Generate key using provided key or generate new one
|
||||
fn generate_key<T : Value>(key: Option<String>, store: &Bucket<String, T>) -> String {
|
||||
let mut new_key = key.unwrap_or(random_string());
|
||||
|
||||
loop {
|
||||
if !store.contains(&new_key).unwrap() {
|
||||
break new_key;
|
||||
}
|
||||
new_key = random_string();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Get settings
|
||||
let port: u16 = env::var("PORT").unwrap_or(String::from("8080")).parse().expect("Failed to parse PORT variable");
|
||||
@ -26,9 +38,13 @@ fn main() {
|
||||
let store = Store::new(config).expect("Failed to initialize database store");
|
||||
let about = fs::read_to_string("./about.html").expect("about.html not found!!");
|
||||
|
||||
// Get pastes bucket (default)
|
||||
// Get pastes bucket
|
||||
let pastes = store.bucket::<String, Json<Paste>>(Some("pastes"))
|
||||
.expect("Failed to open default bucket");
|
||||
.expect("Failed to open pastes bucket");
|
||||
|
||||
// Get links bucket
|
||||
let links = store.bucket::<String, String>(Some("links"))
|
||||
.expect("Failed to open links bucket");
|
||||
|
||||
// Start server
|
||||
println!("Started PASTABBLE server on port {}", port);
|
||||
@ -37,9 +53,22 @@ fn main() {
|
||||
(GET) (/) => {
|
||||
Response::html(&about)
|
||||
},
|
||||
(GET) (/to/{id: String}) => {
|
||||
match links.get(&id).expect("Failed to access links DB") {
|
||||
Some(lnk) => {
|
||||
Response::redirect_301(lnk)
|
||||
},
|
||||
None => {
|
||||
Response::text(format!("Redirect with ID '{}' not found", &id))
|
||||
.with_status_code(404)
|
||||
}
|
||||
}
|
||||
},
|
||||
(POST) (/to/{id: String}) => { register_link(&links, req, Some(id)) },
|
||||
(POST) (/to) => { register_link(&links, req, None) },
|
||||
(GET) (/{id: String}) => {
|
||||
// Get note from database, if exists
|
||||
match pastes.get(&id).expect("Failed to access DB") {
|
||||
match pastes.get(&id).expect("Failed to access pastes DB") {
|
||||
Some(paste) => {
|
||||
Response::text(paste.0.content)
|
||||
},
|
||||
@ -49,45 +78,65 @@ fn main() {
|
||||
}
|
||||
}
|
||||
},
|
||||
(POST) (/{id: String}) => {
|
||||
// Use provided key or generate new one
|
||||
let key = if !id.is_empty() && !pastes.contains(&id).unwrap() {
|
||||
id
|
||||
} else {
|
||||
loop {
|
||||
let new_key = new_key();
|
||||
if !pastes.contains(&new_key).expect("Could not access store") {
|
||||
break new_key;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Try read body from form data, and if not present from request body
|
||||
let body = match post_input!(&req, {
|
||||
content: String
|
||||
}) {
|
||||
Ok(f) => {
|
||||
f.content
|
||||
},
|
||||
Err(_) => {
|
||||
try_or_400!(rouille::input::plain_text_body(&req))
|
||||
}
|
||||
};
|
||||
|
||||
// Create and save new note
|
||||
let paste = Json(Paste {
|
||||
content: body,
|
||||
expires: None,
|
||||
language: None,
|
||||
created: Utc::now()
|
||||
});
|
||||
|
||||
pastes.set(&key, &paste).expect("Failed to save note");
|
||||
|
||||
// Return key
|
||||
Response::text(key)
|
||||
(POST) (/{id: String}) => {
|
||||
let id = if id.is_empty() { None } else { Some(id) };
|
||||
register_paste(&pastes, req, id)
|
||||
},
|
||||
_ => Response::empty_404()
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// Register paste handler
|
||||
fn register_paste(pastes: &Bucket<String, Json<Paste>>, req: &Request, id: Option<String>) -> Response {
|
||||
|
||||
// Try read body from form data, and if not present from request body
|
||||
let body = match post_input!(req, {
|
||||
content: String
|
||||
}) {
|
||||
Ok(f) => {
|
||||
f.content
|
||||
},
|
||||
Err(_) => {
|
||||
try_or_400!(rouille::input::plain_text_body(req))
|
||||
}
|
||||
};
|
||||
|
||||
// Create and save new note
|
||||
let paste = Json(Paste {
|
||||
content: body,
|
||||
expires: None,
|
||||
language: None,
|
||||
created: Utc::now()
|
||||
});
|
||||
|
||||
let key = generate_key(id, &pastes);
|
||||
pastes.set(&key, &paste).expect("Failed to save note");
|
||||
pastes.flush().expect("Failed to svae paste to database");
|
||||
|
||||
// Return key
|
||||
Response::text(key)
|
||||
}
|
||||
|
||||
// Register link route handler
|
||||
fn register_link(links: &Bucket<String,String>, req: &Request, id: Option<String>) -> Response {
|
||||
|
||||
// Try read body from form data, and if not present from request body
|
||||
let link = match post_input!(req, {
|
||||
link: String
|
||||
}) {
|
||||
Ok(f) => {
|
||||
f.link
|
||||
},
|
||||
Err(_) => {
|
||||
try_or_400!(rouille::input::plain_text_body(req))
|
||||
}
|
||||
}.trim().to_string();
|
||||
|
||||
let key = generate_key(id, &links);
|
||||
links.set(&key, &link).expect("Failed to save link");
|
||||
links.flush().expect("Failed to save link to database");
|
||||
|
||||
// Return key
|
||||
Response::text(key)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user