diff --git a/json-api/db/src/badges.rs b/json-api/db/src/badges.rs new file mode 100644 index 0000000..9535740 --- /dev/null +++ b/json-api/db/src/badges.rs @@ -0,0 +1,80 @@ +use crate::Badge; +use mysql_async::prelude::Queryable; +use mysql_async::{params, Pool, Result as SqlResult}; +use rand::RngCore; + +pub async fn add(pool: &Pool, name: &str, color: u32, perms: u64) -> SqlResult{ + // First gather the parameters required for the query + let id = rand::rngs::OsRng.next_u64(); + + let mut conn = pool.get_conn().await?; + let q = "INSERT INTO badges (id, name, color, permissions) + VALUES(:id, :name, :color, :perms)"; + let sqlparams = params!{ + "id" => id, + "name" => name, + "color" => color, + "perms" => perms + }; + conn.exec_drop(q, sqlparams).await?; + Ok(Badge{ + id, + name: String::from(name), + color, + perms + }) +} + +pub async fn delete(pool: &Pool, id: u64) -> SqlResult { + let mut conn = pool.get_conn().await?; + let q = "DELETE FROM badges WHERE id = :id"; + conn.exec_drop(q, params!{"id" => id}).await?; + Ok(id) +} + +async fn get(pool: &Pool, id: u64) -> SqlResult> { + let mut conn = pool.get_conn().await?; + let q = "SELECT name, color, permissions FROM badges WHERE id = :id"; + let row: Option<(String, u32, u64)> = conn.exec_first(q, params!{ "id" => id}).await?; + match row { + Some(row) => { + let b = Badge { + id, + name: row.0, + color: row.1, + perms: row.2, + }; + Ok(Some(b)) + }, + None => Ok(None) + } +} + +pub async fn update(pool: &Pool, badge: Badge) -> SqlResult> { + // Ok(None) if that badge was not registered anywhere + // Ok(Some(Badge)) if that badge was registered + if let Ok(None) = get(pool, badge.id).await { + return Ok(None); + } + + let q = "UPDATE badges SET name = :name, color = :color, permissions = :perms + WHERE id = :id"; + let p = params! { + "id" => badge.id, + "name" => badge.name.clone(), + "color" => badge.color, + "perms" => badge.perms + }; + let mut conn = pool.get_conn().await?; + conn.exec_drop(q, p).await?; + Ok(Some(badge)) +} + +pub async fn list(pool: &Pool) -> SqlResult> { + let q = "SELECT id, name, color, permissions FROM badges"; + let mut conn = pool.get_conn().await?; + let set: Vec = conn.exec_map(q, (), |(id, name, color, perms)| { + Badge { id, name, color, perms } + }).await?; + Ok(set) +} diff --git a/json-api/src/badges.rs b/json-api/src/badges.rs new file mode 100644 index 0000000..81bafed --- /dev/null +++ b/json-api/src/badges.rs @@ -0,0 +1,73 @@ +use crate::{db, qs_param, http::set_json_body}; + +use std::collections::HashMap; +use mysql_async::Pool; +use hyper::{Response, StatusCode, Body}; +use serde_json::json; + +pub async fn new(p: &Pool, response: &mut Response, params: HashMap) { + // Only name is really required the other two can default to white/ + let name = qs_param!(params, "badge_name", String); + let perms = match qs_param!(params, "badge_perms", u64) { + Some(perms) => perms, + None => 0 + }; + let color = match qs_param!(params, "badge_color", u32) { + Some(color) => color, + None => 0xffffffff, + }; + if let Some(name) = name { + match db::badges::add(p, &name, color, perms).await { + Ok(badge) => { + set_json_body(response, json!({"badge": json!(badge)})); + // TODO: add some rtc notification here + }, + Err(e) => { + eprintln!("[HTTP][ERROR] /badge/new {}", e); + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + } + }; + } else { + *response.status_mut() = StatusCode::BAD_REQUEST; + } +} + +pub async fn update(_p: &Pool, _response: &mut Response, _params: HashMap) { + /* TODO: + * This handler could actually benefit from being split into multiple handlers + * Concern: Permissions handling with is route could get ugly when handling updates to the + * permissions flag in each badge which is why we may want a + * /badge/update/color + * /badge/update/name + * /badge/update/permissions + */ +} + +pub async fn delete(p: &Pool, response: &mut Response, params: HashMap) { + if let Some(id) = qs_param!(params, "badge_id", u64) { + match db::badges::delete(p, id).await { + Ok(id) => { + // TODO: add rtc notification here + println!("TODO remove me at some point {}", id); + }, + Err(e) => { + eprintln!("[HTTP][ERROR] /badge/delete {}", e); + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + } + } + } else { + *response.status_mut() = StatusCode::BAD_REQUEST; + } +} + +pub async fn list(p: &Pool, response: &mut Response) { + match db::badges::list(p).await { + Ok(badges) => { + set_json_body(response, json!({"badges": json!(badges)})); + }, + Err(e) => { + eprintln!("[HTTP][ERRO] /badge/list {}", e); + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + } + } +}