From 9e42567050af430322710d7d6824ccc93baee831 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Sun, 7 Apr 2024 22:13:42 +0100 Subject: [PATCH] refactor(quark): port roles_create, roles_delete, roles_edit, roles_fetch, server_ack, server_delete, server_edit, server_fetch #283 --- crates/core/database/src/models/bots/model.rs | 2 +- crates/core/database/src/util/bridge/v0.rs | 41 ++++++ crates/core/models/src/v0/servers.rs | 123 +++++++++++++++++- crates/delta/src/routes/servers/mod.rs | 16 +-- .../delta/src/routes/servers/roles_create.rs | 80 +++++------- .../delta/src/routes/servers/roles_delete.rs | 31 +++-- crates/delta/src/routes/servers/roles_edit.rs | 79 +++++------ .../delta/src/routes/servers/roles_fetch.rs | 21 +-- crates/delta/src/routes/servers/server_ack.rs | 18 ++- .../delta/src/routes/servers/server_delete.rs | 31 ++--- .../delta/src/routes/servers/server_edit.rs | 112 ++++++---------- .../delta/src/routes/servers/server_fetch.rs | 67 ++++------ 12 files changed, 355 insertions(+), 266 deletions(-) diff --git a/crates/core/database/src/models/bots/model.rs b/crates/core/database/src/models/bots/model.rs index 14796240..cf36bedc 100644 --- a/crates/core/database/src/models/bots/model.rs +++ b/crates/core/database/src/models/bots/model.rs @@ -93,7 +93,7 @@ impl Bot { Some(id.to_string()), Some(PartialUser { bot: Some(BotInformation { - owner: id.to_string(), + owner: owner.id.to_string(), }), ..Default::default() }), diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index d6b0b794..5509589a 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -587,6 +587,18 @@ impl From for FieldsServer { } } +impl From for crate::FieldsServer { + fn from(value: FieldsServer) -> crate::FieldsServer { + match value { + FieldsServer::Banner => crate::FieldsServer::Banner, + FieldsServer::Categories => crate::FieldsServer::Categories, + FieldsServer::Description => crate::FieldsServer::Description, + FieldsServer::Icon => crate::FieldsServer::Icon, + FieldsServer::SystemMessages => crate::FieldsServer::SystemMessages, + } + } +} + impl From for Category { fn from(value: crate::Category) -> Self { Category { @@ -597,6 +609,16 @@ impl From for Category { } } +impl From for crate::Category { + fn from(value: Category) -> Self { + crate::Category { + id: value.id, + title: value.title, + channels: value.channels, + } + } +} + impl From for SystemMessageChannels { fn from(value: crate::SystemMessageChannels) -> Self { SystemMessageChannels { @@ -608,6 +630,17 @@ impl From for SystemMessageChannels { } } +impl From for crate::SystemMessageChannels { + fn from(value: SystemMessageChannels) -> Self { + crate::SystemMessageChannels { + user_joined: value.user_joined, + user_left: value.user_left, + user_kicked: value.user_kicked, + user_banned: value.user_banned, + } + } +} + impl From for Role { fn from(value: crate::Role) -> Self { Role { @@ -640,6 +673,14 @@ impl From for FieldsRole { } } +impl From for crate::FieldsRole { + fn from(value: FieldsRole) -> Self { + match value { + FieldsRole::Colour => crate::FieldsRole::Colour, + } + } +} + impl crate::User { pub async fn into<'a, P>(self, db: &Database, perspective: P) -> User where diff --git a/crates/core/models/src/v0/servers.rs b/crates/core/models/src/v0/servers.rs index 424eb674..ae5a50a2 100644 --- a/crates/core/models/src/v0/servers.rs +++ b/crates/core/models/src/v0/servers.rs @@ -1,4 +1,4 @@ -use super::{Channel, File}; +use super::{Channel, File, RE_COLOUR}; use revolt_permissions::{Override, OverrideField}; use std::collections::HashMap; @@ -6,6 +6,9 @@ use std::collections::HashMap; #[cfg(feature = "validator")] use validator::Validate; +#[cfg(feature = "rocket")] +use rocket::FromForm; + auto_derived_partial!( /// Server pub struct Server { @@ -120,10 +123,13 @@ auto_derived!( } /// Channel category + #[cfg_attr(feature = "validator", derive(Validate))] pub struct Category { /// Unique ID for this category + #[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))] pub id: String, /// Title for this category + #[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))] pub title: String, /// Channels in this category pub channels: Vec, @@ -160,10 +166,24 @@ auto_derived!( pub nsfw: Option, } - /// New role permissions - pub struct DataSetServerRolePermission { - /// Allow / deny values for the role in this server. - pub permissions: Override, + /// Information about new role to create + #[cfg_attr(feature = "validator", derive(Validate))] + pub struct DataCreateRole { + /// Role name + #[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))] + pub name: String, + /// Ranking position + /// + /// Smaller values take priority. + pub rank: Option, + } + + /// Response after creating new role + pub struct NewRoleResponse { + /// Id of the role + pub id: String, + /// New role + pub role: Role, } /// Information returned when creating server @@ -173,4 +193,97 @@ auto_derived!( /// Default channels pub channels: Vec, } + + /// Options when fetching server + #[cfg_attr(feature = "rocket", derive(FromForm))] + pub struct OptionsFetchServer { + /// Whether to include channels + pub include_channels: Option, + } + + /// Fetch server information + #[serde(untagged)] + pub enum FetchServerResponse { + JustServer(Server), + ServerWithChannels { + #[serde(flatten)] + server: Server, + channels: Vec, + }, + } + + /// New server information + #[cfg_attr(feature = "validator", derive(Validate))] + pub struct DataEditServer { + /// Server name + #[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))] + pub name: Option, + /// Server description + #[cfg_attr(feature = "validator", validate(length(min = 0, max = 1024)))] + pub description: Option, + + /// Attachment Id for icon + pub icon: Option, + /// Attachment Id for banner + pub banner: Option, + + /// Category structure for server + #[cfg_attr(feature = "validator", validate)] + pub categories: Option>, + /// System message configuration + pub system_messages: Option, + + /// Bitfield of server flags + #[cfg_attr(feature = "validator", serde(skip_serializing_if = "Option::is_none"))] + pub flags: Option, + + // Whether this server is age-restricted + // nsfw: Option, + /// Whether this server is public and should show up on [Revolt Discover](https://rvlt.gg) + pub discoverable: Option, + /// Whether analytics should be collected for this server + /// + /// Must be enabled in order to show up on [Revolt Discover](https://rvlt.gg). + pub analytics: Option, + + /// Fields to remove from server object + #[cfg_attr(feature = "validator", validate(length(min = 1)))] + pub remove: Option>, + } + + /// New role information + #[cfg_attr(feature = "validator", derive(Validate))] + pub struct DataEditRole { + /// Role name + #[cfg_attr(feature = "validator", validate(length(min = 1, max = 32)))] + pub name: Option, + /// Role colour + #[cfg_attr( + feature = "validator", + validate(length(min = 1, max = 128), regex = "RE_COLOUR") + )] + pub colour: Option, + /// Whether this role should be displayed separately + pub hoist: Option, + /// Ranking position + /// + /// Smaller values take priority. + pub rank: Option, + /// Fields to remove from role object + #[cfg_attr(feature = "validator", validate(length(min = 1)))] + pub remove: Option>, + } + + /// New role permissions + pub struct DataSetServerRolePermission { + /// Allow / deny values for the role in this server. + pub permissions: Override, + } + + /// Options when leaving a server + #[cfg_attr(feature = "rocket", derive(FromForm))] + pub struct OptionsServerDelete { + /// Whether to not send a leave message + pub leave_silently: Option, + } ); diff --git a/crates/delta/src/routes/servers/mod.rs b/crates/delta/src/routes/servers/mod.rs index a0197130..a7553625 100644 --- a/crates/delta/src/routes/servers/mod.rs +++ b/crates/delta/src/routes/servers/mod.rs @@ -27,10 +27,10 @@ mod server_fetch; pub fn routes() -> (Vec, OpenApi) { openapi_get_routes_spec![ server_create::create_server, - server_delete::req, - server_fetch::req, - server_edit::req, - server_ack::req, + server_delete::delete, + server_fetch::fetch, + server_edit::edit, + server_ack::ack, channel_create::create_server_channel, member_fetch_all::fetch_all, member_remove::kick, @@ -41,10 +41,10 @@ pub fn routes() -> (Vec, OpenApi) { ban_remove::unban, ban_list::list, invites_fetch::invites, - roles_create::req, - roles_edit::req, - roles_fetch::req, - roles_delete::req, + roles_create::create, + roles_edit::edit, + roles_fetch::fetch, + roles_delete::delete, permissions_set::set_role_permission, permissions_set_default::set_default_permissions, emoji_list::list_emoji diff --git a/crates/delta/src/routes/servers/roles_create.rs b/crates/delta/src/routes/servers/roles_create.rs index 54e01637..a9e07d2b 100644 --- a/crates/delta/src/routes/servers/roles_create.rs +++ b/crates/delta/src/routes/servers/roles_create.rs @@ -1,63 +1,49 @@ -use revolt_quark::{ - models::{server::Role, User}, - perms, Db, Error, Permission, Ref, Result, variables::delta::MAX_ROLE_COUNT, +use revolt_config::config; +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, Role, User, }; - -use rocket::serde::json::Json; -use serde::{Deserialize, Serialize}; +use revolt_models::v0; +use revolt_permissions::{calculate_server_permissions, ChannelPermission}; +use revolt_result::{create_error, Result}; +use rocket::{serde::json::Json, State}; use validator::Validate; -/// # Role Data -#[derive(Validate, Deserialize, JsonSchema)] -pub struct DataCreateRole { - /// Role name - #[validate(length(min = 1, max = 32))] - name: String, - /// Ranking position - /// - /// Smaller values take priority. - rank: Option, -} - -/// # New Role Response -#[derive(Serialize, JsonSchema)] -pub struct NewRoleResponse { - /// Id of the role - id: String, - /// New role - role: Role, -} - /// # Create Role /// /// Creates a new server role. #[openapi(tag = "Server Permissions")] #[post("//roles", data = "")] -pub async fn req( - db: &Db, +pub async fn create( + db: &State, user: User, - target: Ref, - data: Json, -) -> Result> { + target: Reference, + data: Json, +) -> Result> { let data = data.into_inner(); - data.validate() - .map_err(|error| Error::FailedValidation { error })?; + data.validate().map_err(|error| { + create_error!(FailedValidation { + error: error.to_string() + }) + })?; let server = target.as_server(db).await?; - let mut permissions = perms(&user).server(&server); + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + calculate_server_permissions(&mut query) + .await + .throw_if_lacking_channel_permission(ChannelPermission::ManageRole); - permissions - .throw_permission(db, Permission::ManageRole) - .await?; - - if server.roles.len() > *MAX_ROLE_COUNT { - return Err(Error::TooManyRoles { max: *MAX_ROLE_COUNT }) + let config = config().await; + if server.roles.len() >= config.features.limits.default.server_roles { + return Err(create_error!(TooManyRoles { + max: config.features.limits.default.server_roles, + })); }; - let member_rank = permissions.get_member_rank(); + let member_rank = query.get_member_rank(); let rank = if let Some(given_rank) = data.rank { if given_rank <= member_rank.unwrap_or(i64::MIN) { - return Err(Error::NotElevated); + return Err(create_error!(NotElevated)); } given_rank @@ -68,11 +54,13 @@ pub async fn req( let role = Role { name: data.name, rank, - ..Default::default() + colour: None, + hoist: false, + permissions: Default::default(), }; - Ok(Json(NewRoleResponse { + Ok(Json(v0::NewRoleResponse { id: role.create(db, &server.id).await?, - role, + role: role.into(), })) } diff --git a/crates/delta/src/routes/servers/roles_delete.rs b/crates/delta/src/routes/servers/roles_delete.rs index 6d60db1d..e7df633a 100644 --- a/crates/delta/src/routes/servers/roles_delete.rs +++ b/crates/delta/src/routes/servers/roles_delete.rs @@ -1,29 +1,40 @@ -use revolt_quark::{models::User, perms, Db, EmptyResponse, Error, Permission, Ref, Result}; +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, User, +}; +use revolt_permissions::{calculate_server_permissions, ChannelPermission}; +use revolt_result::{create_error, Result}; +use rocket::State; +use rocket_empty::EmptyResponse; /// # Delete Role /// /// Delete a server role by its id. #[openapi(tag = "Server Permissions")] #[delete("//roles/")] -pub async fn req(db: &Db, user: User, target: Ref, role_id: String) -> Result { +pub async fn delete( + db: &State, + user: User, + target: Reference, + role_id: String, +) -> Result { let mut server = target.as_server(db).await?; - let mut permissions = perms(&user).server(&server); + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + calculate_server_permissions(&mut query) + .await + .throw_if_lacking_channel_permission(ChannelPermission::ManageRole); - permissions - .throw_permission(db, Permission::ManageRole) - .await?; - - let member_rank = permissions.get_member_rank().unwrap_or(i64::MIN); + let member_rank = query.get_member_rank().unwrap_or(i64::MIN); if let Some(role) = server.roles.remove(&role_id) { if role.rank <= member_rank { - return Err(Error::NotElevated); + return Err(create_error!(NotElevated)); } role.delete(db, &server.id, &role_id) .await .map(|_| EmptyResponse) } else { - Err(Error::NotFound) + Err(create_error!(NotFound)) } } diff --git a/crates/delta/src/routes/servers/roles_edit.rs b/crates/delta/src/routes/servers/roles_edit.rs index cbd38e12..a75c011c 100644 --- a/crates/delta/src/routes/servers/roles_edit.rs +++ b/crates/delta/src/routes/servers/roles_edit.rs @@ -1,69 +1,48 @@ -use revolt_quark::{ - models::{ - server::{FieldsRole, PartialRole, Role}, - User, - }, - perms, - util::regex::RE_COLOUR, - Db, Error, Permission, Ref, Result, +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, PartialRole, User, }; - -use rocket::serde::json::Json; +use revolt_models::v0; +use revolt_permissions::{calculate_server_permissions, ChannelPermission}; +use revolt_result::{create_error, Result}; +use rocket::{serde::json::Json, State}; use serde::{Deserialize, Serialize}; use validator::Validate; -/// # Role Data -#[derive(Validate, Serialize, Deserialize, JsonSchema)] -pub struct DataEditRole { - /// Role name - #[validate(length(min = 1, max = 32))] - name: Option, - /// Role colour - #[validate(length(min = 1, max = 128), regex = "RE_COLOUR")] - colour: Option, - /// Whether this role should be displayed separately - hoist: Option, - /// Ranking position - /// - /// Smaller values take priority. - rank: Option, - /// Fields to remove from role object - #[validate(length(min = 1))] - remove: Option>, -} - /// # Edit Role /// /// Edit a role by its id. #[openapi(tag = "Server Permissions")] #[patch("//roles/", data = "")] -pub async fn req( - db: &Db, +pub async fn edit( + db: &State, user: User, - target: Ref, + target: Reference, role_id: String, - data: Json, -) -> Result> { + data: Json, +) -> Result> { let data = data.into_inner(); - data.validate() - .map_err(|error| Error::FailedValidation { error })?; + data.validate().map_err(|error| { + create_error!(FailedValidation { + error: error.to_string() + }) + })?; let mut server = target.as_server(db).await?; - let mut permissions = perms(&user).server(&server); + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + calculate_server_permissions(&mut query) + .await + .throw_if_lacking_channel_permission(ChannelPermission::ManageRole); - permissions - .throw_permission(db, Permission::ManageRole) - .await?; - - let member_rank = permissions.get_member_rank().unwrap_or(i64::MIN); + let member_rank = query.get_member_rank().unwrap_or(i64::MIN); if let Some(mut role) = server.roles.remove(&role_id) { // Prevent us from editing roles above us if role.rank <= member_rank { - return Err(Error::NotElevated); + return Err(create_error!(NotElevated)); } - let DataEditRole { + let v0::DataEditRole { name, colour, hoist, @@ -74,7 +53,7 @@ pub async fn req( // Prevent us from moving a role above other roles if let Some(rank) = &rank { if rank <= &member_rank { - return Err(Error::NotElevated); + return Err(create_error!(NotElevated)); } } @@ -91,12 +70,14 @@ pub async fn req( &server.id, &role_id, partial, - remove.unwrap_or_default(), + remove + .map(|v| v.into_iter().map(Into::into).collect()) + .unwrap_or_default(), ) .await?; - Ok(Json(role)) + Ok(Json(role.into())) } else { - Err(Error::NotFound) + Err(create_error!(NotFound)) } } diff --git a/crates/delta/src/routes/servers/roles_fetch.rs b/crates/delta/src/routes/servers/roles_fetch.rs index 20ee0614..74b2aa1d 100644 --- a/crates/delta/src/routes/servers/roles_fetch.rs +++ b/crates/delta/src/routes/servers/roles_fetch.rs @@ -1,19 +1,24 @@ -use revolt_quark::{models::server::Role, Db, Error, Ref, Result}; -use rocket::serde::json::Json; +use revolt_database::{util::reference::Reference, Database}; +use revolt_models::v0; +use revolt_result::{create_error, Result}; +use rocket::{serde::json::Json, State}; /// # Fetch Role /// /// Fetch a role by its id. #[openapi(tag = "Server Permissions")] #[get("//roles/")] -pub async fn req(db: &Db, target: Ref, role_id: String) -> Result> { - let server = target.as_server(db).await?; - - let role = server.roles.get(&role_id); +pub async fn fetch( + db: &State, + target: Reference, + role_id: String, +) -> Result> { + let mut server = target.as_server(db).await?; + let role = server.roles.remove(&role_id); if let Some(role) = role { - Ok(Json(role.clone())) + Ok(Json(role.into())) } else { - Err(Error::NotFound) + Err(create_error!(NotFound)) } } diff --git a/crates/delta/src/routes/servers/server_ack.rs b/crates/delta/src/routes/servers/server_ack.rs index 2412bb6a..d70eefec 100644 --- a/crates/delta/src/routes/servers/server_ack.rs +++ b/crates/delta/src/routes/servers/server_ack.rs @@ -1,17 +1,27 @@ -use revolt_quark::{models::User, perms, Db, EmptyResponse, Error, Ref, Result}; +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, User, +}; +use revolt_permissions::PermissionQuery; +use revolt_result::{create_error, Result}; +use rocket::State; +use rocket_empty::EmptyResponse; /// # Mark Server As Read /// /// Mark all channels in a server as read. #[openapi(tag = "Server Information")] #[put("//ack")] -pub async fn req(db: &Db, user: User, target: Ref) -> Result { +pub async fn ack(db: &State, user: User, target: Reference) -> Result { if user.bot.is_some() { - return Err(Error::IsBot); + return Err(create_error!(IsBot)); } let server = target.as_server(db).await?; - perms(&user).server(&server).calc(db).await?; + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + if !query.are_we_a_member().await { + return Err(create_error!(NotFound)); + } db.acknowledge_channels(&user.id, &server.channels) .await diff --git a/crates/delta/src/routes/servers/server_delete.rs b/crates/delta/src/routes/servers/server_delete.rs index 919a9b0a..28a3bf42 100644 --- a/crates/delta/src/routes/servers/server_delete.rs +++ b/crates/delta/src/routes/servers/server_delete.rs @@ -1,27 +1,20 @@ -use revolt_quark::{ - models::{server_member::RemovalIntention, User}, - Db, EmptyResponse, Ref, Result, -}; -use serde::{Deserialize, Serialize}; -use validator::Validate; +use revolt_database::{util::reference::Reference, Database, RemovalIntention, User}; +use revolt_models::v0; +use revolt_result::Result; +use rocket::State; -/// # Query Parameters -#[derive(Validate, Serialize, Deserialize, JsonSchema, FromForm)] -pub struct OptionsServerDelete { - /// Whether to not send a leave message - leave_silently: Option, -} +use rocket_empty::EmptyResponse; /// # Delete / Leave Server /// /// Deletes a server if owner otherwise leaves. #[openapi(tag = "Server Information")] #[delete("/?")] -pub async fn req( - db: &Db, +pub async fn delete( + db: &State, user: User, - target: Ref, - options: OptionsServerDelete, + target: Reference, + options: v0::OptionsServerDelete, ) -> Result { let server = target.as_server(db).await?; let member = db.fetch_member(&target.id, &user.id).await?; @@ -29,10 +22,10 @@ pub async fn req( if server.owner == user.id { server.delete(db).await } else { - server - .remove_member( + member + .remove( db, - member, + &server, RemovalIntention::Leave, options.leave_silently.unwrap_or_default(), ) diff --git a/crates/delta/src/routes/servers/server_edit.rs b/crates/delta/src/routes/servers/server_edit.rs index b18cbc9f..6ef4f62b 100644 --- a/crates/delta/src/routes/servers/server_edit.rs +++ b/crates/delta/src/routes/servers/server_edit.rs @@ -1,74 +1,36 @@ use std::collections::HashSet; -use revolt_quark::{ - models::{ - server::{Category, FieldsServer, PartialServer, SystemMessageChannels}, - File, Server, User, - }, - perms, Db, Error, Permission, Ref, Result, +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, File, PartialServer, User, }; - -use rocket::serde::json::Json; -use serde::{Deserialize, Serialize}; +use revolt_models::v0; +use revolt_permissions::{calculate_server_permissions, ChannelPermission}; +use revolt_result::{create_error, Result}; +use rocket::{serde::json::Json, State}; use validator::Validate; -/// # Server Data -#[derive(Validate, Serialize, Deserialize, JsonSchema)] -pub struct DataEditServer { - /// Server name - #[validate(length(min = 1, max = 32))] - name: Option, - /// Server description - #[validate(length(min = 0, max = 1024))] - description: Option, - - /// Attachment Id for icon - icon: Option, - /// Attachment Id for banner - banner: Option, - - /// Category structure for server - #[validate] - categories: Option>, - /// System message configuration - system_messages: Option, - - /// Bitfield of server flags - #[serde(skip_serializing_if = "Option::is_none")] - pub flags: Option, - - // Whether this server is age-restricted - // nsfw: Option, - /// Whether this server is public and should show up on [Revolt Discover](https://rvlt.gg) - discoverable: Option, - /// Whether analytics should be collected for this server - /// - /// Must be enabled in order to show up on [Revolt Discover](https://rvlt.gg). - analytics: Option, - - /// Fields to remove from server object - #[validate(length(min = 1))] - remove: Option>, -} - /// # Edit Server /// /// Edit a server by its id. #[openapi(tag = "Server Information")] #[patch("/", data = "")] -pub async fn req( - db: &Db, +pub async fn edit( + db: &State, user: User, - target: Ref, - data: Json, -) -> Result> { + target: Reference, + data: Json, +) -> Result> { let data = data.into_inner(); - data.validate() - .map_err(|error| Error::FailedValidation { error })?; + data.validate().map_err(|error| { + create_error!(FailedValidation { + error: error.to_string() + }) + })?; let mut server = target.as_server(db).await?; - let mut permissions = perms(&user).server(&server); - permissions.calc(db).await?; + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + let permissions = calculate_server_permissions(&mut query).await; // Check permissions if data.name.is_none() @@ -83,7 +45,7 @@ pub async fn req( && data.discoverable.is_none() && data.remove.is_none() { - return Ok(Json(server)); + return Ok(Json(server.into())); } else if data.name.is_some() || data.description.is_some() || data.icon.is_some() @@ -92,26 +54,22 @@ pub async fn req( || data.analytics.is_some() || data.remove.is_some() { - permissions - .throw_permission(db, Permission::ManageServer) - .await?; + permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageServer)?; } // Check we are privileged if changing sensitive fields if (data.flags.is_some() /*|| data.nsfw.is_some()*/ || data.discoverable.is_some()) && !user.privileged { - return Err(Error::NotPrivileged); + return Err(create_error!(NotPrivileged)); } // Changing categories requires manage channel if data.categories.is_some() { - permissions - .throw_permission(db, Permission::ManageChannel) - .await?; + permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?; } - let DataEditServer { + let v0::DataEditServer { name, description, icon, @@ -128,8 +86,8 @@ pub async fn req( let mut partial = PartialServer { name, description, - categories, - system_messages, + categories: categories.map(|v| v.into_iter().map(Into::into).collect()), + system_messages: system_messages.map(Into::into), flags, // nsfw, discoverable, @@ -139,13 +97,13 @@ pub async fn req( // 1. Remove fields from object if let Some(fields) = &remove { - if fields.contains(&FieldsServer::Banner) { + if fields.contains(&v0::FieldsServer::Banner) { if let Some(banner) = &server.banner { db.mark_attachment_as_deleted(&banner.id).await?; } } - if fields.contains(&FieldsServer::Icon) { + if fields.contains(&v0::FieldsServer::Icon) { if let Some(icon) = &server.icon { db.mark_attachment_as_deleted(&icon.id).await?; } @@ -156,7 +114,7 @@ pub async fn req( if let Some(system_messages) = &partial.system_messages { for id in system_messages.clone().into_channel_ids() { if !server.channels.contains(&id) { - return Err(Error::NotFound); + return Err(create_error!(NotFound)); } } } @@ -166,7 +124,7 @@ pub async fn req( for category in categories { for channel in &category.channels { if channel_ids.contains(channel) { - return Err(Error::InvalidOperation); + return Err(create_error!(InvalidOperation)); } channel_ids.insert(channel.to_string()); @@ -191,8 +149,14 @@ pub async fn req( } server - .update(db, partial, remove.unwrap_or_default()) + .update( + db, + partial, + remove + .map(|v| v.into_iter().map(Into::into).collect()) + .unwrap_or_default(), + ) .await?; - Ok(Json(server)) + Ok(Json(server.into())) } diff --git a/crates/delta/src/routes/servers/server_fetch.rs b/crates/delta/src/routes/servers/server_fetch.rs index ded1b756..e668021c 100644 --- a/crates/delta/src/routes/servers/server_fetch.rs +++ b/crates/delta/src/routes/servers/server_fetch.rs @@ -1,65 +1,48 @@ -use revolt_quark::{ - models::{Channel, Server, User}, - perms, Db, Ref, Result, +use revolt_database::{ + util::{permissions::DatabasePermissionQuery, reference::Reference}, + Database, User, }; -use rocket::serde::json::Json; -use serde::{Deserialize, Serialize}; - -/// # Query Parameters -#[derive(Deserialize, JsonSchema, FromForm)] -pub struct OptionsFetchServer { - /// Whether to include channels - include_channels: Option, -} - -/// # Fetch server route response -#[derive(Serialize, JsonSchema)] -#[serde(untagged)] -pub enum FetchServerResponse { - JustServer(Server), - ServerWithChannels { - #[serde(flatten)] - server: Server, - channels: Vec, - }, -} +use revolt_models::v0; +use revolt_permissions::{calculate_channel_permissions, ChannelPermission, PermissionQuery}; +use revolt_result::{create_error, Result}; +use rocket::{serde::json::Json, State}; /// # Fetch Server /// /// Fetch a server by its id. #[openapi(tag = "Server Information")] #[get("/?")] -pub async fn req( - db: &Db, +pub async fn fetch( + db: &State, user: User, - target: Ref, - options: OptionsFetchServer, -) -> Result> { + target: Reference, + options: v0::OptionsFetchServer, +) -> Result> { let server = target.as_server(db).await?; - let mut perms = perms(&user).server(&server); - perms.calc(db).await?; + let mut query = DatabasePermissionQuery::new(db, &user).server(&server); + if !query.are_we_a_member().await { + return Err(create_error!(NotFound)); + } if let Some(true) = options.include_channels { let all_channels = db.fetch_channels(&server.channels).await?; - let mut visible_channels = vec![]; + let mut visible_channels: Vec = vec![]; for channel in all_channels { - if perms - .clone() - .channel(&channel) - .calc(db) - .await? - .can_view_channel() + let mut channel_query = query.clone().channel(&channel); + if calculate_channel_permissions(&mut channel_query) + .await + .has_channel_permission(ChannelPermission::ViewChannel) { - visible_channels.push(channel); + visible_channels.push(channel.into()); } } - Ok(Json(FetchServerResponse::ServerWithChannels { - server, + Ok(Json(v0::FetchServerResponse::ServerWithChannels { + server: server.into(), channels: visible_channels, })) } else { - Ok(Json(FetchServerResponse::JustServer(server))) + Ok(Json(v0::FetchServerResponse::JustServer(server.into()))) } }