mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 13:36:59 +00:00
Add group creation. Sync channels to clients on creation.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
use crate::database::*;
|
||||
use crate::{database::*, notifications::{events::ClientboundNotification, hive}};
|
||||
use crate::util::result::{Error, Result};
|
||||
use mongodb::bson::to_document;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use mongodb::bson::to_document;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Channel {
|
||||
SavedMessages {
|
||||
@@ -20,6 +20,8 @@ pub enum Channel {
|
||||
Group {
|
||||
#[serde(rename = "_id")]
|
||||
id: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
nonce: Option<String>,
|
||||
name: String,
|
||||
owner: String,
|
||||
description: String,
|
||||
@@ -36,7 +38,7 @@ impl Channel {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save(&self) -> Result<()> {
|
||||
pub async fn publish(self) -> Result<()> {
|
||||
get_collection("channels")
|
||||
.insert_one(
|
||||
to_document(&self).map_err(|_| Error::DatabaseError {
|
||||
@@ -50,6 +52,25 @@ impl Channel {
|
||||
operation: "insert_one",
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct Message {
|
||||
pub previous_content: Vec<PreviousEntry>,
|
||||
}*/
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Message {
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
@@ -41,7 +41,7 @@ pub struct Message {
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub async fn send(self) -> Result<()> {
|
||||
pub async fn publish(self) -> Result<()> {
|
||||
get_collection("messages")
|
||||
.insert_one(to_bson(&self).unwrap().as_document().unwrap().clone(), None)
|
||||
.await
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub enum RelationshipStatus {
|
||||
None,
|
||||
User,
|
||||
|
||||
@@ -42,6 +42,8 @@ pub enum ClientboundNotification {
|
||||
id: String,
|
||||
},
|
||||
|
||||
ChannelCreate(Channel),
|
||||
|
||||
/*MessageCreate {
|
||||
id: String,
|
||||
nonce: Option<String>,
|
||||
|
||||
74
src/routes/channels/group_create.rs
Normal file
74
src/routes/channels/group_create.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
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::*;
|
||||
use crate::util::result::{Error, Result};
|
||||
|
||||
use mongodb::bson::doc;
|
||||
use rocket_contrib::json::Json;
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
@@ -17,7 +17,7 @@ pub struct Data {
|
||||
}
|
||||
|
||||
#[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
|
||||
.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
@@ -43,10 +43,10 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> {
|
||||
})?
|
||||
.is_some()
|
||||
{
|
||||
Err(Error::AlreadySentMessage)?
|
||||
Err(Error::DuplicateNonce)?
|
||||
}
|
||||
|
||||
Message {
|
||||
let msg = Message {
|
||||
id: Ulid::new().to_string(),
|
||||
channel: target.id().to_string(),
|
||||
author: user.id,
|
||||
@@ -54,9 +54,12 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> {
|
||||
content: message.content.clone(),
|
||||
nonce: Some(message.nonce.clone()),
|
||||
edited: None,
|
||||
}
|
||||
.send()
|
||||
.await?;
|
||||
};
|
||||
|
||||
msg
|
||||
.clone()
|
||||
.publish()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
Ok(json!(msg))
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ mod message_edit;
|
||||
mod message_fetch;
|
||||
mod message_query;
|
||||
mod message_send;
|
||||
mod group_create;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
@@ -16,6 +17,7 @@ pub fn routes() -> Vec<Route> {
|
||||
message_query::req,
|
||||
message_fetch::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> {
|
||||
}
|
||||
};
|
||||
|
||||
channel.save().await?;
|
||||
channel.clone().publish().await?;
|
||||
Ok(json!(channel))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,17 @@ pub enum Error {
|
||||
Blocked,
|
||||
#[snafu(display("You have been blocked by this user."))]
|
||||
BlockedByOther,
|
||||
#[snafu(display("Not friends with target user."))]
|
||||
NotFriends,
|
||||
|
||||
// ? Channel related errors.
|
||||
#[snafu(display("Already sent a message with this nonce."))]
|
||||
AlreadySentMessage,
|
||||
#[snafu(display("Cannot edit someone else's message."))]
|
||||
CannotEditMessage,
|
||||
|
||||
#[snafu(display("Group size is too large."))]
|
||||
GroupTooLarge {
|
||||
max: usize
|
||||
},
|
||||
|
||||
// ? General errors.
|
||||
#[snafu(display("Failed to validate fields."))]
|
||||
FailedValidation { error: ValidationErrors },
|
||||
@@ -47,6 +51,8 @@ pub enum Error {
|
||||
},
|
||||
#[snafu(display("Internal server error."))]
|
||||
InternalError,
|
||||
#[snafu(display("Already created an object with this nonce."))]
|
||||
DuplicateNonce,
|
||||
#[snafu(display("This request had no effect."))]
|
||||
NoEffect,
|
||||
}
|
||||
@@ -67,13 +73,15 @@ impl<'r> Responder<'r, 'static> for Error {
|
||||
Error::AlreadySentRequest => Status::Conflict,
|
||||
Error::Blocked => Status::Conflict,
|
||||
Error::BlockedByOther => Status::Forbidden,
|
||||
Error::NotFriends => Status::Forbidden,
|
||||
|
||||
Error::AlreadySentMessage => Status::Conflict,
|
||||
Error::CannotEditMessage => Status::Forbidden,
|
||||
|
||||
Error::GroupTooLarge { .. } => Status::Forbidden,
|
||||
|
||||
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
||||
Error::DatabaseError { .. } => Status::InternalServerError,
|
||||
Error::InternalError => Status::InternalServerError,
|
||||
Error::DuplicateNonce => Status::Conflict,
|
||||
Error::NoEffect => Status::Ok,
|
||||
};
|
||||
|
||||
|
||||
@@ -33,10 +33,14 @@ lazy_static! {
|
||||
pub static ref SMTP_HOST: String =
|
||||
env::var("REVOLT_SMTP_HOST").unwrap_or_else(|_| "".to_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 =
|
||||
env::var("SMTP_PASSWORD").unwrap_or_else(|_| "".to_string());
|
||||
pub static ref SMTP_FROM: String = env::var("SMTP_FROM").unwrap_or_else(|_| "".to_string());
|
||||
env::var("REVOLT_SMTP_PASSWORD").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() {
|
||||
|
||||
Reference in New Issue
Block a user