Skip to content
Snippets Groups Projects
Commit 34ac8f54 authored by insert's avatar insert
Browse files

Add group creation. Sync channels to clients on creation.

parent c562d33c
No related merge requests found
use crate::database::*; use crate::{database::*, notifications::{events::ClientboundNotification, hive}};
use crate::util::result::{Error, Result}; use crate::util::result::{Error, Result};
use mongodb::bson::to_document;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use mongodb::bson::to_document;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Channel { pub enum Channel {
SavedMessages { SavedMessages {
...@@ -20,6 +20,8 @@ pub enum Channel { ...@@ -20,6 +20,8 @@ pub enum Channel {
Group { Group {
#[serde(rename = "_id")] #[serde(rename = "_id")]
id: String, id: String,
#[serde(skip_serializing_if = "Option::is_none")]
nonce: Option<String>,
name: String, name: String,
owner: String, owner: String,
description: String, description: String,
...@@ -36,7 +38,7 @@ impl Channel { ...@@ -36,7 +38,7 @@ impl Channel {
} }
} }
pub async fn save(&self) -> Result<()> { pub async fn publish(self) -> Result<()> {
get_collection("channels") get_collection("channels")
.insert_one( .insert_one(
to_document(&self).map_err(|_| Error::DatabaseError { to_document(&self).map_err(|_| Error::DatabaseError {
...@@ -50,6 +52,25 @@ impl Channel { ...@@ -50,6 +52,25 @@ impl Channel {
operation: "insert_one", operation: "insert_one",
with: "channel", with: "channel",
})?; })?;
// ! IMPORTANT FIXME: THESE SUBSCRIPTIONS SHOULD BE DONE FROM HIVE NOT HERE!!!
let channel_id = self.id().to_string();
match &self {
Channel::SavedMessages { user, .. } => {
hive::subscribe_if_exists(user.clone(), channel_id.clone()).ok();
}
Channel::DirectMessage { recipients, .. } |
Channel::Group { recipients, .. } => {
for recipient in recipients {
hive::subscribe_if_exists(recipient.clone(), channel_id.clone()).ok();
}
}
}
ClientboundNotification::ChannelCreate(self)
.publish(channel_id)
.await
.ok();
Ok(()) Ok(())
} }
......
...@@ -26,7 +26,7 @@ pub struct Message { ...@@ -26,7 +26,7 @@ pub struct Message {
pub previous_content: Vec<PreviousEntry>, pub previous_content: Vec<PreviousEntry>,
}*/ }*/
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Message { pub struct Message {
#[serde(rename = "_id")] #[serde(rename = "_id")]
pub id: String, pub id: String,
...@@ -41,7 +41,7 @@ pub struct Message { ...@@ -41,7 +41,7 @@ pub struct Message {
} }
impl Message { impl Message {
pub async fn send(self) -> Result<()> { pub async fn publish(self) -> Result<()> {
get_collection("messages") get_collection("messages")
.insert_one(to_bson(&self).unwrap().as_document().unwrap().clone(), None) .insert_one(to_bson(&self).unwrap().as_document().unwrap().clone(), None)
.await .await
......
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum RelationshipStatus { pub enum RelationshipStatus {
None, None,
User, User,
......
...@@ -42,6 +42,8 @@ pub enum ClientboundNotification { ...@@ -42,6 +42,8 @@ pub enum ClientboundNotification {
id: String, id: String,
}, },
ChannelCreate(Channel),
/*MessageCreate { /*MessageCreate {
id: String, id: String,
nonce: Option<String>, nonce: Option<String>,
......
use crate::database::*;
use crate::util::result::{Error, Result};
use crate::util::variables::MAX_GROUP_SIZE;
use mongodb::bson::doc;
use rocket_contrib::json::{Json, JsonValue};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::iter::FromIterator;
use ulid::Ulid;
use validator::Validate;
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate(length(min = 1, max = 32))]
name: String,
#[validate(length(min = 0, max = 1024))]
description: Option<String>,
// Maximum length of 36 allows both ULIDs and UUIDs.
#[validate(length(min = 1, max = 36))]
nonce: String,
users: Vec<String>
}
#[post("/create", data = "<info>")]
pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
info
.validate()
.map_err(|error| Error::FailedValidation { error })?;
let mut set: HashSet<String> = HashSet::from_iter(info.users.iter().cloned());
set.insert(user.id.clone());
if set.len() > *MAX_GROUP_SIZE {
Err(Error::GroupTooLarge { max: *MAX_GROUP_SIZE })?
}
if get_collection("channels")
.find_one(
doc! {
"nonce": &info.nonce
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "channel",
})?
.is_some()
{
Err(Error::DuplicateNonce)?
}
for target in &set {
if get_relationship(&user, target) != RelationshipStatus::Friend {
Err(Error::NotFriends)?
}
}
let id = Ulid::new().to_string();
let channel = Channel::Group {
id,
nonce: Some(info.nonce.clone()),
name: info.name.clone(),
description: info.description.clone().unwrap_or_else(|| "A group.".to_string()),
owner: user.id,
recipients: set.into_iter().collect::<Vec<String>>()
};
channel.clone().publish().await?;
Ok(json!(channel))
}
...@@ -2,7 +2,7 @@ use crate::database::*; ...@@ -2,7 +2,7 @@ use crate::database::*;
use crate::util::result::{Error, Result}; use crate::util::result::{Error, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket_contrib::json::Json; use rocket_contrib::json::{Json, JsonValue};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ulid::Ulid; use ulid::Ulid;
use validator::Validate; use validator::Validate;
...@@ -17,7 +17,7 @@ pub struct Data { ...@@ -17,7 +17,7 @@ pub struct Data {
} }
#[post("/<target>/messages", data = "<message>")] #[post("/<target>/messages", data = "<message>")]
pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> { pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<JsonValue> {
message message
.validate() .validate()
.map_err(|error| Error::FailedValidation { error })?; .map_err(|error| Error::FailedValidation { error })?;
...@@ -43,10 +43,10 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> { ...@@ -43,10 +43,10 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> {
})? })?
.is_some() .is_some()
{ {
Err(Error::AlreadySentMessage)? Err(Error::DuplicateNonce)?
} }
Message { let msg = Message {
id: Ulid::new().to_string(), id: Ulid::new().to_string(),
channel: target.id().to_string(), channel: target.id().to_string(),
author: user.id, author: user.id,
...@@ -54,9 +54,12 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> { ...@@ -54,9 +54,12 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> {
content: message.content.clone(), content: message.content.clone(),
nonce: Some(message.nonce.clone()), nonce: Some(message.nonce.clone()),
edited: None, edited: None,
} };
.send()
.await?; msg
.clone()
.publish()
.await?;
Ok(()) Ok(json!(msg))
} }
...@@ -7,6 +7,7 @@ mod message_edit; ...@@ -7,6 +7,7 @@ mod message_edit;
mod message_fetch; mod message_fetch;
mod message_query; mod message_query;
mod message_send; mod message_send;
mod group_create;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![ routes![
...@@ -16,6 +17,7 @@ pub fn routes() -> Vec<Route> { ...@@ -16,6 +17,7 @@ pub fn routes() -> Vec<Route> {
message_query::req, message_query::req,
message_fetch::req, message_fetch::req,
message_edit::req, message_edit::req,
message_delete::req message_delete::req,
group_create::req
] ]
} }
...@@ -43,7 +43,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> { ...@@ -43,7 +43,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
} }
}; };
channel.save().await?; channel.clone().publish().await?;
Ok(json!(channel)) Ok(json!(channel))
} }
} }
...@@ -30,13 +30,17 @@ pub enum Error { ...@@ -30,13 +30,17 @@ pub enum Error {
Blocked, Blocked,
#[snafu(display("You have been blocked by this user."))] #[snafu(display("You have been blocked by this user."))]
BlockedByOther, BlockedByOther,
#[snafu(display("Not friends with target user."))]
NotFriends,
// ? Channel related errors. // ? Channel related errors.
#[snafu(display("Already sent a message with this nonce."))]
AlreadySentMessage,
#[snafu(display("Cannot edit someone else's message."))] #[snafu(display("Cannot edit someone else's message."))]
CannotEditMessage, CannotEditMessage,
#[snafu(display("Group size is too large."))]
GroupTooLarge {
max: usize
},
// ? General errors. // ? General errors.
#[snafu(display("Failed to validate fields."))] #[snafu(display("Failed to validate fields."))]
FailedValidation { error: ValidationErrors }, FailedValidation { error: ValidationErrors },
...@@ -47,6 +51,8 @@ pub enum Error { ...@@ -47,6 +51,8 @@ pub enum Error {
}, },
#[snafu(display("Internal server error."))] #[snafu(display("Internal server error."))]
InternalError, InternalError,
#[snafu(display("Already created an object with this nonce."))]
DuplicateNonce,
#[snafu(display("This request had no effect."))] #[snafu(display("This request had no effect."))]
NoEffect, NoEffect,
} }
...@@ -67,13 +73,15 @@ impl<'r> Responder<'r, 'static> for Error { ...@@ -67,13 +73,15 @@ impl<'r> Responder<'r, 'static> for Error {
Error::AlreadySentRequest => Status::Conflict, Error::AlreadySentRequest => Status::Conflict,
Error::Blocked => Status::Conflict, Error::Blocked => Status::Conflict,
Error::BlockedByOther => Status::Forbidden, Error::BlockedByOther => Status::Forbidden,
Error::NotFriends => Status::Forbidden,
Error::AlreadySentMessage => Status::Conflict,
Error::CannotEditMessage => Status::Forbidden, Error::CannotEditMessage => Status::Forbidden,
Error::GroupTooLarge { .. } => Status::Forbidden,
Error::FailedValidation { .. } => Status::UnprocessableEntity, Error::FailedValidation { .. } => Status::UnprocessableEntity,
Error::DatabaseError { .. } => Status::InternalServerError, Error::DatabaseError { .. } => Status::InternalServerError,
Error::InternalError => Status::InternalServerError, Error::InternalError => Status::InternalServerError,
Error::DuplicateNonce => Status::Conflict,
Error::NoEffect => Status::Ok, Error::NoEffect => Status::Ok,
}; };
......
...@@ -33,10 +33,14 @@ lazy_static! { ...@@ -33,10 +33,14 @@ lazy_static! {
pub static ref SMTP_HOST: String = pub static ref SMTP_HOST: String =
env::var("REVOLT_SMTP_HOST").unwrap_or_else(|_| "".to_string()); env::var("REVOLT_SMTP_HOST").unwrap_or_else(|_| "".to_string());
pub static ref SMTP_USERNAME: String = pub static ref SMTP_USERNAME: String =
env::var("SMTP_USERNAME").unwrap_or_else(|_| "".to_string()); env::var("REVOLT_SMTP_USERNAME").unwrap_or_else(|_| "".to_string());
pub static ref SMTP_PASSWORD: String = pub static ref SMTP_PASSWORD: String =
env::var("SMTP_PASSWORD").unwrap_or_else(|_| "".to_string()); env::var("REVOLT_SMTP_PASSWORD").unwrap_or_else(|_| "".to_string());
pub static ref SMTP_FROM: String = env::var("SMTP_FROM").unwrap_or_else(|_| "".to_string()); pub static ref SMTP_FROM: String = env::var("REVOLT_SMTP_FROM").unwrap_or_else(|_| "".to_string());
// Application Logic Settings
pub static ref MAX_GROUP_SIZE: usize =
env::var("REVOLT_MAX_GROUP_SIZE").unwrap_or_else(|_| "50".to_string()).parse().unwrap();
} }
pub fn preflight_checks() { pub fn preflight_checks() {
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment