From 7bbc871e3402fdedec8f07c8969a8877b87fae18 Mon Sep 17 00:00:00 2001 From: curly Date: Thu, 9 Feb 2023 09:27:58 -0700 Subject: message_list, delete_user, limits --- README.md | 16 +++++++-- TODO | 6 +--- src/database.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/database/types.rs | 29 ++++++++++------- src/main.rs | 30 ++++++++++++++++- 5 files changed, 146 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 033b570..be2fc96 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,13 @@ POST `/create_user/` - Return type: JSON - Returns: `UID` of user +DELETE `/delete_user` + Deletes a user +- Data type: JSON +- Data: `UID` +- Return type: JSON +- Returns: `Result` + GET `/get_user/` Gets a user from id - Return type: JSON @@ -39,10 +46,15 @@ GET `/get_message_id_newest` - Returns: GET `/get_message_id_list//` - Gets a list of messages from_id to to_id inclusive + Gets a list of message ids from_id to to_id inclusive (limit 25) - Return type: JSON - Returns: > +GET `/get_message_list//` + Gets a list of messages from_id to to_id inclusive (limit 25) +- Return type: JSON +- Returns: > + POST `/send_message` Sends a message - Data type: JSON @@ -56,6 +68,6 @@ POST `/send_message` DELETE `/delete_message` Deletes a message - Data type: JSON -- Data: `u64` +- Data: `UID` - Return type: JSON - Returns: `Result` \ No newline at end of file diff --git a/TODO b/TODO index 70968b4..7121bc0 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ Authentication -Delete user Rework Response to be an enum Add Channels @@ -7,12 +6,9 @@ Add DM'ing Federation would be cool -Limit get_message_id_list -Add get_message_list - ACLs Config /api - list functions/routes -Delete is a bit funky \ No newline at end of file +Delete is a bit funky - doesn't always report correctly \ No newline at end of file diff --git a/src/database.rs b/src/database.rs index 84c402f..0671594 100644 --- a/src/database.rs +++ b/src/database.rs @@ -13,7 +13,6 @@ impl Database { let statement = self.db.prepare(query).unwrap().into_iter().bind((":id", id as i64)).unwrap(); for row in statement.map(|row| row.unwrap()) { - let msg = row.read::<&str, _>("message"); let reply_to = row.read::, _>("reply_to"); let reply_to = match reply_to { @@ -23,7 +22,7 @@ impl Database { let date = row.read::("date").into(); let deleted = row.read::("deleted"); - let deleted = if deleted < 0 { + let deleted = if deleted < 1 { false } else { true @@ -66,7 +65,54 @@ impl Database { } } + pub fn get_message_list(&self, id_start: UID, id_end: UID) -> Vec { + let query = "SELECT * FROM messages WHERE id BETWEEN :id_start AND :id_end"; + let statement = self.db.prepare(query).unwrap().into_iter().bind::<&[(_, sqlite::Value)]>(&[ + (":id_start", id_start.into()), + (":id_end", id_end.into()), + ]).unwrap(); + + + let mut message_id_vec: Vec = vec![]; + for row in statement.map(|row| row.unwrap()) { + let msg = row.read::<&str, _>("message"); + let reply_to = row.read::, _>("reply_to"); + let reply_to = match reply_to { + Some(n) => Some(n.into()), + None => None + }; + + let date = row.read::("date").into(); + let deleted = row.read::("deleted"); + let deleted = if deleted < 1 { + false + } else { + true + }; + + let sender = row.read::("sender").into(); + let id = row.read::("id").into(); + + + let msg = Message::construct(String::from(msg), sender, id, reply_to, date, deleted); + + + message_id_vec.push(msg); + } + + return message_id_vec; + } + pub fn send_message(&mut self, msg: &Message) -> Result { + // Check if user exists + match self.get_user(msg.sender()) { + Some(n) => match n.deleted() { + true => return Err("User deleted"), + false => () + }, + None => return Err("User not found"), + } + let query = "INSERT INTO messages (date, sender, message, id, reply_to, deleted) VALUES (:date, :sender, :message, :id, :reply_to, :deleted)"; let statement = self.db.prepare(query).unwrap().into_iter() .bind::<&[(_, sqlite::Value)]>(&[ @@ -132,8 +178,13 @@ impl Database { let username = row.read::<&str, _>("username"); let id = row.read::("id").into(); + let deleted = if row.read::("deleted") > 0 { + true + } else { + false + }; - return Some(User::new(String::from(username), id)) + return Some(User::construct(String::from(username), id, deleted)) } None @@ -155,7 +206,7 @@ impl Database { pub fn create_user(&mut self, name: String) -> Result { let id: UID = self.get_user_count().into(); - let query = "INSERT INTO users (id, username) VALUES (:id, :name)"; + let query = "INSERT INTO users (id, username, deleted) VALUES (:id, :name, false)"; let statement = self.db.prepare(query).unwrap().into_iter() .bind::<&[(_, sqlite::Value)]>(&[(":id", id.into()),(":name", name.into())]); @@ -174,6 +225,35 @@ impl Database { Ok(id) } + pub fn delete_user(&mut self, id: UID) -> Result<&'static str, String> { + let query = "UPDATE users SET username=:username, deleted=:deleted WHERE id IS :id AND deleted IS false"; + let statement = self.db.prepare(query).unwrap().into_iter() + .bind::<&[(_, sqlite::Value)]>(&[ + (":username", "deleted".into()), + (":deleted", 1.into()), + (":id", id.into()), + ]); + + let change_count = self.db.change_count(); + + for x in statement.unwrap() { + match x { + Ok(_) => (), + Err(n) => { + match n.code.unwrap_or(0) { + n => return Err(format!("Unknown Error: {}", n)) + } + }, + } + } + + if change_count > 0 { + Ok("Deleted") + } else { + Err("Unabled to delete".to_string()) + } + } + pub fn get_user_count(&self) -> u64 { self.get_table_length("users") } @@ -204,7 +284,7 @@ impl Database { }; // Setup the db - let query = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY NOT NULL, username UNIQUE NOT NULL) WITHOUT ROWID"; + let query = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY NOT NULL, username UNIQUE NOT NULL, deleted BOOL NOT NULL) WITHOUT ROWID"; match db.execute(query) { Ok(_) => (), Err(n) => panic!("{n}"), diff --git a/src/database/types.rs b/src/database/types.rs index 1a8ab86..a0bfd12 100644 --- a/src/database/types.rs +++ b/src/database/types.rs @@ -32,17 +32,27 @@ impl std::convert::From for sqlite::Value { pub struct User { username: String, id: UID, + deleted: bool, } impl User { pub fn new(username: String, id: UID) -> User { User { username, id, + deleted: false, } } - pub fn id(&self) -> UID { - self.id + pub fn construct(username: String, id: UID, deleted: bool) -> User { + User { + username, + id, + deleted, + } + } + + pub fn deleted(&self) -> bool { + self.deleted } } @@ -67,6 +77,11 @@ impl std::convert::From for UID { } } } +impl std::convert::From for i64 { + fn from(t :UID) -> i64 { + t.0 as i64 + } +} impl std::convert::From for sqlite::Value { fn from(t: UID) -> sqlite::Value { (t.0 as i64).into() @@ -83,16 +98,6 @@ pub struct Message { date: Date, } impl Message { - pub fn new(message: String, sender: &User, id: UID, reply_to: Option) -> Message { - Message { - id, - sender: sender.id(), - message, - reply_to, - deleted: false, - date: Date::now(), - } - } pub fn construct(msg: String, sender: UID, id: UID, reply_to: Option, date: Date, deleted: bool) -> Message { Message { date: date, diff --git a/src/main.rs b/src/main.rs index 9ed4ddc..86a6186 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,10 @@ fn get_message(id: usize, db: &State) -> Json/")] fn get_message_id_list(id_start: u64, id_end: u64, db: &State) -> Json, &'static str>> { + if id_end - id_start > 25 { + return Json(Response(Err("Request limit is 25"))) + } + let lock = db.sdb.lock().unwrap(); let list = lock.get_message_id_list(id_start.into(), id_end.into()); @@ -35,6 +39,21 @@ fn get_message_id_list(id_start: u64, id_end: u64, db: &State) -> Json Json(Response(Ok(list))) } } +#[get("/get_message_list//")] +fn get_message_list(id_start: u64, id_end: u64, db: &State) -> Json, &'static str>> { + if id_end - id_start > 25 { + return Json(Response(Err("Request limit is 25"))) + } + + let lock = db.sdb.lock().unwrap(); + let list = lock.get_message_list(id_start.into(), id_end.into()); + + if list.len() == 0 { + Json(Response(Err("No messages"))) + } else { + Json(Response(Ok(list))) + } +} #[get("/get_message_id_newest")] fn get_message_id_newest(db: &State) -> Json> { let lock = db.sdb.lock().unwrap(); @@ -85,6 +104,13 @@ fn create_user(name: Json, db: &State) -> Json, db: &State) -> Json> { + let mut lock = db.sdb.lock().unwrap(); + + Json(Response(lock.delete_user(id.0))) +} + #[get("/ping")] fn ping() -> Json> { Json(Response(Ok("pong"))) @@ -115,7 +141,9 @@ fn rocket() -> _ { get_user_by_name, get_message_id_newest, delete_message, + delete_user, + get_message_list, ]) .mount("/", routes![api_index]) .manage(SharedDB{sdb: Mutex::new(database::Database::new())}) -} +} \ No newline at end of file -- cgit v1.2.3