diff --git a/json-api/db/src/channels.rs b/json-api/db/src/channels.rs index 0903b9c..fea7d46 100644 --- a/json-api/db/src/channels.rs +++ b/json-api/db/src/channels.rs @@ -2,159 +2,44 @@ use mysql_async::{params, Pool, Conn}; use mysql_async::prelude::Queryable; use mysql_async::error::Error as SqlError; -use async_trait::async_trait; - use crate::{VarChar, UBigInt, Integer}; -use crate::common::FromDB; use crate::{sql_err, no_conn, Response}; -use serde::Serialize; -#[derive(Serialize)] -pub struct Channel { - pub id: UBigInt, - pub name: VarChar, - pub description: Option, - pub kind: Integer -} pub const VOICE_CHANNEL: Integer = 1; pub const TEXT_CHANNEL: Integer = 2; -#[async_trait] -impl FromDB for Channel { - // id name desc kind - type Row = Option<(UBigInt, VarChar, Option, Integer)>; - async fn get(p: &Pool, id: UBigInt) -> Response { - //! Retrieves a Full single Channel row from the DB or fails in a - //! fashion described by crate::Response - //! @param p -> SqlPool - //! @param id -> UBigInt - //! @return on_success -> Response::Row(Channel) - //! @return on_fail -> Response::{Empty, Other} - if let Ok(conn) = p.get_conn().await { - let q = "SELECT id, name, description, kind FROM channels WHERE id = :id"; - let result: Result<(Conn, Self::Row), SqlError> = - conn.first_exec(q, params!{"id" => id}).await; - if let Ok((_, row)) = result { - return match row { - Some(row) => Response::Row(Channel { - id, - name: row.1, - description: row.2, - kind: row.3 +impl crate::Channel { + pub async fn filter(p: &Pool, kind: Integer) -> Result, SqlError> { + //! @returns -> on success : Ok(Response::Set(Vec)) + //! @throw -> on sql fail : Err(SqlError) - }), - None => Response::Empty + if kind != VOICE_CHANNEL || kind !=TEXT_CHANNEL { + let conn = p.get_conn().await?; + let q = "SELECT id, name, description FROM channels WHERE kind = :kind"; + + let result = conn.prep_exec(q, params!{"kind" => kind}).await?; + let (_conn, channels) = result.map_and_drop(|row| { + let (id, name, description): (UBigInt, VarChar, Option) = + mysql_async::from_row(row); + Self { + id, + name, + description, + kind } - } - return Response::Other(no_conn!("Invite::FromDB::get fetch failed")); - } - return Response::Other(no_conn!("Invite::FromDB::get")); - } + }).await?; - async fn update(p: &Pool, row: Self) -> Response { - //! Updates a whole single based on a given Row Of Channel Type - //! @param p -> SqlPool - //! @param row -> Channel - //! @return on_success -> Response::Success - //! @return on_failure -> Response::Other - if let Ok(conn) = p.get_conn().await { - let q = "UPDATE channels - SET name = :name, description = :desc, kind = :kind - WHERE id = :id"; - let result: Result = - conn.drop_exec(q, params!{ - "id" => row.id, - "name" => row.name, - "desc" => row.description, - "kind" => row.kind - }).await; - return match result { - Ok(_) => Response::Success, - Err(_) => Response::Other(sql_err!("Invite::FromDB::update Update failed")) - } - } - return Response::Other(no_conn!("Invite::FromDB::get connection failed")); - } - - async fn delete(p: &Pool, id: UBigInt) -> Response { - //! Deletes channel given UBigInt as the row key - //! @param p -> SqlPool - //! @param id -> UBigInt - //! @return on success -> Response::Success - //! @return on server failure -> Response::Other - if let Ok(conn) = p.get_conn().await { - let q = "DELETE FROM channels WHERE id = :id"; - let result: Result = - conn.drop_exec(q, params!{"id" => id}).await; - return match result { - Ok(_) => Response::Success, - Err(sql) => Response::Other(sql_err!(sql)) - } + Ok(Response::Set(channels)) } else { - return Response::Other(no_conn!("Member::FromDB::delete")) + return Ok(Response::RestrictedInput("Channel kind is invalid".into())); } + } - 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, - 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 new(p: &Pool, name: &str, desc: &str, kind: Integer) -> Response { //! @returns on success -> Response::Row //! @returns on partial success -> Response::Empty @@ -176,7 +61,7 @@ impl Channel { return match fetch_result { Ok((_, id_opt)) => { if let Some(id) = id_opt { - Response::Row(Channel { + Response::Row(Self { id, name: name.into(), description: Some(desc.into()), @@ -194,6 +79,28 @@ impl Channel { } } return Response::Other(no_conn!("db::channels::add")) + } + + pub async fn delete(p: &Pool, id: UBigInt) -> Response { + //! Deletes channel given UBigInt as the row key + //! @param p -> SqlPool + //! @param id -> UBigInt + //! @return on success -> Response::Success + //! @return on server failure -> Response::Other + if let Ok(conn) = p.get_conn().await { + let q = "DELETE FROM channels WHERE id = :id"; + let result: Result = + conn.drop_exec(q, params!{"id" => id}).await; + return match result { + Ok(_) => Response::Success, + Err(sql) => Response::Other(sql_err!(sql)) + } + } + else { + return Response::Other(no_conn!("Member::FromDB::delete")) + } } + + } diff --git a/json-api/db/src/lib.rs b/json-api/db/src/lib.rs index 9180621..9c03f75 100644 --- a/json-api/db/src/lib.rs +++ b/json-api/db/src/lib.rs @@ -54,6 +54,14 @@ pub struct UserMessage { pub name: VarChar } +#[derive(Serialize)] +pub struct Channel { + pub id: UBigInt, + pub name: VarChar, + pub description: Option, + pub kind: Integer +} + #[macro_export] macro_rules! fetch_row { ($table:literal, $col:literal, $key:expr, $rtype:ty,$conn:expr) => { diff --git a/json-api/src/channels.rs b/json-api/src/channels.rs index 02869b4..2b4f9e5 100644 --- a/json-api/src/channels.rs +++ b/json-api/src/channels.rs @@ -6,28 +6,33 @@ use serde_json::json; use std::collections::HashMap; -use db::{ - self, - common::FromDB, - channels::Channel -}; +use db::{ self, common::FromDB, Channel }; use crate::http::set_json_body; use crate::qs_param; -pub async fn list_channels(pool: &Pool, response: &mut Response) { +pub async fn list_channels(pool: &Pool, response: &mut Response, params: HashMap) { /* * @user-params -> for now none as i don't feel like dealing with it - * @TODO: add in a let var that actually */ - return match db::channels::Channel::filter(pool, 0).await { - db::Response::Set(channels) => { - set_json_body(response, json!({"channels": channels})); - }, - db::Response::Other(_msg) => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR, - _ => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR, + + // Default to filtering for text channels only + let chan_type = match qs_param!(params, "type", i32) { + Some(ctype) => ctype, + None => db::channels::TEXT_CHANNEL }; + + match db::Channel::filter(pool, chan_type).await { + Ok(resp) => match resp { + db::Response::Set(channels) => set_json_body(response, json!(channels)), + _ => *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR + }, + Err(e) => { + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + eprintln!("{}", e); + } + } } pub async fn create_channel(pool: &Pool, response: &mut Response, params: HashMap) { diff --git a/json-api/src/main.rs b/json-api/src/main.rs index 2cdc3cf..b303dd2 100644 --- a/json-api/src/main.rs +++ b/json-api/src/main.rs @@ -61,7 +61,7 @@ async fn route_dispatcher( (POST, routes::INVITE_CREATE) => invites::create(pool, resp, params).await, (GET, routes::INVITE_JOIN) => invites::join(pool, resp, params).await, /* CHANNELS */ - (GET, routes::CHANNELS_LIST) => channels::list_channels(pool, resp).await, + (GET, routes::CHANNELS_LIST) => channels::list_channels(pool, resp, params).await, (POST, routes::CHANNELS_CREATE) => channels::create_channel(pool, resp, params).await, (DELETE, routes::CHANNELS_DELETE) => channels::delete_channel(pool, resp, params).await, /* MESSAGING */