From 89213f62f69409c2ae689366eb77f97c6a1834e7 Mon Sep 17 00:00:00 2001 From: ToastXC <100072983+toastxc@users.noreply.github.com> Date: Wed, 27 Dec 2023 16:50:14 +0800 Subject: [PATCH] uploaded changes --- .../delta/src/routes/servers/member_fetch.rs | 24 ++++++--- crates/delta/src/routes/servers/mod.rs | 2 + .../delta/src/routes/servers/roles_fetch.rs | 19 +++++++ .../src/impl/dummy/servers/server_member.rs | 7 ++- .../src/impl/generic/servers/server_member.rs | 31 +++++++++++- .../src/impl/mongo/servers/server_member.rs | 13 +++-- .../quark/src/models/servers/server_member.rs | 49 +++++++++++++++++++ .../quark/src/traits/servers/server_member.rs | 6 ++- crates/quark/src/util/ref.rs | 13 +++-- 9 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 crates/delta/src/routes/servers/roles_fetch.rs diff --git a/crates/delta/src/routes/servers/member_fetch.rs b/crates/delta/src/routes/servers/member_fetch.rs index 47b254f0c..2017ec48c 100644 --- a/crates/delta/src/routes/servers/member_fetch.rs +++ b/crates/delta/src/routes/servers/member_fetch.rs @@ -1,17 +1,25 @@ -use revolt_quark::{ - models::{Member, User}, - perms, Db, Ref, Result, -}; +use revolt_quark::models::server_member::MemberResponse; +use revolt_quark::{models::User, perms, Db, Ref, Result}; use rocket::serde::json::Json; - /// # Fetch Member /// /// Retrieve a member. #[openapi(tag = "Server Members")] -#[get("//members/")] -pub async fn req(db: &Db, user: User, target: Ref, member: Ref) -> Result> { +#[get("//members/?")] +pub async fn req( + db: &Db, + user: User, + target: Ref, + member: Ref, + roles: Option, +) -> Result> { let server = target.as_server(db).await?; perms(&user).server(&server).calc(db).await?; - member.as_member(db, &server.id).await.map(Json) + let member_response: MemberResponse = match roles { + Some(true) => member.as_member_with_roles(db, &server.id).await?.into(), + _ => member.as_member(db, &server.id).await?.into(), + }; + + Ok(Json(member_response)) } diff --git a/crates/delta/src/routes/servers/mod.rs b/crates/delta/src/routes/servers/mod.rs index 9e0eed6de..636da3d0d 100644 --- a/crates/delta/src/routes/servers/mod.rs +++ b/crates/delta/src/routes/servers/mod.rs @@ -17,6 +17,7 @@ mod permissions_set_default; mod roles_create; mod roles_delete; mod roles_edit; +mod roles_fetch; mod server_ack; mod server_create; mod server_delete; @@ -42,6 +43,7 @@ pub fn routes() -> (Vec, OpenApi) { invites_fetch::req, roles_create::req, roles_edit::req, + roles_fetch::req, roles_delete::req, permissions_set::req, permissions_set_default::req, diff --git a/crates/delta/src/routes/servers/roles_fetch.rs b/crates/delta/src/routes/servers/roles_fetch.rs new file mode 100644 index 000000000..20ee0614b --- /dev/null +++ b/crates/delta/src/routes/servers/roles_fetch.rs @@ -0,0 +1,19 @@ +use revolt_quark::{models::server::Role, Db, Error, Ref, Result}; +use rocket::serde::json::Json; + +/// # 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); + + if let Some(role) = role { + Ok(Json(role.clone())) + } else { + Err(Error::NotFound) + } +} diff --git a/crates/quark/src/impl/dummy/servers/server_member.rs b/crates/quark/src/impl/dummy/servers/server_member.rs index 87aaf0332..535e2fb6f 100644 --- a/crates/quark/src/impl/dummy/servers/server_member.rs +++ b/crates/quark/src/impl/dummy/servers/server_member.rs @@ -1,4 +1,6 @@ -use crate::models::server_member::{FieldsMember, Member, MemberCompositeKey, PartialMember}; +use crate::models::server_member::{ + FieldsMember, Member, MemberCompositeKey, MemberWithRoles, PartialMember, +}; use crate::{AbstractServerMember, Result}; use super::super::DummyDb; @@ -8,6 +10,9 @@ impl AbstractServerMember for DummyDb { async fn fetch_member(&self, server: &str, user: &str) -> Result { Ok(Member::new(server.into(), user.into())) } + async fn fetch_member_with_roles(&self, server: &str, user: &str) -> Result { + Ok(MemberWithRoles::new(server.into(), user.into())) + } async fn insert_member(&self, member: &Member) -> Result<()> { info!("Create {member:?}"); diff --git a/crates/quark/src/impl/generic/servers/server_member.rs b/crates/quark/src/impl/generic/servers/server_member.rs index 217fbd040..464ca5d69 100644 --- a/crates/quark/src/impl/generic/servers/server_member.rs +++ b/crates/quark/src/impl/generic/servers/server_member.rs @@ -1,9 +1,12 @@ +use std::collections::HashMap; + use iso8601_timestamp::Timestamp; use crate::{ events::client::EventV1, models::{ - server_member::{FieldsMember, MemberCompositeKey, PartialMember}, + server::Role, + server_member::{FieldsMember, MemberCompositeKey, MemberWithRoles, PartialMember}, Member, Server, }, Database, Result, @@ -81,4 +84,30 @@ impl Member { FieldsMember::Timeout => self.timeout = None, } } + + pub fn with_roles(&self, roles: HashMap) -> MemberWithRoles { + MemberWithRoles { + id: self.id.clone(), + joined_at: self.joined_at, + nickname: self.nickname.clone(), + avatar: self.avatar.clone(), + roles, + timeout: self.timeout, + } + } +} +impl MemberWithRoles { + pub fn new(server_id: String, user_id: String) -> Self { + Self { + id: MemberCompositeKey { + server: server_id, + user: user_id, + }, + joined_at: Timestamp::now_utc(), + nickname: None, + avatar: None, + roles: HashMap::new(), + timeout: None, + } + } } diff --git a/crates/quark/src/impl/mongo/servers/server_member.rs b/crates/quark/src/impl/mongo/servers/server_member.rs index 500f36a24..d4fcd7e24 100644 --- a/crates/quark/src/impl/mongo/servers/server_member.rs +++ b/crates/quark/src/impl/mongo/servers/server_member.rs @@ -1,10 +1,10 @@ use bson::Document; +use super::super::MongoDb; +use crate::models::server_member::MemberWithRoles; use crate::models::server_member::{FieldsMember, Member, MemberCompositeKey, PartialMember}; use crate::r#impl::mongo::IntoDocumentPath; -use crate::{AbstractServerMember, Error, Result}; - -use super::super::MongoDb; +use crate::{AbstractServer, AbstractServerMember, Error, Result}; static COL: &str = "server_members"; @@ -21,6 +21,13 @@ impl AbstractServerMember for MongoDb { .await } + async fn fetch_member_with_roles(&self, server: &str, user: &str) -> Result { + Ok(self + .fetch_member(server, user) + .await? + .with_roles(self.fetch_server(server).await?.roles)) + } + async fn insert_member(&self, member: &Member) -> Result<()> { self.insert_one(COL, member).await.map(|_| ()) } diff --git a/crates/quark/src/models/servers/server_member.rs b/crates/quark/src/models/servers/server_member.rs index 23b802f3d..0d340d5f3 100644 --- a/crates/quark/src/models/servers/server_member.rs +++ b/crates/quark/src/models/servers/server_member.rs @@ -1,8 +1,13 @@ +use std::collections::HashMap; + use iso8601_timestamp::Timestamp; + use serde::{Deserialize, Serialize}; use crate::models::attachment::File; +use super::server::Role; + /// Composite primary key consisting of server and user id #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, Default)] pub struct MemberCompositeKey { @@ -41,6 +46,50 @@ pub struct Member { pub timeout: Option, } +/// Representation of a member of a server on Revolt With Role Data +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, OptionalStruct)] +#[optional_derive(Serialize, Deserialize, JsonSchema, Debug, Default, Clone)] +#[opt_skip_serializing_none] +#[opt_some_priority] +pub struct MemberWithRoles { + /// Unique member id + #[serde(rename = "_id")] + pub id: MemberCompositeKey, + + /// Time at which this user joined the server + pub joined_at: Timestamp, + + /// Member's nickname + #[serde(skip_serializing_if = "Option::is_none")] + pub nickname: Option, + /// Avatar attachment + #[serde(skip_serializing_if = "Option::is_none")] + pub avatar: Option, + + /// Member's roles + #[serde(skip_serializing_if = "HashMap::is_empty", default)] + pub roles: HashMap, + /// Timestamp this member is timed out until + #[serde(skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] +pub enum MemberResponse { + Members(Member), + MembersWithRoles(MemberWithRoles), +} + +impl From for MemberResponse { + fn from(value: Member) -> Self { + Self::Members(value) + } +} +impl From for MemberResponse { + fn from(value: MemberWithRoles) -> Self { + Self::MembersWithRoles(value) + } +} /// Optional fields on server member object #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)] pub enum FieldsMember { diff --git a/crates/quark/src/traits/servers/server_member.rs b/crates/quark/src/traits/servers/server_member.rs index caf57036e..419663a1c 100644 --- a/crates/quark/src/traits/servers/server_member.rs +++ b/crates/quark/src/traits/servers/server_member.rs @@ -1,4 +1,6 @@ -use crate::models::server_member::{FieldsMember, Member, MemberCompositeKey, PartialMember}; +use crate::models::server_member::{ + FieldsMember, Member, MemberCompositeKey, MemberWithRoles, PartialMember, +}; use crate::Result; #[async_trait] @@ -6,6 +8,8 @@ pub trait AbstractServerMember: Sync + Send { /// Fetch a server member by their id async fn fetch_member(&self, server: &str, user: &str) -> Result; + async fn fetch_member_with_roles(&self, server: &str, user: &str) -> Result; + /// Insert a new server member into the database async fn insert_member(&self, member: &Member) -> Result<()>; diff --git a/crates/quark/src/util/ref.rs b/crates/quark/src/util/ref.rs index 110ad501f..775374663 100644 --- a/crates/quark/src/util/ref.rs +++ b/crates/quark/src/util/ref.rs @@ -5,9 +5,8 @@ use schemars::schema::{InstanceType, Schema, SchemaObject, SingleOrVec}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::models::{ - Channel, Emoji, Invite, Member, Message, Report, Server, ServerBan, User, -}; +use crate::models::server_member::MemberWithRoles; +use crate::models::{Channel, Emoji, Invite, Member, Message, Report, Server, ServerBan, User}; use crate::{Database, Error, Result}; /// Reference to some object in the database @@ -66,6 +65,14 @@ impl Ref { db.fetch_member(server, &self.id).await } + pub async fn as_member_with_roles( + &self, + db: &Database, + server: &str, + ) -> Result { + db.fetch_member_with_roles(server, &self.id).await + } + /// Fetch ban from Ref pub async fn as_ban(&self, db: &Database, server: &str) -> Result { db.fetch_ban(server, &self.id).await