add Edit function

This commit is contained in:
minoplhy 2024-10-31 23:08:51 +07:00
parent 201d0b319f
commit abb48c68c5
Signed by: minoplhy
GPG Key ID: 41D406044E2434BF
6 changed files with 132 additions and 12 deletions

View File

@ -77,6 +77,15 @@ pub fn delete_link(shortlink: String, db: &Connection) -> bool {
}
}
// Edit Existing Long link.
pub fn edit_link(shortlink: String, longlink: String, db: &Connection) -> bool {
db.execute(
"UPDATE urls SET long_url = ?1 WHERE short_url = ?2;",
[longlink, shortlink],
)
.is_ok()
}
// Open the DB, and create schema if missing
pub fn open_db(path: String) -> Connection {
let db = Connection::open(path).expect("Unable to open database!");

View File

@ -63,6 +63,7 @@ async fn main() -> Result<()> {
.service(services::siteurl)
.service(services::version)
.service(services::add_link)
.service(services::edit_link)
.service(services::delete_link)
.service(services::login)
.service(services::logout)

View File

@ -4,11 +4,7 @@
use actix_files::NamedFile;
use actix_session::Session;
use actix_web::{
delete, get,
http::StatusCode,
post,
web::{self, Redirect},
Either, HttpResponse, Responder,
delete, get, http::StatusCode, post, put, web::{self, Redirect}, Either, HttpResponse, Responder
};
use std::env;
@ -128,6 +124,26 @@ pub async fn logout(session: Session) -> HttpResponse {
}
}
// Edit link
#[put("/api/edit/{shortlink}")]
pub async fn edit_link(
req: String,
shortlink: web::Path<String>,
data: web::Data<AppState>,
session: Session,
) -> HttpResponse {
if env::var("public_mode") == Ok(String::from("Enable")) || auth::validate(session) {
let out = utils::edit_link(req, shortlink.to_string(), &data.db);
if out.0 {
HttpResponse::Created().body(out.1)
} else {
HttpResponse::Conflict().body(out.1)
}
} else {
HttpResponse::Unauthorized().body("Not logged in!")
}
}
// Delete a given shortlink
#[delete("/api/del/{shortlink}")]
pub async fn delete_link(
@ -144,4 +160,4 @@ pub async fn delete_link(
} else {
HttpResponse::Unauthorized().body("Not logged in!")
}
}
}

View File

@ -17,6 +17,11 @@ struct URLPair {
longlink: String,
}
#[derive(Deserialize)]
struct EditLinkJson {
longlink: String,
}
// Request the DB for searching an URL
pub fn get_longurl(shortlink: String, db: &Connection) -> Option<String> {
if validate_link(&shortlink) {
@ -76,6 +81,46 @@ pub fn add_link(req: String, db: &Connection) -> (bool, String) {
}
}
// Make Check then edit the longurl link
pub fn edit_link(req: String, shortlink: String, db: &Connection) -> (bool, String) {
let chunks: EditLinkJson;
if let Ok(json) = serde_json::from_str(&req) {
chunks = json;
} else {
// shorturl should always be supplied, even if empty
return (false, String::from("Invalid request!"));
}
if shortlink.is_empty() {
(false, String::from("Invaild edit parameter received."));
}
if longurl_compares(shortlink.clone(), chunks.longlink.clone(), db)
{
(
database::edit_link(shortlink.clone(), chunks.longlink, db),
shortlink,
)
} else {
(
false,
String::from("Long/Short URL not valid or already in use!"),
)
}
}
// Doing Longurl check(Type None or existed?)
pub fn longurl_compares(shorturl: String, longurl:String, db: &Connection) -> bool {
if get_longurl(shorturl.clone(), db).is_none() {
return false;
}
if get_longurl(shorturl.clone(), db).unwrap() == longurl {
return false;
}
return true;
}
// Check if link, and request DB to delete it if exists
pub fn delete_link(shortlink: String, db: &Connection) -> bool {
if validate_link(shortlink.as_str()) {

View File

@ -35,10 +35,10 @@
<input type="url" name="longUrl" id="longUrl" placeholder="Please enter a valid URL"
onblur="addProtocol(this)" required />
</div>
<div class=" pure-control-group">
<div class="pure-control-group">
<label for="shortUrl">Short URL (optional)</label>
<input type="text" name="shortUrl" id="shortUrl" placeholder="Only a-z, 0-9, - and _ are allowed"
pattern="[a-z0-9\-_]+" title="Only a-z, 0-9, - and _ are allowed"/>
pattern="[a-z0-9\-_]+" title="Only a-z, 0-9, - and _ are allowed" />
</div>
<div class="pure-controls" id="controls">
<button class="pure-button pure-button-primary">Shorten!</button>
@ -56,6 +56,7 @@
<td id="short-url-header">Short URL (click to copy)</td>
<td>Long URL</td>
<td name="hitsColumn">Hits</td>
<td name="editBtn">Edit</td>
<td name="deleteBtn">&times;</td>
</tr>
</thead>

View File

@ -105,19 +105,20 @@ const TR = (row, site) => {
var shortTD = null;
if (window.isSecureContext) {
shortTD = TD(A_SHORT(row["shortlink"], site), "Short URL");
}
else {
} else {
shortTD = TD(A_SHORT_INSECURE(row["shortlink"], site), "Short URL");
}
let hitsTD = TD(row["hits"]);
hitsTD.setAttribute("label", "Hits");
hitsTD.setAttribute("name", "hitsColumn");
const btn = deleteButton(row["shortlink"]);
const deleteBtn = deleteButton(row["shortlink"]);
const editBtn = editButton(row["shortlink"]);
tr.appendChild(shortTD);
tr.appendChild(longTD);
tr.appendChild(hitsTD);
tr.appendChild(btn);
tr.appendChild(editBtn);
tr.appendChild(deleteBtn);
return tr;
}
@ -178,6 +179,53 @@ const deleteButton = (shortUrl) => {
return td;
}
const editButton = (shortUrl) => {
const td = document.createElement("td");
const btn = document.createElement("button");
btn.innerHTML = "Edit";
btn.onclick = async (e) => {
e.preventDefault();
const newUrl = prompt("Enter the new long URL:");
if (newUrl) {
if (!isValidUrl(newUrl)) {
showAlert("Invalid URL format. Please enter a valid URL.", "red");
return;
}
const response = await fetch(prepSubdir(`/api/edit/${shortUrl}`), {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ longlink: newUrl }),
});
if (response.ok) {
showAlert(`Successfully updated ${shortUrl}.`, "green");
refreshData();
} else {
const errorMsg = await response.text();
showAlert(`Error: ${errorMsg}`, "red");
}
}
};
td.setAttribute("name", "editBtn");
td.appendChild(btn);
return td;
}
const isValidUrl = (urlString) => {
try {
new URL(urlString);
return true;
} catch (_) {
return false;
}
}
const TD = (s, u) => {
const td = document.createElement("td");
const div = document.createElement("div");