forked from jmug/stoatchat
Invite bot to server / group for #8.
This commit is contained in:
@@ -3,6 +3,7 @@ use std::collections::HashMap;
|
|||||||
use crate::database::*;
|
use crate::database::*;
|
||||||
use crate::notifications::events::ClientboundNotification;
|
use crate::notifications::events::ClientboundNotification;
|
||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
|
use crate::util::variables::MAX_GROUP_SIZE;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use mongodb::bson::Bson;
|
use mongodb::bson::Bson;
|
||||||
use mongodb::{
|
use mongodb::{
|
||||||
@@ -344,4 +345,53 @@ impl Channel {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_to_group(&self, member: String, by_user: String) -> Result<()> {
|
||||||
|
if let Channel::Group { id, recipients, .. } = &self {
|
||||||
|
if recipients.len() >= *MAX_GROUP_SIZE {
|
||||||
|
Err(Error::GroupTooLarge {
|
||||||
|
max: *MAX_GROUP_SIZE,
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
|
||||||
|
if recipients.iter().find(|x| *x == &member).is_some() {
|
||||||
|
Err(Error::AlreadyInGroup)?
|
||||||
|
}
|
||||||
|
|
||||||
|
get_collection("channels")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": &id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$push": {
|
||||||
|
"recipients": &member
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "update_one",
|
||||||
|
with: "channel",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
ClientboundNotification::ChannelGroupJoin {
|
||||||
|
id: id.clone(),
|
||||||
|
user: member.clone(),
|
||||||
|
}
|
||||||
|
.publish(id.clone());
|
||||||
|
|
||||||
|
Content::SystemMessage(SystemMessage::UserAdded {
|
||||||
|
id: member,
|
||||||
|
by: by_user,
|
||||||
|
})
|
||||||
|
.send_as_system(&self)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidOperation)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ impl Ref {
|
|||||||
self.fetch("channel_invites").await
|
self.fetch("channel_invites").await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_bot(&self) -> Result<Bot> {
|
||||||
|
self.fetch("bots").await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_member(&self, server: &str) -> Result<Member> {
|
pub async fn fetch_member(&self, server: &str) -> Result<Member> {
|
||||||
let doc = get_collection("server_members")
|
let doc = get_collection("server_members")
|
||||||
.find_one(
|
.find_one(
|
||||||
|
|||||||
65
src/routes/bots/invite.rs
Normal file
65
src/routes/bots/invite.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct ServerId {
|
||||||
|
server: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct GroupId {
|
||||||
|
group: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Destination {
|
||||||
|
Server(ServerId),
|
||||||
|
Group(GroupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/<target>/invite", data = "<dest>")]
|
||||||
|
pub async fn invite_bot(user: User, target: Ref, dest: Json<Destination>) -> Result<()> {
|
||||||
|
let bot = target.fetch_bot().await?;
|
||||||
|
|
||||||
|
if !bot.public {
|
||||||
|
if bot.owner != user.id {
|
||||||
|
return Err(Error::BotIsPrivate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match dest.into_inner() {
|
||||||
|
Destination::Server(ServerId { server }) => {
|
||||||
|
let server = Ref::from(server)?.fetch_server().await?;
|
||||||
|
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_server(&server)
|
||||||
|
.for_server()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_manage_server() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
server.join_member(&bot.id).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Destination::Group(GroupId { group }) => {
|
||||||
|
let channel = Ref::from(group)?.fetch_channel().await?;
|
||||||
|
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_channel(&channel)
|
||||||
|
.for_channel()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_invite_others() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.add_to_group(bot.id, user.id).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
|
mod invite;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![
|
routes![
|
||||||
create::create_bot
|
create::create_bot,
|
||||||
|
invite::invite_bot
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
use crate::util::variables::MAX_GROUP_SIZE;
|
use crate::database::*;
|
||||||
use crate::{database::*, notifications::events::ClientboundNotification};
|
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
|
|
||||||
@@ -20,51 +19,5 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
|
|||||||
Err(Error::MissingPermission)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Channel::Group { id, recipients, .. } = &channel {
|
channel.add_to_group(member.id, user.id).await
|
||||||
if recipients.len() >= *MAX_GROUP_SIZE {
|
|
||||||
Err(Error::GroupTooLarge {
|
|
||||||
max: *MAX_GROUP_SIZE,
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
|
|
||||||
if recipients.iter().find(|x| *x == &member.id).is_some() {
|
|
||||||
Err(Error::AlreadyInGroup)?
|
|
||||||
}
|
|
||||||
|
|
||||||
get_collection("channels")
|
|
||||||
.update_one(
|
|
||||||
doc! {
|
|
||||||
"_id": &id
|
|
||||||
},
|
|
||||||
doc! {
|
|
||||||
"$push": {
|
|
||||||
"recipients": &member.id
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|_| Error::DatabaseError {
|
|
||||||
operation: "update_one",
|
|
||||||
with: "channel",
|
|
||||||
})?;
|
|
||||||
|
|
||||||
ClientboundNotification::ChannelGroupJoin {
|
|
||||||
id: id.clone(),
|
|
||||||
user: member.id.clone(),
|
|
||||||
}
|
|
||||||
.publish(id.clone());
|
|
||||||
|
|
||||||
Content::SystemMessage(SystemMessage::UserAdded {
|
|
||||||
id: member.id,
|
|
||||||
by: user.id,
|
|
||||||
})
|
|
||||||
.send_as_system(&channel)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::InvalidOperation)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::database::*;
|
use crate::database::*;
|
||||||
use crate::util::result::Result;
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
use rocket::serde::json::Value;
|
use rocket::serde::json::Value;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ pub enum Error {
|
|||||||
// ? Bot related errors.
|
// ? Bot related errors.
|
||||||
ReachedMaximumBots,
|
ReachedMaximumBots,
|
||||||
IsBot,
|
IsBot,
|
||||||
|
BotIsPrivate,
|
||||||
|
|
||||||
// ? General errors.
|
// ? General errors.
|
||||||
TooManyIds,
|
TooManyIds,
|
||||||
@@ -104,6 +105,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
|
|
||||||
Error::ReachedMaximumBots => Status::BadRequest,
|
Error::ReachedMaximumBots => Status::BadRequest,
|
||||||
Error::IsBot => Status::BadRequest,
|
Error::IsBot => Status::BadRequest,
|
||||||
|
Error::BotIsPrivate => Status::Forbidden,
|
||||||
|
|
||||||
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
||||||
Error::DatabaseError { .. } => Status::InternalServerError,
|
Error::DatabaseError { .. } => Status::InternalServerError,
|
||||||
|
|||||||
Reference in New Issue
Block a user