Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Showing
with 1273 additions and 0 deletions
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)?
}
if target.id == user.id {
return Err(Error::InvalidOperation);
}
if target.id == server.owner {
return 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(())
}
use std::collections::HashMap;
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(Serialize, Deserialize)]
enum ChannelType {
Text,
Voice
}
impl Default for ChannelType {
fn default() -> Self {
ChannelType::Text
}
}
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[serde(rename = "type", default = "ChannelType::default")]
channel_type: ChannelType,
#[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_channels() {
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 = match info.channel_type {
ChannelType::Text => Channel::TextChannel {
id: id.clone(),
server: target.id.clone(),
nonce: Some(info.nonce),
name: info.name,
description: info.description,
icon: None,
last_message: None,
default_permissions: None,
role_permissions: HashMap::new()
},
ChannelType::Voice => Channel::VoiceChannel {
id: id.clone(),
server: target.id.clone(),
nonce: Some(info.nonce),
name: info.name,
description: info.description,
icon: None,
default_permissions: None,
role_permissions: HashMap::new()
}
};
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))
}
use crate::database::*;
use crate::util::result::{Error, Result};
use futures::StreamExt;
use mongodb::bson::{doc, from_document};
use rocket_contrib::json::JsonValue;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ServerInvite {
#[serde(rename = "_id")]
code: String,
creator: String,
channel: String,
}
#[get("/<target>/invites")]
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_server() {
Err(Error::MissingPermission)?
}
let mut cursor = get_collection("channel_invites")
.find(
doc! {
"server": target.id
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find",
with: "channel_invites",
})?;
let mut invites = vec![];
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
if let Ok(invite) = from_document::<Invite>(doc) {
invites.push(invite);
}
}
}
Ok(json!(invites))
}
use std::collections::HashSet;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use crate::{database::*, notifications::events::RemoveMemberField};
use mongodb::bson::{doc, to_document};
use rocket_contrib::json::Json;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate(length(min = 1, max = 32))]
nickname: Option<String>,
avatar: Option<String>,
roles: Option<Vec<String>>,
remove: Option<RemoveMemberField>,
}
#[patch("/<server>/members/<target>", data = "<data>")]
pub async fn req(user: User, server: Ref, target: String, data: Json<Data>) -> Result<()> {
let data = data.into_inner();
data.validate()
.map_err(|error| Error::FailedValidation { error })?;
if data.nickname.is_none() && data.avatar.is_none() && data.roles.is_none() && data.remove.is_none() {
return Ok(());
}
let server = server.fetch_server().await?;
let target = Ref::from(target)?.fetch_member(&server.id).await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&server)
.for_server()
.await?;
if data.roles.is_some() && !perm.get_manage_roles() {
return Err(Error::MissingPermission);
}
if target.id.user == user.id {
if (data.nickname.is_some() && !perm.get_change_nickname())
|| (data.avatar.is_some() && !perm.get_change_avatar())
{
return Err(Error::MissingPermission);
}
if let Some(remove) = &data.remove {
if match remove {
RemoveMemberField::Avatar => !perm.get_change_avatar(),
RemoveMemberField::Nickname => !perm.get_change_nickname(),
} {
return Err(Error::MissingPermission);
}
}
} else {
if data.avatar.is_some() || (data.nickname.is_some() && !perm.get_manage_nicknames()) {
return Err(Error::MissingPermission);
}
if let Some(remove) = &data.remove {
if match remove {
RemoveMemberField::Avatar => !perm.get_remove_avatars(),
RemoveMemberField::Nickname => !perm.get_manage_nicknames(),
} {
return Err(Error::MissingPermission);
}
}
}
let mut set = doc! {};
let mut unset = doc! {};
let mut remove_avatar = false;
if let Some(remove) = &data.remove {
match remove {
RemoveMemberField::Avatar => {
unset.insert("avatar", 1);
remove_avatar = true;
}
RemoveMemberField::Nickname => {
unset.insert("nickname", 1);
}
}
}
if let Some(name) = &data.nickname {
set.insert("nickname", name);
}
if let Some(attachment_id) = &data.avatar {
let attachment =
File::find_and_use(&attachment_id, "avatars", "user", &target.id.user).await?;
set.insert(
"avatar",
to_document(&attachment).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "attachment",
})?,
);
remove_avatar = true;
}
if let Some(role_ids) = &data.roles {
let mut ids = HashSet::new();
for role in role_ids {
if server.roles.contains_key(role) {
ids.insert(role.clone());
}
}
set.insert("roles", ids.into_iter().collect::<Vec<String>>());
}
let mut operations = doc! {};
if set.len() > 0 {
operations.insert("$set", &set);
}
if unset.len() > 0 {
operations.insert("$unset", unset);
}
if operations.len() > 0 {
get_collection("server_members")
.update_one(
doc! { "_id.server": &server.id, "_id.user": &target.id.user },
operations,
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "server_member",
})?;
}
ClientboundNotification::ServerMemberUpdate {
id: target.id.clone(),
data: json!(set),
clear: data.remove,
}
.publish(server.id.clone());
let Member { avatar, .. } = target;
if remove_avatar {
if let Some(old_avatar) = avatar {
old_avatar.delete().await?;
}
}
Ok(())
}
use crate::database::*;
use crate::util::result::{Error, Result};
use mongodb::bson::doc;
use rocket_contrib::json::JsonValue;
#[get("/<target>/members/<member>")]
pub async fn req(user: User, target: Ref, member: String) -> Result<JsonValue> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_view() {
Err(Error::MissingPermission)?
}
Ok(json!(Ref::from(member)?.fetch_member(&target.id).await?))
}
use crate::database::*;
use crate::util::result::{Error, Result};
use futures::StreamExt;
use mongodb::bson::{doc, from_document, Document};
use rocket_contrib::json::JsonValue;
// ! FIXME: this is a temporary route while permissions are being worked on.
#[get("/<target>/members")]
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_view() {
Err(Error::MissingPermission)?
}
let members = get_collection("server_members")
.find(
doc! {
"_id.server": target.id
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find",
with: "server_members",
})?
.filter_map(async move |s| s.ok())
.collect::<Vec<Document>>()
.await
.into_iter()
.filter_map(|x| from_document(x).ok())
.collect::<Vec<Member>>();
let member_ids = members
.iter()
.map(|m| m.id.user.clone())
.collect::<Vec<String>>();
Ok(json!({
"members": members,
"users": user.fetch_multiple_users(member_ids).await?
}))
}
use crate::database::*;
use crate::util::result::{Error, Result};
use mongodb::bson::doc;
#[delete("/<target>/members/<member>")]
pub async fn req(user: User, target: Ref, member: String) -> Result<()> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_kick_members() {
return Err(Error::MissingPermission);
}
let member = Ref::from(member)?.fetch_member(&target.id).await?;
if member.id.user == user.id {
return Err(Error::InvalidOperation);
}
if target.id == target.owner {
return Err(Error::MissingPermission);
}
target
.remove_member(&member.id.user, RemoveMember::Kick)
.await
}
use rocket::Route;
mod server_create;
mod server_delete;
mod server_edit;
mod server_fetch;
mod channel_create;
mod member_edit;
mod member_fetch;
mod member_fetch_all;
mod member_remove;
mod ban_create;
mod ban_list;
mod ban_remove;
mod invites_fetch;
mod roles_create;
mod roles_edit;
mod roles_delete;
mod permissions_set;
mod permissions_set_default;
pub fn routes() -> Vec<Route> {
routes![
server_create::req,
server_delete::req,
server_fetch::req,
server_edit::req,
channel_create::req,
member_fetch_all::req,
member_remove::req,
member_fetch::req,
member_edit::req,
ban_create::req,
ban_remove::req,
ban_list::req,
invites_fetch::req,
roles_create::req,
roles_edit::req,
roles_delete::req,
permissions_set::req,
permissions_set_default::req
]
}
use mongodb::bson::doc;
use rocket_contrib::json::Json;
use serde::{Serialize, Deserialize};
use crate::database::*;
use crate::database::permissions::channel::ChannelPermission;
use crate::database::permissions::server::ServerPermission;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
#[derive(Serialize, Deserialize)]
pub struct Values {
server: u32,
channel: u32
}
#[derive(Serialize, Deserialize)]
pub struct Data {
permissions: Values
}
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
pub async fn req(user: User, target: Ref, role_id: String, data: Json<Data>) -> Result<()> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_manage_roles() {
return Err(Error::MissingPermission);
}
if !target.roles.contains_key(&role_id) {
return Err(Error::NotFound);
}
let server_permissions: u32 = ServerPermission::View as u32 | data.permissions.server;
let channel_permissions: u32 = ChannelPermission::View as u32 | data.permissions.channel;
get_collection("servers")
.update_one(
doc! { "_id": &target.id },
doc! {
"$set": {
"roles.".to_owned() + &role_id + &".permissions": [
server_permissions as i32,
channel_permissions as i32
]
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "server"
})?;
ClientboundNotification::ServerRoleUpdate {
id: target.id.clone(),
role_id,
data: json!({
"permissions": [
server_permissions as i32,
channel_permissions as i32
]
}),
clear: None
}
.publish(target.id);
Ok(())
}
use mongodb::bson::doc;
use rocket_contrib::json::Json;
use serde::{Serialize, Deserialize};
use crate::database::*;
use crate::database::permissions::channel::ChannelPermission;
use crate::database::permissions::server::ServerPermission;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
#[derive(Serialize, Deserialize)]
pub struct Values {
server: u32,
channel: u32
}
#[derive(Serialize, Deserialize)]
pub struct Data {
permissions: Values
}
#[put("/<target>/permissions/default", data = "<data>", rank = 1)]
pub async fn req(user: User, target: Ref, data: Json<Data>) -> Result<()> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_manage_roles() {
return Err(Error::MissingPermission);
}
let server_permissions: u32 = ServerPermission::View as u32 | data.permissions.server;
let channel_permissions: u32 = ChannelPermission::View as u32 | data.permissions.channel;
get_collection("servers")
.update_one(
doc! { "_id": &target.id },
doc! {
"$set": {
"default_permissions": [
server_permissions as i32,
channel_permissions as i32
]
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "server"
})?;
ClientboundNotification::ServerUpdate {
id: target.id.clone(),
data: json!({
"default_permissions": [
server_permissions as i32,
channel_permissions as i32
]
}),
clear: None
}
.publish(target.id);
Ok(())
}
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use ulid::Ulid;
use mongodb::bson::doc;
use validator::Validate;
use serde::{Serialize, Deserialize};
use rocket_contrib::json::{Json, JsonValue};
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate(length(min = 1, max = 32))]
name: String
}
#[post("/<target>/roles", data = "<data>")]
pub async fn req(user: User, target: Ref, data: Json<Data>) -> Result<JsonValue> {
let data = data.into_inner();
data.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_roles() {
Err(Error::MissingPermission)?
}
let id = Ulid::new().to_string();
let perm_tuple = (
*permissions::server::DEFAULT_PERMISSION as i32,
*permissions::channel::DEFAULT_PERMISSION_SERVER as i32
);
get_collection("servers")
.update_one(
doc! {
"_id": &target.id
},
doc! {
"$set": {
"roles.".to_owned() + &id: {
"name": &data.name,
"permissions": [
&perm_tuple.0,
&perm_tuple.1
]
}
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "servers"
})?;
ClientboundNotification::ServerRoleUpdate {
id: target.id.clone(),
role_id: id.clone(),
data: json!({
"name": data.name,
"permissions": &perm_tuple
}),
clear: None
}
.publish(target.id);
Ok(json!({ "id": id, "permissions": perm_tuple }))
}
use crate::database::*;
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use mongodb::bson::doc;
#[delete("/<target>/roles/<role_id>")]
pub async fn req(user: User, target: Ref, role_id: String) -> Result<()> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_manage_roles() {
Err(Error::MissingPermission)?
}
get_collection("servers")
.update_one(
doc! {
"_id": &target.id
},
doc! {
"$unset": {
"roles.".to_owned() + &role_id: 1
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "servers"
})?;
get_collection("channels")
.update_one(
doc! {
"server": &target.id
},
doc! {
"$unset": {
"role_permissions.".to_owned() + &role_id: 1
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "channels"
})?;
get_collection("server_members")
.update_many(
doc! {
"_id.server": &target.id
},
doc! {
"$pull": {
"roles": &role_id
}
},
None
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_many",
with: "server_members"
})?;
ClientboundNotification::ServerRoleDelete {
id: target.id.clone(),
role_id
}
.publish(target.id);
Ok(())
}
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use crate::{database::*, notifications::events::RemoveRoleField};
use mongodb::bson::doc;
use rocket_contrib::json::Json;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate(length(min = 1, max = 32))]
name: Option<String>,
#[validate(length(min = 1, max = 32))]
colour: Option<String>,
remove: Option<RemoveRoleField>,
}
#[patch("/<target>/roles/<role_id>", data = "<data>")]
pub async fn req(user: User, target: Ref, role_id: String, data: Json<Data>) -> Result<()> {
let data = data.into_inner();
data.validate()
.map_err(|error| Error::FailedValidation { error })?;
if data.name.is_none() && data.colour.is_none() && data.remove.is_none()
{
return Ok(());
}
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_manage_roles() {
return Err(Error::MissingPermission)
}
if !target.roles.contains_key(&role_id) {
return Err(Error::InvalidRole)
}
let mut set = doc! {};
let mut unset = doc! {};
// ! FIXME: we should probably just require clients to support basic MQL incl. $set / $unset
let mut set_update = doc! {};
let role_key = "roles.".to_owned() + &role_id;
if let Some(remove) = &data.remove {
match remove {
RemoveRoleField::Colour => {
unset.insert(role_key.clone() + ".colour", 1);
}
}
}
if let Some(name) = &data.name {
set.insert(role_key.clone() + ".name", name);
set_update.insert("name", name);
}
if let Some(colour) = &data.colour {
set.insert(role_key.clone() + ".colour", colour);
set_update.insert("colour", colour);
}
let mut operations = doc! {};
if set.len() > 0 {
operations.insert("$set", &set);
}
if unset.len() > 0 {
operations.insert("$unset", unset);
}
if operations.len() > 0 {
get_collection("servers")
.update_one(doc! { "_id": &target.id }, operations, None)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "server",
})?;
}
ClientboundNotification::ServerRoleUpdate {
id: target.id.clone(),
role_id,
data: json!(set_update),
clear: data.remove,
}
.publish(target.id.clone());
Ok(())
}
use std::collections::HashMap;
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("/create", data = "<info>")]
pub async fn req(user: User, info: Json<Data>) -> Result<JsonValue> {
let info = info.into_inner();
info.validate()
.map_err(|error| Error::FailedValidation { error })?;
if get_collection("servers")
.find_one(
doc! {
"nonce": &info.nonce
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "server",
})?
.is_some()
{
Err(Error::DuplicateNonce)?
}
let id = Ulid::new().to_string();
let cid = Ulid::new().to_string();
let server = Server {
id: id.clone(),
nonce: Some(info.nonce.clone()),
owner: user.id.clone(),
name: info.name,
description: info.description,
channels: vec![cid.clone()],
categories: None,
system_messages: Some(SystemMessageChannels {
user_joined: Some(cid.clone()),
user_left: Some(cid.clone()),
user_kicked: Some(cid.clone()),
user_banned: Some(cid.clone()),
}),
roles: HashMap::new(),
default_permissions: (
*permissions::server::DEFAULT_PERMISSION as i32,
*permissions::channel::DEFAULT_PERMISSION_SERVER as i32
),
icon: None,
banner: None,
};
Channel::TextChannel {
id: cid,
server: id,
nonce: Some(info.nonce),
name: "general".to_string(),
description: None,
icon: None,
last_message: None,
default_permissions: None,
role_permissions: HashMap::new()
}
.publish()
.await?;
server.clone().create().await?;
server.join_member(&user.id).await?;
Ok(json!(server))
}
use crate::database::*;
use crate::util::result::{Error, Result};
use mongodb::bson::doc;
#[delete("/<target>")]
pub async fn req(user: User, target: Ref) -> Result<()> {
let target = target.fetch_server().await?;
let perm = permissions::PermissionCalculator::new(&user)
.with_server(&target)
.for_server()
.await?;
if !perm.get_view() {
return Err(Error::MissingPermission);
}
if user.id == target.owner {
target.delete().await
} else {
target.remove_member(&user.id, RemoveMember::Leave).await
}
}
use crate::notifications::events::ClientboundNotification;
use crate::util::result::{Error, Result};
use crate::{database::*, notifications::events::RemoveServerField};
use mongodb::bson::{doc, to_bson, to_document};
use rocket_contrib::json::Json;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Validate, Serialize, Deserialize)]
pub struct Data {
#[validate(length(min = 1, max = 32))]
name: Option<String>,
#[validate(length(min = 0, max = 1024))]
description: Option<String>,
icon: Option<String>,
banner: Option<String>,
categories: Option<Vec<Category>>,
system_messages: Option<SystemMessageChannels>,
remove: Option<RemoveServerField>,
}
#[patch("/<target>", data = "<data>")]
pub async fn req(user: User, target: Ref, data: Json<Data>) -> Result<()> {
let data = data.into_inner();
data.validate()
.map_err(|error| Error::FailedValidation { error })?;
if data.name.is_none() && data.description.is_none() && data.icon.is_none() && data.banner.is_none() && data.remove.is_none() && data.categories.is_none() && data.system_messages.is_none()
{
return Ok(());
}
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)?
}
let mut set = doc! {};
let mut unset = doc! {};
let mut remove_icon = false;
let mut remove_banner = false;
if let Some(remove) = &data.remove {
match remove {
RemoveServerField::Icon => {
unset.insert("icon", 1);
remove_icon = true;
}
RemoveServerField::Banner => {
unset.insert("banner", 1);
remove_banner = true;
}
RemoveServerField::Description => {
unset.insert("description", 1);
}
}
}
if let Some(name) = &data.name {
set.insert("name", name);
}
if let Some(description) = &data.description {
set.insert("description", description);
}
if let Some(attachment_id) = &data.icon {
let attachment = File::find_and_use(&attachment_id, "icons", "object", &target.id).await?;
set.insert(
"icon",
to_document(&attachment).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "attachment",
})?,
);
remove_icon = true;
}
if let Some(attachment_id) = &data.banner {
let attachment =
File::find_and_use(&attachment_id, "banners", "server", &target.id).await?;
set.insert(
"banner",
to_document(&attachment).map_err(|_| Error::DatabaseError {
operation: "to_document",
with: "attachment",
})?,
);
remove_banner = true;
}
if let Some(categories) = &data.categories {
set.insert("categories", to_bson(&categories).map_err(|_| Error::DatabaseError { operation: "to_document", with: "categories" })?);
}
if let Some(system_messages) = &data.system_messages {
set.insert("system_messages", to_bson(&system_messages).map_err(|_| Error::DatabaseError { operation: "to_document", with: "system_messages" })?);
}
let mut operations = doc! {};
if set.len() > 0 {
operations.insert("$set", &set);
}
if unset.len() > 0 {
operations.insert("$unset", unset);
}
if operations.len() > 0 {
get_collection("servers")
.update_one(doc! { "_id": &target.id }, operations, None)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
with: "server",
})?;
}
ClientboundNotification::ServerUpdate {
id: target.id.clone(),
data: json!(set),
clear: data.remove,
}
.publish(target.id.clone());
let Server { icon, banner, .. } = target;
if remove_icon {
if let Some(old_icon) = icon {
old_icon.delete().await?;
}
}
if remove_banner {
if let Some(old_banner) = banner {
old_banner.delete().await?;
}
}
Ok(())
}
use crate::database::*;
use crate::util::result::{Error, Result};
use rocket_contrib::json::JsonValue;
#[get("/<target>")]
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_view() {
Err(Error::MissingPermission)?
}
Ok(json!(target))
}
use crate::database::*;
use crate::util::result::{Error, Result};
use mongodb::bson::doc;
use mongodb::options::FindOneOptions;
use rocket_contrib::json::{Json, JsonValue};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Options {
keys: Vec<String>,
}
#[post("/settings/fetch", data = "<options>")]
pub async fn req(user: User, options: Json<Options>) -> Result<JsonValue> {
let options = options.into_inner();
let mut projection = doc! {
"_id": 0,
};
for key in options.keys {
projection.insert(key, 1);
}
if let Some(doc) = get_collection("user_settings")
.find_one(
doc! {
"_id": user.id
},
FindOneOptions::builder().projection(projection).build(),
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find_one",
with: "user_settings",
})?
{
Ok(json!(doc))
} else {
Ok(json!({}))
}
}
use crate::database::*;
use crate::util::result::Result;
use mongodb::bson::doc;
use rocket_contrib::json::JsonValue;
#[get("/unreads")]
pub async fn req(user: User) -> Result<JsonValue> {
Ok(json!(User::fetch_unreads(&user.id).await?))
}
use rocket::Route;
mod get_settings;
mod get_unreads;
mod set_settings;
pub fn routes() -> Vec<Route> {
routes![get_settings::req, set_settings::req, get_unreads::req]
}