diff --git a/actix/Cargo.lock b/actix/Cargo.lock index fb9da0a..8fe58e6 100644 --- a/actix/Cargo.lock +++ b/actix/Cargo.lock @@ -485,6 +485,8 @@ dependencies = [ "rand", "regex", "rusqlite", + "serde", + "serde_json", ] [[package]] diff --git a/actix/Cargo.toml b/actix/Cargo.toml index 440ee82..763fb79 100644 --- a/actix/Cargo.toml +++ b/actix/Cargo.toml @@ -32,3 +32,5 @@ rand = "0.8.5" actix-session = { version = "0.9.0", features = ["cookie-session"] } env_logger = "0.11.1" nanoid = "0.4.0" +serde_json = "1.0.115" +serde = { version = "1.0.197", features = [ "derive" ] } diff --git a/actix/src/database.rs b/actix/src/database.rs index 53e32e6..0dc66a1 100644 --- a/actix/src/database.rs +++ b/actix/src/database.rs @@ -1,4 +1,12 @@ use rusqlite::Connection; +use serde::Serialize; + +#[derive(Serialize)] +pub struct DbRow { + shortlink: String, + longlink: String, + hits: i64, +} pub fn find_url(shortlink: &str, db: &Connection) -> Option { let mut statement = db @@ -10,17 +18,19 @@ pub fn find_url(shortlink: &str, db: &Connection) -> Option { .ok() } -pub fn getall(db: &Connection) -> Vec { +pub fn getall(db: &Connection) -> Vec { let mut statement = db.prepare_cached("SELECT * FROM urls").unwrap(); let mut data = statement.query([]).unwrap(); - let mut links: Vec = Vec::new(); + let mut links: Vec = Vec::new(); while let Some(row) = data.next().unwrap() { - let short_url: String = row.get("short_url").unwrap(); - let long_url: String = row.get("long_url").unwrap(); - let hits: i64 = row.get("hits").unwrap(); - links.push(format!("{short_url},{long_url},{hits}")); + let row_struct = DbRow { + shortlink: row.get("short_url").unwrap(), + longlink: row.get("long_url").unwrap(), + hits: row.get("hits").unwrap(), + }; + links.push(row_struct); } links diff --git a/actix/src/utils.rs b/actix/src/utils.rs index 1575596..68bad35 100644 --- a/actix/src/utils.rs +++ b/actix/src/utils.rs @@ -5,6 +5,13 @@ use nanoid::nanoid; use rand::seq::SliceRandom; use regex::Regex; use rusqlite::Connection; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Url { + shortlink: String, + longlink: String, +} pub fn get_longurl(shortlink: String, db: &Connection) -> Option { if validate_link(&shortlink) { @@ -21,12 +28,11 @@ fn validate_link(link: &str) -> bool { pub fn getall(db: &Connection) -> String { let links = database::getall(db); - links.join("\n") + serde_json::to_string(&links).unwrap() } pub fn add_link(req: String, db: &Connection) -> (bool, String) { - let chunks: Vec<&str> = req.split(';').collect(); - let longlink = String::from(chunks[0]); + let mut chunks: Url = serde_json::from_str(&req).unwrap(); let style = env::var("slug_style").unwrap_or(String::from("Pair")); let len_str = env::var("slug_length").unwrap_or(String::from("8")); @@ -35,20 +41,16 @@ pub fn add_link(req: String, db: &Connection) -> (bool, String) { len = 4; } - let mut shortlink; - if chunks.len() > 1 { - shortlink = chunks[1].to_string().to_lowercase(); - if shortlink.is_empty() { - shortlink = gen_link(style, len); - } - } else { - shortlink = gen_link(style, len); + if chunks.shortlink.is_empty() { + chunks.shortlink = gen_link(style, len); } - if validate_link(shortlink.as_str()) && get_longurl(shortlink.clone(), db).is_none() { + if validate_link(chunks.shortlink.as_str()) + && get_longurl(chunks.shortlink.clone(), db).is_none() + { ( - database::add_link(shortlink.clone(), longlink, db), - shortlink, + database::add_link(chunks.shortlink.clone(), chunks.longlink, db), + chunks.shortlink, ) } else { (false, String::from("shortUrl not valid or already in use")) diff --git a/resources/static/script.js b/resources/static/script.js index b7d19ca..c9d6194 100644 --- a/resources/static/script.js +++ b/resources/static/script.js @@ -31,16 +31,7 @@ const refreshData = async () => { document.getElementById("login-dialog").showModal(); document.getElementById("password").focus(); } else { - data = reply - .split("\n") - .filter(line => line !== "") - .map(line => line.split(",")) - .map(arr => ({ - short: arr[0], - long: arr[1], - hits: arr[2] - })); - + data = JSON.parse(reply) displayData(data); } }; @@ -87,18 +78,18 @@ const showAlert = async (text, col) => { const TR = (row, site) => { const tr = document.createElement("tr"); - const longTD = TD(A_LONG(row.long), "Long URL"); + const longTD = TD(A_LONG(row["longlink"]), "Long URL"); var shortTD = null; if (window.isSecureContext) { - shortTD = TD(A_SHORT(row.short, site), "Short URL"); + shortTD = TD(A_SHORT(row["shortlink"], site), "Short URL"); } else { - shortTD = TD(A_SHORT_INSECURE(row.short, site), "Short URL"); + shortTD = TD(A_SHORT_INSECURE(row["shortlink"], site), "Short URL"); } - hitsTD = TD(row.hits); + hitsTD = TD(row["hits"]); hitsTD.setAttribute("label", "Hits"); hitsTD.setAttribute("name", "hitsColumn"); - const btn = deleteButton(row.short); + const btn = deleteButton(row["shortlink"]); tr.appendChild(shortTD); tr.appendChild(longTD); @@ -168,14 +159,19 @@ const TD = (s, u) => { const submitForm = () => { const form = document.forms.namedItem("new-url-form"); - const longUrl = form.elements["longUrl"]; - const shortUrl = form.elements["shortUrl"]; + const data ={ + "longlink": form.elements["longUrl"].value, + "shortlink": form.elements["shortUrl"].value, + }; const url = prepSubdir("/api/new"); fetch(url, { method: "POST", - body: `${longUrl.value};${shortUrl.value}` + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), }) .then(res => { if (!res.ok) {