use crate::database::{ self, user::User, channel::Channel, message::Message }; use crate::websocket; use bson::{ bson, doc, from_bson, Bson::UtcDatetime }; use rocket_contrib::json::{ JsonValue, Json }; use serde::{ Serialize, Deserialize }; use num_enum::TryFromPrimitive; use chrono::prelude::*; use ulid::Ulid; #[derive(Debug, TryFromPrimitive)] #[repr(usize)] pub enum ChannelType { DM = 0, GROUPDM = 1, GUILDCHANNEL = 2, } fn has_permission(user: &User, target: &Channel) -> bool { match target.channel_type { 0..=1 => { if let Some(arr) = &target.recipients { for item in arr { if item == &user.id { return true; } } } false }, 2 => false, _ => false } } fn get_recipients(target: &Channel) -> Vec { match target.channel_type { 0..=1 => target.recipients.clone().unwrap(), _ => vec![] } } /// fetch channel information #[get("/")] pub fn channel(user: User, target: Channel) -> Option { if !has_permission(&user, &target) { return None } Some( json!({ "id": target.id, "type": target.channel_type, "recipients": get_recipients(&target), } )) } /// delete channel /// or leave group DM /// or close DM conversation #[delete("/")] pub fn delete(user: User, target: Channel) -> Option { if !has_permission(&user, &target) { return None } let col = database::get_collection("channels"); Some(match target.channel_type { 0 => { col.update_one( doc! { "_id": target.id }, doc! { "$set": { "active": false } }, None ).expect("Failed to update channel."); json!({ "success": true }) }, 1 => { // ? TODO: group dm json!({ "success": true }) }, 2 => { // ? TODO: guild json!({ "success": true }) }, _ => json!({ "success": false }) }) } /// fetch channel messages #[get("//messages")] pub fn messages(user: User, target: Channel) -> Option { if !has_permission(&user, &target) { return None } let col = database::get_collection("messages"); let result = col.find( doc! { "channel": target.id }, None ).unwrap(); let mut messages = Vec::new(); for item in result { let message: Message = from_bson(bson::Bson::Document(item.unwrap())).expect("Failed to unwrap message."); messages.push( json!({ "id": message.id, "author": message.author, "content": message.content, "edited": if let Some(t) = message.edited { Some(t.timestamp()) } else { None } }) ); } Some(json!(messages)) } #[derive(Serialize, Deserialize)] pub struct SendMessage { content: String, } /// send a message to a channel #[post("//messages", data = "")] pub fn send_message(user: User, target: Channel, message: Json) -> Option { if !has_permission(&user, &target) { return None } let col = database::get_collection("messages"); let id = Ulid::new().to_string(); Some(match col.insert_one( doc! { "_id": id.clone(), "channel": target.id.clone(), "author": user.id.clone(), "content": message.content.clone(), }, None ) { Ok(_) => { if target.channel_type == ChannelType::DM as u8 { let col = database::get_collection("channels"); col.update_one( doc! { "_id": target.id.clone() }, doc! { "$set": { "active": true } }, None ).unwrap(); } websocket::queue_message( get_recipients(&target), json!({ "type": "message", "data": { "id": id.clone(), "channel": target.id, "author": user.id, "content": message.content.clone(), }, }).to_string() ); json!({ "success": true, "id": id }) }, Err(_) => json!({ "success": false, "error": "Failed database query." }) }) } /// get a message #[get("//messages/")] pub fn get_message(user: User, target: Channel, message: Message) -> Option { if !has_permission(&user, &target) { return None } Some( json!({ "id": message.id, "author": message.author, "content": message.content, "edited": if let Some(t) = message.edited { Some(t.timestamp()) } else { None } }) ) } #[derive(Serialize, Deserialize)] pub struct EditMessage { content: String, } /// edit a message #[patch("//messages/", data = "")] pub fn edit_message(user: User, target: Channel, message: Message, edit: Json) -> Option { if !has_permission(&user, &target) { return None } Some( if message.author != user.id { json!({ "success": false, "error": "You did not send this message." }) } else { let col = database::get_collection("messages"); let edited = Utc::now(); match col.update_one( doc! { "_id": message.id.clone() }, doc! { "$set": { "content": edit.content.clone(), "edited": UtcDatetime(edited.clone()) } }, None ) { Ok(_) => { websocket::queue_message( get_recipients(&target), json!({ "type": "message_update", "data": { "id": message.id, "channel": target.id, "content": edit.content.clone(), "edited": edited.timestamp() }, }).to_string() ); json!({ "success": true }) }, Err(_) => json!({ "success": false, "error": "Failed to update message." }) } } ) } /// delete a message #[delete("//messages/")] pub fn delete_message(user: User, target: Channel, message: Message) -> Option { if !has_permission(&user, &target) { return None } Some( if message.author != user.id { json!({ "success": false, "error": "You did not send this message." }) } else { let col = database::get_collection("messages"); match col.delete_one( doc! { "_id": message.id.clone() }, None ) { Ok(_) => { websocket::queue_message( get_recipients(&target), json!({ "type": "message_delete", "data": { "id": message.id, "channel": target.id }, }).to_string() ); json!({ "success": true }) }, Err(_) => json!({ "success": false, "error": "Failed to delete message." }) } } ) }