forked from jmug/stoatchat
Servers: Ban and unban users +
ban list.
This commit is contained in:
@@ -30,7 +30,7 @@ pub struct Member {
|
|||||||
pub struct Ban {
|
pub struct Ban {
|
||||||
#[serde(rename = "_id")]
|
#[serde(rename = "_id")]
|
||||||
pub id: MemberCompositeKey,
|
pub id: MemberCompositeKey,
|
||||||
pub reason: String,
|
pub reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
@@ -234,6 +234,23 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn join_member(&self, id: &str) -> Result<()> {
|
pub async fn join_member(&self, id: &str) -> Result<()> {
|
||||||
|
if get_collection("server_bans")
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"_id.server": &self.id,
|
||||||
|
"_id.user": &id
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "server_bans",
|
||||||
|
})?
|
||||||
|
.is_some() {
|
||||||
|
return Err(Error::Banned)
|
||||||
|
}
|
||||||
|
|
||||||
get_collection("server_members")
|
get_collection("server_members")
|
||||||
.insert_one(
|
.insert_one(
|
||||||
doc! {
|
doc! {
|
||||||
@@ -260,7 +277,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_member(&self, id: &str) -> Result<()> {
|
pub async fn remove_member(&self, id: &str) -> Result<()> {
|
||||||
get_collection("server_members")
|
let result = get_collection("server_members")
|
||||||
.delete_one(
|
.delete_one(
|
||||||
doc! {
|
doc! {
|
||||||
"_id": {
|
"_id": {
|
||||||
@@ -276,11 +293,13 @@ impl Server {
|
|||||||
with: "server_members",
|
with: "server_members",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
ClientboundNotification::ServerMemberLeave {
|
if result.deleted_count > 0 {
|
||||||
id: self.id.clone(),
|
ClientboundNotification::ServerMemberLeave {
|
||||||
user: id.to_string()
|
id: self.id.clone(),
|
||||||
|
user: id.to_string()
|
||||||
|
}
|
||||||
|
.publish(self.id.clone());
|
||||||
}
|
}
|
||||||
.publish(self.id.clone());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl Ref {
|
|||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch<T: DeserializeOwned>(&self, collection: &'static str) -> Result<T> {
|
async fn fetch<T: DeserializeOwned>(&self, collection: &'static str) -> Result<T> {
|
||||||
let doc = get_collection(&collection)
|
let doc = get_collection(&collection)
|
||||||
.find_one(
|
.find_one(
|
||||||
doc! {
|
doc! {
|
||||||
@@ -84,6 +84,28 @@ impl Ref {
|
|||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_ban(&self, server: &str) -> Result<Ban> {
|
||||||
|
let doc = get_collection("server_bans")
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"_id.user": &self.id,
|
||||||
|
"_id.server": server
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "server_ban",
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| Error::NotFound)?;
|
||||||
|
|
||||||
|
Ok(from_document::<Ban>(doc).map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "from_document",
|
||||||
|
with: "server_ban",
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_message(&self, channel: &Channel) -> Result<Message> {
|
pub async fn fetch_message(&self, channel: &Channel) -> Result<Message> {
|
||||||
let message: Message = self.fetch("messages").await?;
|
let message: Message = self.fetch("messages").await?;
|
||||||
if &message.channel != channel.id() {
|
if &message.channel != channel.id() {
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ pub enum ServerPermission {
|
|||||||
ManageMembers = 0b00000000000000000000000000000010, // 2
|
ManageMembers = 0b00000000000000000000000000000010, // 2
|
||||||
ManageChannels = 0b00000000000000000000000000000100, // 4
|
ManageChannels = 0b00000000000000000000000000000100, // 4
|
||||||
ManageServer = 0b00000000000000000000000000001000, // 8
|
ManageServer = 0b00000000000000000000000000001000, // 8
|
||||||
// 8 bits of space
|
KickMembers = 0b00000000000000000000000000010000, // 16
|
||||||
|
BanMembers = 0b00000000000000000000000000100000, // 32
|
||||||
|
// 6 bits of space
|
||||||
ChangeNickname = 0b00000000000000000001000000000000, // 4096
|
ChangeNickname = 0b00000000000000000001000000000000, // 4096
|
||||||
ManageNicknames = 0b00000000000000000010000000000000, // 8192
|
ManageNicknames = 0b00000000000000000010000000000000, // 8192
|
||||||
ChangeAvatar = 0b00000000000000000100000000000000, // 16392
|
ChangeAvatar = 0b00000000000000000100000000000000, // 16392
|
||||||
@@ -30,6 +32,8 @@ bitfield! {
|
|||||||
pub get_manage_members, _: 30;
|
pub get_manage_members, _: 30;
|
||||||
pub get_manage_channels, _: 29;
|
pub get_manage_channels, _: 29;
|
||||||
pub get_manage_server, _: 28;
|
pub get_manage_server, _: 28;
|
||||||
|
pub get_kick_members, _: 27;
|
||||||
|
pub get_ban_members, _: 26;
|
||||||
|
|
||||||
pub get_change_nickname, _: 19;
|
pub get_change_nickname, _: 19;
|
||||||
pub get_manage_nicknames, _: 18;
|
pub get_manage_nicknames, _: 18;
|
||||||
|
|||||||
56
src/routes/servers/ban_create.rs
Normal file
56
src/routes/servers/ban_create.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
use validator::Validate;
|
||||||
|
use rocket_contrib::json::Json;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Validate, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
#[validate(length(min = 1, max = 1024))]
|
||||||
|
reason: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[put("/<server>/bans/<target>", data = "<data>")]
|
||||||
|
pub async fn req(user: User, server: Ref, target: Ref, data: Json<Data>) -> Result<()> {
|
||||||
|
let data = data.into_inner();
|
||||||
|
data.validate()
|
||||||
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
|
let server = server.fetch_server().await?;
|
||||||
|
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_server(&server)
|
||||||
|
.for_server()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_ban_members() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = target.fetch_user().await?;
|
||||||
|
let mut document = doc! {
|
||||||
|
"_id": {
|
||||||
|
"server": &server.id,
|
||||||
|
"user": &target.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(reason) = data.reason {
|
||||||
|
document.insert("reason", reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_collection("server_bans")
|
||||||
|
.insert_one(
|
||||||
|
document,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "insert_one",
|
||||||
|
with: "server_ban"
|
||||||
|
})?;
|
||||||
|
|
||||||
|
server.remove_member(&target.id).await
|
||||||
|
}
|
||||||
44
src/routes/servers/ban_list.rs
Normal file
44
src/routes/servers/ban_list.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
use rocket_contrib::json::JsonValue;
|
||||||
|
use mongodb::bson::{doc, from_document};
|
||||||
|
|
||||||
|
#[get("/<target>/bans")]
|
||||||
|
pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
||||||
|
let target = target.fetch_server().await?;
|
||||||
|
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_server(&target)
|
||||||
|
.for_server()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_manage_members() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cursor = get_collection("server_bans")
|
||||||
|
.find(
|
||||||
|
doc! {
|
||||||
|
"_id.server": target.id
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find",
|
||||||
|
with: "server_bans",
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut bans = vec![];
|
||||||
|
while let Some(result) = cursor.next().await {
|
||||||
|
if let Ok(doc) = result {
|
||||||
|
if let Ok(ban) = from_document::<Ban>(doc) {
|
||||||
|
bans.push(ban);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(bans))
|
||||||
|
}
|
||||||
35
src/routes/servers/ban_remove.rs
Normal file
35
src/routes/servers/ban_remove.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
|
||||||
|
#[delete("/<server>/bans/<target>")]
|
||||||
|
pub async fn req(user: User, server: Ref, target: Ref) -> Result<()> {
|
||||||
|
let server = server.fetch_server().await?;
|
||||||
|
|
||||||
|
let perm = permissions::PermissionCalculator::new(&user)
|
||||||
|
.with_server(&server)
|
||||||
|
.for_server()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !perm.get_ban_members() {
|
||||||
|
Err(Error::MissingPermission)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = target.fetch_ban(&server.id).await?;
|
||||||
|
get_collection("server_bans")
|
||||||
|
.delete_one(
|
||||||
|
doc! {
|
||||||
|
"_id.server": &server.id,
|
||||||
|
"_id.user": &target.id.user
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "delete_one",
|
||||||
|
with: "server_ban"
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -12,6 +12,10 @@ mod member_remove;
|
|||||||
mod member_fetch;
|
mod member_fetch;
|
||||||
mod member_edit;
|
mod member_edit;
|
||||||
|
|
||||||
|
mod ban_create;
|
||||||
|
mod ban_remove;
|
||||||
|
mod ban_list;
|
||||||
|
|
||||||
mod invites_fetch;
|
mod invites_fetch;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
@@ -25,6 +29,9 @@ pub fn routes() -> Vec<Route> {
|
|||||||
member_remove::req,
|
member_remove::req,
|
||||||
member_fetch::req,
|
member_fetch::req,
|
||||||
member_edit::req,
|
member_edit::req,
|
||||||
|
ban_create::req,
|
||||||
|
ban_remove::req,
|
||||||
|
ban_list::req,
|
||||||
invites_fetch::req
|
invites_fetch::req
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ pub enum Error {
|
|||||||
|
|
||||||
// ? Server related errors.
|
// ? Server related errors.
|
||||||
UnknownServer,
|
UnknownServer,
|
||||||
|
Banned,
|
||||||
|
|
||||||
// ? General errors.
|
// ? General errors.
|
||||||
TooManyIds,
|
TooManyIds,
|
||||||
@@ -87,6 +88,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::NotInGroup => Status::NotFound,
|
Error::NotInGroup => Status::NotFound,
|
||||||
|
|
||||||
Error::UnknownServer => Status::NotFound,
|
Error::UnknownServer => Status::NotFound,
|
||||||
|
Error::Banned => 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