freechat/server/src/messages.rs
2020-07-10 19:54:41 -07:00

98 lines
3.6 KiB
Rust

use std::borrow::Cow;
use mysql_async::{Conn, Pool, params};
use mysql_async::prelude::{Queryable};
use mysql_async::error::Error;
use hyper::{Response, Body, StatusCode};
use serde_json::Value;
use chrono::Utc;
use crate::members::Member;
use crate::channels::{Channel, ChannelID, ChannelType};
struct Message {
author: Member,
date: u64, // used as thr primary key in our table
content: String,
channel: Channel
}
fn validate_params(p: &Value, keys: Vec<&str>) -> bool {
let mut fail = false;
for key in keys.iter() {
if let None = p.get(key) {
fail = true;
break;
}
}
return fail == false;
}
async fn update_messages_table(pool: &Pool, secret: &str, content: Option<&str>, id: Option<ChannelID>)
-> Result<(), mysql_async::error::Error> {
match (content, id) {
(Some(content), Some(id)) => {
let conn = pool.get_conn().await?;
// get the user data first since we kinda need it
// make sure the channel exists
const CID_QUERY: &'static str = "SELECT kind from `channels` WHERE id = :id";
let (conn, row): (Conn, Option<i32>) = conn
.first_exec(CID_QUERY, params!{"id"=>id})
.await?;
let channel_exists = match row {
Some(r) => r == ChannelType::Text.as_i32(),
None => false
};
// may as well grab the user id now since the fail case is going to be rare (hopefully)
const UID_QUERY : &'static str = "SELECT userid FROM `keys` WHERE `secret` = :secret";
let (conn, row): (Conn, Option<u64>) = conn
.first_exec(UID_QUERY, params!{"secret"=>secret})
.await?;
// for a message entry we need: (DATE, CONTENT, AUTHOR_ID, Channel_id)
if channel_exists {
// NOTE: not checking if the user exists as our auth model does that
// for us already
conn.batch_exec(
"INSERT INTO `messages` (id, content, author_id, channel_id) \
VALUES (:mid, :content, :aid, :cid)",
params!{
"mid" => Utc::now().timestamp() as u64,
"content" => content,
"aid" => row.expect("uid is None when it should have come back as Some(u64):\
Occurence in <update_messages_table, batch_exec>"),
"cid" => id
}).await?;
Ok(())
}
else {
let x = Cow::from("Channel does not exist");
Err(Error::Other(x))
}
}
_ => {
let x = Cow::from("Missing required parameters to create message");
Err(Error::Other(x))
}
}
}
pub async fn send_message(pool: &Pool, response: &mut Response<Body>, params: Value) {
/*
* @content: expecting string type
* @id: expecting the channel id that we're posting data to
*/
if validate_params(&params, vec!["content", "id"]) {
// now we prepare some arguments for our db and send them down the wire
let content = params.get("content").unwrap().as_str();
let id = params.get("id").unwrap().as_u64();
let secret: &str = params.get("secret").unwrap().as_str().unwrap(); //auth sucess guarantees this param is fine
match update_messages_table(pool, secret, content, id).await {
Ok(_) => *response.status_mut() = StatusCode::OK,
Err(_err) => *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR
}
}
}