feat(api): add api for script management (list, create, rename, delete, fill with content)
This commit is contained in:
parent
aa6a48a09b
commit
26e666bae0
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
database.db
|
||||
.env
|
||||
/scripts
|
||||
|
231
src/api/mod.rs
231
src/api/mod.rs
@ -4,6 +4,8 @@ use rusqlite::Connection;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::db;
|
||||
@ -17,7 +19,12 @@ pub fn get_routes() -> Router {
|
||||
.route("/change_username", post(change_username))
|
||||
.route("/change_email", post(change_email))
|
||||
.route("/change_password", post(change_password))
|
||||
.route("/delete_account", post(delete_account)),
|
||||
.route("/delete_account", post(delete_account))
|
||||
.route("/get_scripts", post(get_scripts))
|
||||
.route("/add_script", post(add_script))
|
||||
.route("/delete_script", post(delete_script))
|
||||
.route("/edit_script", post(edit_script))
|
||||
.route("/rename_script", post(rename_script)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -216,11 +223,11 @@ pub async fn change_password(Json(payload): Json<ChangePasswordPayload>) -> Json
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeleteAccountPayload {
|
||||
pub struct GenericTokenPayload {
|
||||
token: String,
|
||||
}
|
||||
|
||||
pub async fn delete_account(Json(payload): Json<DeleteAccountPayload>) -> Json<Value> {
|
||||
pub async fn delete_account(Json(payload): Json<GenericTokenPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
@ -236,3 +243,221 @@ pub async fn delete_account(Json(payload): Json<DeleteAccountPayload>) -> Json<V
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "success": "Account deleted with success" }))
|
||||
}
|
||||
|
||||
pub async fn get_scripts(Json(payload): Json<GenericTokenPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
};
|
||||
let connection = Connection::open("database.db").expect("Failed to open database");
|
||||
let scripts = db::get_scripts(&connection, account_id);
|
||||
connection.close().expect("Failed to close database");
|
||||
match scripts {
|
||||
Ok(scripts) => {
|
||||
let mut result = json!({});
|
||||
for (id, name, last_edit) in scripts {
|
||||
result[id.to_string()] = json!({ "name": name, "last_edit": last_edit });
|
||||
}
|
||||
Json(result)
|
||||
}
|
||||
Err(_) => Json(json!({ "error": "Failed to get scripts" })),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AddScriptPayload {
|
||||
name: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
pub async fn add_script(Json(payload): Json<AddScriptPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
};
|
||||
let connection = Connection::open("database.db").expect("Failed to open database");
|
||||
match db::add_script(&connection, &payload.name, account_id) {
|
||||
Ok(_) => {
|
||||
let username = match db::get_account_username(&connection, account_id)
|
||||
.expect("Failed to get account username")
|
||||
{
|
||||
Some(username) => username,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get account username" }));
|
||||
}
|
||||
};
|
||||
let filename = format!("scripts/{}/{}", username, &payload.name);
|
||||
std::fs::create_dir_all(format!("scripts/{}", username))
|
||||
.expect("Failed to create directory");
|
||||
File::create(&filename).expect("Failed to create file");
|
||||
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "success": "Script added with success" }))
|
||||
}
|
||||
Err(_) => {
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "error": "Failed to add script" }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeleteScriptPayload {
|
||||
script_id: usize,
|
||||
token: String,
|
||||
}
|
||||
|
||||
pub async fn delete_script(Json(payload): Json<DeleteScriptPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
};
|
||||
let connection = Connection::open("database.db").expect("Failed to open database");
|
||||
if !db::script_is_owned_by(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to check if script is owned by user")
|
||||
{
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Script is not owned by user" }));
|
||||
}
|
||||
let script_name = match db::get_script_name(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to get script name")
|
||||
{
|
||||
Some(script_name) => script_name,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get script name" }));
|
||||
}
|
||||
};
|
||||
|
||||
match db::remove_script(&connection, payload.script_id) {
|
||||
Ok(_) => {
|
||||
let username = match db::get_account_username(&connection, account_id)
|
||||
.expect("Failed to get account username")
|
||||
{
|
||||
Some(username) => username,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get account username" }));
|
||||
}
|
||||
};
|
||||
let filename = format!("scripts/{}/{}", username, script_name);
|
||||
std::fs::remove_file(&filename).expect("Failed to remove file");
|
||||
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "success": "Script deleted with success" }))
|
||||
}
|
||||
Err(_) => {
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "error": "Failed to delete script" }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EditScriptPayload {
|
||||
script_id: usize,
|
||||
content: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
pub async fn edit_script(Json(payload): Json<EditScriptPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
};
|
||||
let connection = Connection::open("database.db").expect("Failed to open database");
|
||||
if !db::script_is_owned_by(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to check if script is owned by user")
|
||||
{
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Script is not owned by user" }));
|
||||
}
|
||||
match db::update_script_last_edit(&connection, payload.script_id) {
|
||||
Ok(_) => {
|
||||
let username = match db::get_account_username(&connection, account_id)
|
||||
.expect("Failed to get account username")
|
||||
{
|
||||
Some(username) => username,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get account username" }));
|
||||
}
|
||||
};
|
||||
let script_name = match db::get_script_name(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to get script name")
|
||||
{
|
||||
Some(script_name) => script_name,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get script name" }));
|
||||
}
|
||||
};
|
||||
let filename = format!("scripts/{}/{}", username, script_name);
|
||||
let mut file = File::create(&filename).expect("Failed to open file");
|
||||
file.write_all(payload.content.as_bytes())
|
||||
.expect("Failed to write to file");
|
||||
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "success": "Script edited with success" }))
|
||||
}
|
||||
Err(_) => {
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "error": "Failed to edit script" }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RenameScriptPayload {
|
||||
script_id: usize,
|
||||
new_script_name: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
pub async fn rename_script(Json(payload): Json<RenameScriptPayload>) -> Json<Value> {
|
||||
let account_id = match get_account_id_from_jwt(&payload.token) {
|
||||
Ok(account_id) => account_id,
|
||||
Err(_) => return Json(json!({ "error": "Invalid token" })),
|
||||
};
|
||||
let connection = Connection::open("database.db").expect("Failed to open database");
|
||||
if !db::script_is_owned_by(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to check if script is owned by user")
|
||||
{
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Script is not owned by user" }));
|
||||
}
|
||||
let old_script_name = match db::get_script_name(&connection, payload.script_id, account_id)
|
||||
.expect("Failed to get script name")
|
||||
{
|
||||
Some(script_name) => script_name,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get script name" }));
|
||||
}
|
||||
};
|
||||
|
||||
match db::modify_script_name(&connection, payload.script_id, &payload.new_script_name) {
|
||||
Ok(_) => {
|
||||
let username = match db::get_account_username(&connection, account_id)
|
||||
.expect("Failed to get account username")
|
||||
{
|
||||
Some(username) => username,
|
||||
None => {
|
||||
connection.close().expect("Failed to close");
|
||||
return Json(json!({ "error": "Failed to get account username" }));
|
||||
}
|
||||
};
|
||||
let old_filename = format!("scripts/{}/{}", username, old_script_name);
|
||||
let new_filename = format!("scripts/{}/{}", username, &payload.new_script_name);
|
||||
std::fs::rename(&old_filename, &new_filename).expect("Failed to rename file");
|
||||
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "success": "Script renamed with success" }))
|
||||
}
|
||||
Err(_) => {
|
||||
connection.close().expect("Failed to close");
|
||||
Json(json!({ "error": "Failed to rename script" }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,17 @@ pub fn get_account_id_from_email(conn: &Connection, email: &str) -> Result<Optio
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_scripts(conn: &Connection, account_id: usize) -> Result<Vec<(usize, String, usize)>> {
|
||||
pub fn get_account_username(conn: &Connection, id: usize) -> Result<Option<String>> {
|
||||
let mut stmt = conn.prepare("SELECT username FROM accounts WHERE id = ?1")?;
|
||||
let mut rows = stmt.query([id])?;
|
||||
if let Some(row) = rows.next()? {
|
||||
Ok(Some(row.get(0)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_scripts(conn: &Connection, account_id: usize) -> Result<Vec<(usize, String, String)>> {
|
||||
let mut stmt = conn.prepare("SELECT id, name, last_edit FROM scripts WHERE account_id = ?1")?;
|
||||
let mut rows = stmt.query([account_id])?;
|
||||
let mut scripts = Vec::new();
|
||||
@ -138,12 +148,7 @@ pub fn get_scripts(conn: &Connection, account_id: usize) -> Result<Vec<(usize, S
|
||||
Ok(scripts)
|
||||
}
|
||||
|
||||
pub fn add_script(
|
||||
conn: &Connection,
|
||||
name: &str,
|
||||
last_edit: usize,
|
||||
account_id: usize,
|
||||
) -> Result<()> {
|
||||
pub fn add_script(conn: &Connection, name: &str, account_id: usize) -> Result<()> {
|
||||
let mut stmt = conn.prepare("SELECT id FROM scripts WHERE name = ?1 AND account_id = ?2")?;
|
||||
let mut rows = stmt.query([&name as &dyn ToSql, &account_id as &dyn ToSql])?;
|
||||
if rows.next()?.is_some() {
|
||||
@ -151,8 +156,8 @@ pub fn add_script(
|
||||
}
|
||||
|
||||
conn.execute(
|
||||
"INSERT INTO scripts (name, last_edit, account_id) VALUES (?1, ?2, ?3)",
|
||||
(name, last_edit, account_id),
|
||||
"INSERT INTO scripts (name, account_id) VALUES (?1, ?2)",
|
||||
(name, account_id),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@ -169,10 +174,15 @@ pub fn script_is_owned_by(conn: &Connection, script_id: usize, account_id: usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_script_id(conn: &Connection, name: &str, account_id: usize) -> Result<Option<usize>> {
|
||||
let mut stmt = conn.prepare("SELECT id FROM scripts WHERE name = ?1 AND account_id = ?2")?;
|
||||
let mut rows = stmt.query([&name as &dyn ToSql, &account_id as &dyn ToSql])?;
|
||||
pub fn get_script_name(
|
||||
conn: &Connection,
|
||||
script_id: usize,
|
||||
account_id: usize,
|
||||
) -> Result<Option<String>> {
|
||||
let mut stmt = conn.prepare("SELECT name FROM scripts WHERE id = ?1 AND account_id = ?2")?;
|
||||
let mut rows = stmt.query([&script_id as &dyn ToSql, &account_id as &dyn ToSql])?;
|
||||
if let Some(row) = rows.next()? {
|
||||
println!("row: {:?}", row);
|
||||
Ok(Some(row.get(0)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
Loading…
Reference in New Issue
Block a user