From f9bc6b3dc9fefea9551db1d48d0f54e311d091e4 Mon Sep 17 00:00:00 2001 From: shockrah Date: Tue, 3 Nov 2020 23:16:24 -0800 Subject: [PATCH] channels modules have newly updated list endpoints /channels/create requires a rework however --- server-api/db/src/channels.rs | 66 +++++++++++++- server-api/src/channels.rs | 167 ++++------------------------------ 2 files changed, 85 insertions(+), 148 deletions(-) diff --git a/server-api/db/src/channels.rs b/server-api/db/src/channels.rs index 97c9473..76bbba5 100644 --- a/server-api/db/src/channels.rs +++ b/server-api/db/src/channels.rs @@ -8,7 +8,10 @@ use crate::{VarChar, UBigInt, Integer}; use crate::common::FromDB; use crate::{sql_err, no_conn, Response}; +use serde::Serialize; + #[allow(dead_code)] +#[derive(Serialize)] pub struct Channel { pub id: UBigInt, pub name: VarChar, @@ -16,8 +19,11 @@ pub struct Channel { pub kind: Integer } +pub const VOICE_CHANNEL: Integer = 1; +pub const TEXT_CHANNEL: Integer = 2; + #[async_trait] -impl FromDB for Channel { +impl FromDB for Channel { // id name desc kind type Row = Option<(UBigInt, VarChar, Option, Integer)>; @@ -91,4 +97,62 @@ impl FromDB for Channel { } return Response::Other(no_conn!("Member::FromDB::delete")) } + + async fn filter(p: &Pool, kind: Integer) -> Response { + //! @returns -> on success : Response::Set(Vec) + //! @returns -> on empty set : Response::Set(EmptyVector) + //! @params -> on fail : Response::Other + + // NOTE: used for mapping datasets to vectors + let map_rows = |row| { + let (id, name, desc, k): (UBigInt, VarChar, Option, Integer) = + mysql_async::from_row(row); + Channel { + id: id, + name: name, + description: desc, + kind: k + } + }; + return match (p.get_conn().await, kind) { + // Filter for text/voice channels specifically + (Ok(conn), VOICE_CHANNEL..=TEXT_CHANNEL) => { // @NOTE: voice channel and text_channel are literally 1 & 2 respectively + let q = "SELECT id, name, description, kind FROM channels WHERE kind = :kind"; + let q_result = conn.prep_exec(q, params!{"kind" => kind}).await; + if let Ok(res) = q_result { + let mapping_result = res.map_and_drop(map_rows).await; + return match mapping_result { + Ok((_, channels)) => Response::Set(channels), + Err(_) => Response::Other(sql_err!("db::Channels::filter @with params")) + }; + } + else { + Response::Other(sql_err!("")) + } + }, + /* + * Here we are attempting to get all the channels with no filters applied + * This should fetch everything basically in our channels registry + */ + (Ok(conn), _) => { + let q = "SELECT id, name, description, kind FROM channels"; + if let Ok(query) = conn.prep_exec(q, ()).await { + let mapping_r = query.map_and_drop(map_rows).await; + + return match mapping_r { + Ok((_, channels)) => Response::Set(channels), + Err(_) => Response::Other(sql_err!("db::Channels::filter @no params")) + }; + } + else { + Response::Other(sql_err!("db::Channels::filter @no params @no initial query")) + } + }, + (Err(_), _) => {Response::Other(no_conn!("Channel::FromDB::filter"))} + } + } +} + +impl Channel { + pub async fn add() {} } diff --git a/server-api/src/channels.rs b/server-api/src/channels.rs index 36a8870..981184b 100644 --- a/server-api/src/channels.rs +++ b/server-api/src/channels.rs @@ -1,159 +1,40 @@ -use hyper::{StatusCode, Response, Body}; -use hyper::header::HeaderValue; +use hyper::{ + StatusCode, Response, Body, + header::HeaderValue +}; -use mysql_async::{Conn, Pool}; -use mysql_async::error::Error; -use mysql_async::prelude::{params, Queryable}; +use mysql_async::Pool; -use serde_json::Value; +use serde_json::{Value, to_string}; use db::{ self, - UBigInt, VarChar, Integer, - common::FromDB + common::FromDB, + channels::Channel }; -#[derive(Debug)] -pub enum ChannelType { - Voice, - Text, - Undefined -} - -impl ChannelType { - // These funcs are mainly here to help translation from mysql - pub fn from_i32(x: i32) -> ChannelType { - match x { - 1 => ChannelType::Voice, - 2 => ChannelType::Text, - _ => ChannelType::Undefined - } - } - pub fn as_i32(&self) -> i32 { - match self { - ChannelType::Voice => 1, - ChannelType::Text => 2, - ChannelType::Undefined => 3, - - } - } -} - -// Primary way of interpretting sql data on our channels table -pub struct Channel { - pub id: u64, - pub name: String, - pub description: String, - pub kind: ChannelType -} - -#[derive(Debug)] -struct InsertableChannel { - name: String, - kind: ChannelType -} - -impl Channel { - /* - * When our sql library queries things we generally get back tuples rather reasily - * we can use this method to get something that makes more sense - */ - fn from_tup(tup: (UBigInt, VarChar, Option, Integer)) -> Channel { - let desc = match tup.2 { - Some(val) => val, - None => "None".into() - }; - - Channel { - id: tup.0, - name: tup.1, - description: desc, - kind: ChannelType::from_i32(tup.3) - } - } - /* - * When responding with some channel data to the client we use json - * this itemizes a single struct as the following(without the pretty output) - * { - * "id": id, - * "name": "", - * "description": Option<"">, - * "kind": kind - * } - */ - fn as_json_str(&self) -> String { - let mut base = String::from("{"); - base.push_str(&format!("\"id\":{},", self.id)); - base.push_str(&format!("\"name\":\"{}\",", self.name)); - base.push_str(&format!("\"description\":\"{}\",", self.description)); - base.push_str(&format!("\"kind\":{}}}", self.kind.as_i32())); - return base; - } -} - - -/* - * Forwarding SQL errors as we can handle those error in caller site for this leaf function - * On success we back a Vec which we can JSON'ify later and use as a response -*/ -async fn get_channels_vec(conn: Conn) -> Result, Error> { - let rows_db = conn.prep_exec(r"SELECT * FROM channels", ()).await?; - let (_, rows) = rows_db.map_and_drop(|row| { - let (id, name, desc, kind): (UBigInt, VarChar, Option, Integer) = mysql_async::from_row(row); - Channel::from_tup((id, name, desc, kind)) - }).await?; - - Ok(rows) -} pub async fn list_channels(pool: &Pool, response: &mut Response) { /* - * Primary dispatcher for dealing with the CHANNELS_LIST route - * For the most part this function will have a lot more error handling as it - * should know what kind of issues its child functions will have + * @user-params -> for now none as i don't feel like dealing with it + * @TODO: add in a let var that actually */ - if let Ok(conn) = pool.get_conn().await { - match get_channels_vec(conn).await { - Ok(chans) => { - *response.status_mut() = StatusCode::OK; - response.headers_mut().insert("Content-Type", - HeaderValue::from_static("application/json")); - - // At this point we build the content of our response body - // which is a json payload hence why there is weird string manipulation - // because we're trying to avoid dependancy issues and serializing things ourselves - let mut new_body = String::from("{\"channels\":["); - for chan in chans.iter() { - let s = format!("{},", chan.as_json_str()); - new_body.push_str(&s); - } - if new_body.ends_with(',') {new_body.pop();} - new_body.push_str("]}"); + return match db::channels::Channel::filter(pool, 0).await { + db::Response::Set(channels) => { + response.headers_mut().insert("Content type", + HeaderValue::from_static("json/application")); - *response.body_mut() = Body::from(new_body); - }, - Err(_) => { - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - } - } - } - else { - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - } -} - - -async fn insert_channel(pool: &Pool, name: &str, desc: &str, kind: i64) -> Result<(), Error>{ - let conn = pool.get_conn().await?; - conn.prep_exec( - "INSERT INTO channels (name, description, kind) VALUES (:name, :description, :kind)", - params!{"name" => name, "kind" => kind, "description" => desc}).await?; - Ok(()) + *response.body_mut() = Body::from(to_string(&channels).unwrap_or("{}".into())) + }, + db::Response::Other(_msg) => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR, + _ => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR, + }; } pub async fn create_channel(pool: &Pool, response: &mut Response, params: Value) { /* * Create a channel base on a few parameters that may or may not be there + * @responds with the data of the newly created channel */ // Theres an extra un-needed unwrap to be cut out from this proc // specifically with the desc parameter @@ -165,13 +46,6 @@ pub async fn create_channel(pool: &Pool, response: &mut Response, params: }; match req_params { (Some(name), Some(desc), Some(kind)) => { - match insert_channel(pool, name, desc, kind).await { - Err(e) => { - println!("SERVER ERROR: {}", e); - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - }, - _ => {} - } }, // basically one of the parameter gets failed so we bail on all of this _ => *response.status_mut() = StatusCode::BAD_REQUEST @@ -180,7 +54,6 @@ pub async fn create_channel(pool: &Pool, response: &mut Response, params: pub async fn delete_channel(pool: &Pool, response: &mut Response, params: Value) { // make sure we have the right parameters provided - use db::channels::Channel; if let Some(name) = params.get("channel_id") { if let Some(id) = name.as_u64() { // TODO: something more intelligent with the logging im ngl