diff --git a/src/database/channel.rs b/src/database/channel.rs index be88081674f577f6dae95b7607a1f56777bf9bcd..e60856b83db8af5a69a76dc428392118ec01c232 100644 --- a/src/database/channel.rs +++ b/src/database/channel.rs @@ -4,7 +4,10 @@ use serde::{ Deserialize, Serialize }; pub struct Channel { #[serde(rename = "_id")] pub id: String, + #[serde(rename = "type")] pub channel_type: u8, + + pub last_message: Option<String>, // for Direct Messages pub recipients: Option<Vec<String>>, diff --git a/src/database/message.rs b/src/database/message.rs index d65b2118e29611af733a3c2e02db9bf9ceabbd6f..9411b82e88c7993622b5745366a5722284f9d3fc 100644 --- a/src/database/message.rs +++ b/src/database/message.rs @@ -1,8 +1,13 @@ - use serde::{ Deserialize, Serialize }; +use bson::{ UtcDateTime }; #[derive(Serialize, Deserialize, Debug)] pub struct Message { #[serde(rename = "_id")] - pub id: String, + pub id: String, + pub channel: String, + pub author: String, + + pub content: String, + pub edited: Option<UtcDateTime>, } diff --git a/src/guards/channel.rs b/src/guards/channel.rs index daa277d5ced8aefd760ab31e77571414f47e1c99..fde2b82b7476f7b6a79ad3c83e146107853ab298 100644 --- a/src/guards/channel.rs +++ b/src/guards/channel.rs @@ -2,7 +2,7 @@ use rocket::http::{ RawStr }; use rocket::request::{ FromParam }; use bson::{ bson, doc, from_bson }; -use crate::database; +use crate::database::{ self, user::User }; use database::channel::Channel; use database::message::Message; diff --git a/src/routes/channel.rs b/src/routes/channel.rs index 81d3f07437e4255573b61ebe7193a1c9914c0739..66a90f6c7203bc127d132eb1cc3b31cd3efaa713 100644 --- a/src/routes/channel.rs +++ b/src/routes/channel.rs @@ -1,8 +1,11 @@ -use crate::database::{ user::User, channel::Channel }; +use crate::database::{ self, user::User, channel::Channel, message::Message }; -use rocket_contrib::json::{ JsonValue }; +use bson::{ bson, doc, from_bson, Bson::UtcDatetime }; +use rocket_contrib::json::{ JsonValue, Json }; +use serde::{ Serialize, Deserialize }; use num_enum::TryFromPrimitive; -use bson::{ doc }; +use chrono::prelude::*; +use ulid::Ulid; #[derive(Debug, TryFromPrimitive)] #[repr(usize)] @@ -46,3 +49,190 @@ pub fn channel(user: User, target: Channel) -> Option<JsonValue> { } )) } + +/// delete channel +/// or leave group DM +/// or close DM conversation +#[delete("/<target>")] +pub fn delete(user: User, target: Channel) -> Option<JsonValue> { + 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("/<target>/messages")] +pub fn messages(user: User, target: Channel) -> Option<JsonValue> { + 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("/<target>/messages", data = "<message>")] +pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) -> Option<JsonValue> { + 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, + "author": user.id, + "content": message.content.clone(), + }, + None + ) { + Ok(_) => + json!({ + "success": true, + "id": id + }), + Err(_) => + json!({ + "success": false, + "error": "Failed database query." + }) + }) +} + +#[derive(Serialize, Deserialize)] +pub struct EditMessage { + content: String, +} + +/// edit a message +#[patch("/<target>/messages/<message>", data = "<edit>")] +pub fn edit_message(user: User, target: Channel, message: Message, edit: Json<SendMessage>) -> Option<JsonValue> { + 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.update_one( + doc! { "_id": message.id }, + doc! { + "$set": { + "content": edit.content.clone(), + "edited": UtcDatetime(Utc::now()) + } + }, + None + ) { + Ok(_) => + json!({ + "success": true + }), + Err(_) => + json!({ + "success": false, + "error": "Failed to update message." + }) + } + } + ) +} + +/// delete a message +#[delete("/<target>/messages/<message>")] +pub fn delete_message(user: User, target: Channel, message: Message) -> Option<JsonValue> { + 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 }, + None + ) { + Ok(_) => + json!({ + "success": true + }), + Err(_) => + json!({ + "success": false, + "error": "Failed to delete message." + }) + } + } + ) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index b1890803fdaf8e5654b1ec430fd9dd2f37078709..ef4de3380303e526baaffdb6908e4d297fb93b2c 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -8,5 +8,5 @@ pub fn mount(rocket: Rocket) -> Rocket { rocket .mount("/api/account", routes![ account::create, account::verify_email, account::resend_email, account::login ]) .mount("/api/users", routes![ user::me, user::user, user::lookup, user::dms, user::dm, user::get_friends, user::get_friend, user::add_friend, user::remove_friend ]) - .mount("/api/channels", routes![ channel::channel ]) + .mount("/api/channels", routes![ channel::channel, channel::delete, channel::messages, channel::send_message, channel::edit_message, channel::delete_message ]) }