aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--TODO6
-rw-r--r--src/database.rs90
-rw-r--r--src/database/types.rs29
-rw-r--r--src/main.rs30
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/<id>`
Gets a user from id
- Return type: JSON
@@ -39,10 +46,15 @@ GET `/get_message_id_newest`
- Returns: <message_id>
GET `/get_message_id_list/<from_id>/<to_id>`
- 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: <Array<message_id>>
+GET `/get_message_list/<from_id>/<to_id>`
+ Gets a list of messages from_id to to_id inclusive (limit 25)
+- Return type: JSON
+- Returns: <Array<Message>>
+
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::<Option<i64>, _>("reply_to");
let reply_to = match reply_to {
@@ -23,7 +22,7 @@ impl Database {
let date = row.read::<i64, _>("date").into();
let deleted = row.read::<i64, _>("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<Message> {
+ 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<Message> = vec![];
+ for row in statement.map(|row| row.unwrap()) {
+ let msg = row.read::<&str, _>("message");
+ let reply_to = row.read::<Option<i64>, _>("reply_to");
+ let reply_to = match reply_to {
+ Some(n) => Some(n.into()),
+ None => None
+ };
+
+ let date = row.read::<i64, _>("date").into();
+ let deleted = row.read::<i64, _>("deleted");
+ let deleted = if deleted < 1 {
+ false
+ } else {
+ true
+ };
+
+ let sender = row.read::<i64, _>("sender").into();
+ let id = row.read::<i64, _>("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<UID, &'static str> {
+ // 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::<i64, _>("id").into();
+ let deleted = if row.read::<i64, _>("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<UID, &'static str> {
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<Date> 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<i64> for UID {
}
}
}
+impl std::convert::From<UID> for i64 {
+ fn from(t :UID) -> i64 {
+ t.0 as i64
+ }
+}
impl std::convert::From<UID> 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<UID>) -> 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<UID>, 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<SharedDB>) -> Json<Response<Message, &'stat
}
#[get("/get_message_id_list/<id_start>/<id_end>")]
fn get_message_id_list(id_start: u64, id_end: u64, db: &State<SharedDB>) -> Json<Response<Vec<UID>, &'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<SharedDB>) -> Json
Json(Response(Ok(list)))
}
}
+#[get("/get_message_list/<id_start>/<id_end>")]
+fn get_message_list(id_start: u64, id_end: u64, db: &State<SharedDB>) -> Json<Response<Vec<Message>, &'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<SharedDB>) -> Json<Response<UID, &'static str>> {
let lock = db.sdb.lock().unwrap();
@@ -85,6 +104,13 @@ fn create_user(name: Json<String>, db: &State<SharedDB>) -> Json<Response<UID, &
Json(Response(lock.create_user(name.0)))
}
+#[delete("/delete_user", format = "application/json", data = "<id>")]
+fn delete_user(id: Json<UID>, db: &State<SharedDB>) -> Json<Response<&'static str, String>> {
+ let mut lock = db.sdb.lock().unwrap();
+
+ Json(Response(lock.delete_user(id.0)))
+}
+
#[get("/ping")]
fn ping() -> Json<Response<&'static str, &'static str>> {
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