Servers: Add route for creating channels.
Notifications: Subscribe to guild channels.
This commit is contained in:
@@ -42,7 +42,8 @@ pub enum Channel {
|
|||||||
|
|
||||||
name: String,
|
name: String,
|
||||||
owner: String,
|
owner: String,
|
||||||
description: String,
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
description: Option<String>,
|
||||||
recipients: Vec<String>,
|
recipients: Vec<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -58,10 +59,11 @@ pub enum Channel {
|
|||||||
nonce: Option<String>,
|
nonce: Option<String>,
|
||||||
|
|
||||||
name: String,
|
name: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
icon: Option<File>,
|
icon: Option<File>,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel {
|
impl Channel {
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use hive_pubsub::PubSub;
|
use hive_pubsub::PubSub;
|
||||||
|
use mongodb::bson::{doc, Document};
|
||||||
use rauth::auth::Session;
|
use rauth::auth::Session;
|
||||||
use mongodb::bson::{Document, doc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use rocket_contrib::json::JsonValue;
|
use rocket_contrib::json::JsonValue;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::hive::{get_hive, subscribe_if_exists};
|
use super::hive::{get_hive, subscribe_if_exists};
|
||||||
use crate::{database::*, util::result::{Error, Result}};
|
use crate::{
|
||||||
|
database::*,
|
||||||
|
util::result::{Error, Result},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(tag = "error")]
|
#[serde(tag = "error")]
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::database::*;
|
use crate::database::*;
|
||||||
|
use crate::util::result::Error;
|
||||||
|
|
||||||
use super::hive::get_hive;
|
use super::hive::get_hive;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use hive_pubsub::PubSub;
|
use hive_pubsub::PubSub;
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
|
use mongodb::bson::Document;
|
||||||
use mongodb::options::FindOptions;
|
use mongodb::options::FindOptions;
|
||||||
|
|
||||||
pub async fn generate_subscriptions(user: &User) -> Result<(), String> {
|
pub async fn generate_subscriptions(user: &User) -> Result<(), String> {
|
||||||
@@ -16,6 +18,44 @@ pub async fn generate_subscriptions(user: &User) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let server_ids = user
|
||||||
|
.fetch_server_ids()
|
||||||
|
.await
|
||||||
|
.map_err(|_| "Failed to fetch memberships.".to_string())?;
|
||||||
|
|
||||||
|
let channel_ids = get_collection("servers")
|
||||||
|
.find(
|
||||||
|
doc! {
|
||||||
|
"_id": {
|
||||||
|
"$in": &server_ids
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| "Failed to fetch servers.".to_string())?
|
||||||
|
.filter_map(async move |s| s.ok())
|
||||||
|
.collect::<Vec<Document>>()
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|x| {
|
||||||
|
x.get_array("channels").ok().map(|v| {
|
||||||
|
v.into_iter()
|
||||||
|
.filter_map(|x| x.as_str().map(|x| x.to_string()))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
for id in server_ids {
|
||||||
|
hive.subscribe(user.id.clone(), id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in channel_ids {
|
||||||
|
hive.subscribe(user.id.clone(), id)?;
|
||||||
|
}
|
||||||
|
|
||||||
let mut cursor = get_collection("channels")
|
let mut cursor = get_collection("channels")
|
||||||
.find(
|
.find(
|
||||||
doc! {
|
doc! {
|
||||||
@@ -45,14 +85,5 @@ pub async fn generate_subscriptions(user: &User) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_ids = user
|
|
||||||
.fetch_server_ids()
|
|
||||||
.await
|
|
||||||
.map_err(|_| "Failed to fetch memberships.".to_string())?;
|
|
||||||
|
|
||||||
for id in server_ids {
|
|
||||||
hive.subscribe(user.id.clone(), id)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,12 @@ pub async fn req(user: User, target: Ref) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Channel::TextChannel { .. } => unimplemented!()
|
Channel::TextChannel { .. } => {
|
||||||
|
if perm.get_manage_channel() {
|
||||||
|
target.delete().await
|
||||||
|
} else {
|
||||||
|
Err(Error::MissingPermission)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ pub struct Data {
|
|||||||
|
|
||||||
#[post("/create", data = "<info>")]
|
#[post("/create", data = "<info>")]
|
||||||
pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
||||||
|
let info = info.into_inner();
|
||||||
info.validate()
|
info.validate()
|
||||||
.map_err(|error| Error::FailedValidation { error })?;
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
@@ -62,12 +63,9 @@ pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
|||||||
let id = Ulid::new().to_string();
|
let id = Ulid::new().to_string();
|
||||||
let channel = Channel::Group {
|
let channel = Channel::Group {
|
||||||
id,
|
id,
|
||||||
nonce: Some(info.nonce.clone()),
|
nonce: Some(info.nonce),
|
||||||
name: info.name.clone(),
|
name: info.name,
|
||||||
description: info
|
description: info.description,
|
||||||
.description
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| "A group.".to_string()),
|
|
||||||
owner: user.id,
|
owner: user.id,
|
||||||
recipients: set.into_iter().collect::<Vec<String>>(),
|
recipients: set.into_iter().collect::<Vec<String>>(),
|
||||||
icon: None,
|
icon: None,
|
||||||
|
|||||||
85
src/routes/servers/channel_create.rs
Normal file
85
src/routes/servers/channel_create.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
use rocket_contrib::json::{Json, JsonValue};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/<target>/channels", data = "<info>")]
|
||||||
|
pub async fn req(user: User, target: Ref, info: Json<Data>) -> Result<JsonValue> {
|
||||||
|
let info = info.into_inner();
|
||||||
|
info.validate()
|
||||||
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
|
let target = target.fetch_server().await?;
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_server(&target)
|
||||||
|
.for_server()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_manage_server() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = Ulid::new().to_string();
|
||||||
|
let channel = Channel::TextChannel {
|
||||||
|
id: id.clone(),
|
||||||
|
server: target.id.clone(),
|
||||||
|
nonce: Some(info.nonce),
|
||||||
|
|
||||||
|
name: info.name,
|
||||||
|
description: info.description,
|
||||||
|
icon: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.clone().publish().await?;
|
||||||
|
get_collection("servers")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": target.id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$addToSet": {
|
||||||
|
"channels": id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "update_one",
|
||||||
|
with: "server",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(json!(channel))
|
||||||
|
}
|
||||||
@@ -4,6 +4,13 @@ mod server_create;
|
|||||||
mod server_delete;
|
mod server_delete;
|
||||||
mod server_edit;
|
mod server_edit;
|
||||||
|
|
||||||
|
mod channel_create;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![server_create::req, server_delete::req, server_edit::req]
|
routes![
|
||||||
|
server_create::req,
|
||||||
|
server_delete::req,
|
||||||
|
server_edit::req,
|
||||||
|
channel_create::req
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,34 +40,13 @@ pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
|||||||
|
|
||||||
let id = Ulid::new().to_string();
|
let id = Ulid::new().to_string();
|
||||||
let cid = Ulid::new().to_string();
|
let cid = Ulid::new().to_string();
|
||||||
|
|
||||||
Channel::TextChannel {
|
|
||||||
id: cid.clone(),
|
|
||||||
server: id.clone(),
|
|
||||||
nonce: Some(info.nonce.clone()),
|
|
||||||
name: "general".to_string(),
|
|
||||||
description: None,
|
|
||||||
icon: None,
|
|
||||||
}.publish().await?;
|
|
||||||
|
|
||||||
let server = Server {
|
|
||||||
id: id.clone(),
|
|
||||||
nonce: Some(info.nonce.clone()),
|
|
||||||
owner: user.id.clone(),
|
|
||||||
|
|
||||||
name: info.name.clone(),
|
|
||||||
channels: vec![ cid ],
|
|
||||||
|
|
||||||
icon: None,
|
|
||||||
banner: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
get_collection("server_members")
|
get_collection("server_members")
|
||||||
.insert_one(
|
.insert_one(
|
||||||
doc! {
|
doc! {
|
||||||
"_id": {
|
"_id": {
|
||||||
"server": id,
|
"server": &id,
|
||||||
"user": user.id
|
"user": &user.id
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@@ -78,6 +57,29 @@ pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
|
|||||||
with: "server_members",
|
with: "server_members",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
Channel::TextChannel {
|
||||||
|
id: cid.clone(),
|
||||||
|
server: id.clone(),
|
||||||
|
nonce: Some(info.nonce.clone()),
|
||||||
|
name: "general".to_string(),
|
||||||
|
description: None,
|
||||||
|
icon: None,
|
||||||
|
}
|
||||||
|
.publish()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let server = Server {
|
||||||
|
id: id.clone(),
|
||||||
|
nonce: Some(info.nonce.clone()),
|
||||||
|
owner: user.id.clone(),
|
||||||
|
|
||||||
|
name: info.name.clone(),
|
||||||
|
channels: vec![cid],
|
||||||
|
|
||||||
|
icon: None,
|
||||||
|
banner: None,
|
||||||
|
};
|
||||||
|
|
||||||
server.clone().publish().await?;
|
server.clone().publish().await?;
|
||||||
|
|
||||||
Ok(json!(server))
|
Ok(json!(server))
|
||||||
|
|||||||
Reference in New Issue
Block a user