From 8a91d51dc6823adc9d5616c254ae35ba41f0e27f Mon Sep 17 00:00:00 2001 From: shockrah Date: Mon, 10 Aug 2020 18:06:27 -0700 Subject: [PATCH] Invite struct has been simplified Invite::as_json_str/from_tuple changed to reflect new field changes + insert_new_invite: short and sweet error handling by the caller for now * create_invite now named `create` + reduced code complexity in invites::create so its very straight forward to read(imo) --- server/src/invites.rs | 93 ++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/server/src/invites.rs b/server/src/invites.rs index 967fec1..dd7a1f5 100644 --- a/server/src/invites.rs +++ b/server/src/invites.rs @@ -9,10 +9,13 @@ use hyper::{Response, Body, StatusCode}; use chrono::Utc; use rand::random; -struct InviteRow { - id: u64, - expires: u64, - uses: i32, + +use crate::db_types::{BigInt, Integer}; + +struct Invite { + id: BigInt, + uses: Option, // optional because some links are permanent + expires: bool, } /* * Error handling: @@ -20,29 +23,22 @@ struct InviteRow { * are of the enum mysql_async::error::Error */ -impl InviteRow { - pub fn new() -> InviteRow { - let dt = Utc::now() + chrono::Duration::minutes(30); - // TODO:[maybe] ensure no collisions by doing a quick database check here - let invite = InviteRow { - id: random::(), // hopefully there won't ever be collision with this size of pool - uses: 1, // default/hardcorded for now - expires: dt.timestamp() as u64 - }; - invite - } - pub fn from_tuple(tup: (u64, u64, i32)) -> InviteRow { - InviteRow { +impl Invite { + pub fn from_tuple(tup: (BigInt, Option, bool)) -> Invite { + /* + * Let's us convert tuples from mysql into convenient invite structs */ + Invite { id: tup.0, - expires: tup.1, - uses: tup.2, + uses: tup.1, + expires: tup.2 } } pub fn as_json_str(&self) -> String { + // TODO: Deprecate let id = format!("\"id\":{}", self.id); let expires = format!("\"expires\":{}", self.expires); - let uses = format!("\"uses\":{}", self.uses); + let uses = format!("\"uses\":{:?}", self.uses); let mut data = String::from("{"); data.push_str(&format!("{},", id)); @@ -52,14 +48,14 @@ impl InviteRow { } } -async fn get_invite_by_code(pool: &Pool, value: Option<&str>) -> Result, Error> { +async fn get_invite_by_code(pool: &Pool, value: Option<&str>) -> Result, Error> { if let Some(val) = value { let conn = pool.get_conn().await?; - let db_row_result: (Conn, Option<(u64, u64, i32)>) = conn + let db_row_result: (Conn, Option<(BigInt, Option, bool)>) = conn .first_exec(r"SELECT * FROM", mysql_async::params!{"code"=>val}) .await?; if let Some(tup) = db_row_result.1 { - Ok(Some(InviteRow::from_tuple(tup))) + Ok(Some(Invite::from_tuple(tup))) } else { // basically nothing was found but nothing bad happened @@ -70,7 +66,7 @@ async fn get_invite_by_code(pool: &Pool, value: Option<&str>) -> Result Result<(), Error>{ +async fn record_invite_usage(pool: &Pool, data: &Invite) -> Result<(), Error>{ /* * By this this is called we really don't care about what happens as we've * already been querying the db and the likely hood of this seriously failing @@ -87,7 +83,7 @@ async fn record_invite_usage(pool: &Pool, data: &InviteRow) -> Result<(), Error> } pub async fn route_join_invite_code(pool: &Pool, response: &mut Response, params: Value) -> Result<(), Error> { - // First check that the code is there + // collect some things first if let Some(code) = params.get("code") { if let Some(row) = get_invite_by_code(pool, code.as_str()).await? { // since we have a row make sure the invite is valid @@ -107,17 +103,42 @@ pub async fn route_join_invite_code(pool: &Pool, response: &mut Response, Ok(()) } -pub async fn create_invite(pool: &Pool, response: &mut Response) -> Result<(), Error> { - let invite = InviteRow::new(); +async fn insert_new_invite(pool: &Pool, invite: &Invite) -> Result<(), Error>{ let conn = pool.get_conn().await?; - conn.prep_exec(r"INSERT INTO invites (id, expires, uses) VALUES (:id, :expires, :uses", - mysql_async::params!{ - "id" => invite.id, - "expires" => invite.expires, - "uses" => invite.uses, - }).await?; + conn.prep_exec( + "INSERT INTO invites (id, uses, expires) + VALUES (:id, :uses, :expires)", params!{ + "id" => invite.id, + "uses" => invite.uses, + "expires" => invite.expires + }).await?; - *response.body_mut() = Body::from(invite.as_json_str()); - *response.status_mut() = StatusCode::OK; Ok(()) -} \ No newline at end of file +} + +pub async fn create(pool: &Pool, response: &mut Response, params: Value) { + /* + * Creates a new invite + */ + + let use_count = match params.get("uses") { + Some(val) => val.as_i64(), + None => None + }; + + let expires = match params.get("expires") { + Some(val) => val.as_bool().unwrap(), + None => true + }; + + let invite = Invite { + id: (Utc::now() + chrono::Duration::minutes(30)).timestamp(), + uses: use_count, + expires: expires + }; + + match insert_new_invite(&pool, &invite).await { + Ok(_) => *response.body_mut() = Body::from("yes"), + Err(mysqle) => *response.status_mut() = StatusCode::BAD_REQUEST + } +}