refactor(quark): port invite_delete, invite_fetch, invite_join

This commit is contained in:
Paul Makles
2024-04-07 17:47:59 +01:00
parent 569bd1d5e1
commit f6a565385e
13 changed files with 428 additions and 113 deletions

View File

@@ -11,6 +11,8 @@ use rocket::{serde::json::Json, State};
/// # Fetch Group Members
///
/// Retrieves all users who are part of this group.
///
/// This may not return full user information if users are not friends but have mutual connections.
#[openapi(tag = "Groups")]
#[get("/<target>/members")]
pub async fn fetch_members(
@@ -30,7 +32,7 @@ pub async fn fetch_members(
db.fetch_users(&recipients)
.await?
.into_iter()
.map(|other_user| other_user.into(db, &user)),
.map(|other_user| other_user.into_known(&user)),
)
.await,
))

View File

@@ -1,14 +1,18 @@
use revolt_quark::{
models::{Invite, User},
perms, Db, EmptyResponse, Permission, Ref, Result,
use revolt_database::{
util::{permissions::DatabasePermissionQuery, reference::Reference},
Database, Invite, User,
};
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
use revolt_result::Result;
use rocket::State;
use rocket_empty::EmptyResponse;
/// # Delete Invite
///
/// Delete an invite by its id.
#[openapi(tag = "Invites")]
#[delete("/<target>")]
pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
pub async fn delete(db: &State<Database>, user: User, target: Reference) -> Result<EmptyResponse> {
let invite = target.as_invite(db).await?;
if user.id == invite.creator() {
@@ -17,10 +21,10 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
match invite {
Invite::Server { code, server, .. } => {
let server = db.fetch_server(&server).await?;
perms(&user)
.server(&server)
.throw_permission(db, Permission::ManageServer)
.await?;
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
calculate_server_permissions(&mut query)
.await
.throw_if_lacking_channel_permission(ChannelPermission::ManageServer)?;
db.delete_invite(&code).await
}

View File

@@ -1,71 +1,14 @@
use revolt_quark::models::{Channel, File, Invite};
use revolt_quark::{Db, Ref, Result};
use rocket::serde::json::Json;
use serde::Serialize;
/// # Invite
#[allow(clippy::large_enum_variant)]
#[derive(Serialize, Debug, Clone, JsonSchema)]
#[serde(tag = "type")]
pub enum InviteResponse {
/// Server channel invite
Server {
/// Invite code
code: String,
/// Id of the server
server_id: String,
/// Name of the server
server_name: String,
/// Attachment for server icon
#[serde(skip_serializing_if = "Option::is_none")]
server_icon: Option<File>,
/// Attachment for server banner
#[serde(skip_serializing_if = "Option::is_none")]
server_banner: Option<File>,
/// Enum of server flags
#[serde(skip_serializing_if = "Option::is_none")]
server_flags: Option<i32>,
/// Id of server channel
channel_id: String,
/// Name of server channel
channel_name: String,
/// Description of server channel
#[serde(skip_serializing_if = "Option::is_none")]
channel_description: Option<String>,
/// Name of user who created the invite
user_name: String,
/// Avatar of the user who created the invite
#[serde(skip_serializing_if = "Option::is_none")]
user_avatar: Option<File>,
/// Number of members in this server
member_count: i64,
},
/// Group channel invite
Group {
/// Invite code
code: String,
/// Id of group channel
channel_id: String,
/// Name of group channel
channel_name: String,
/// Description of group channel
#[serde(skip_serializing_if = "Option::is_none")]
channel_description: Option<String>,
/// Name of user who created the invite
user_name: String,
/// Avatar of the user who created the invite
#[serde(skip_serializing_if = "Option::is_none")]
user_avatar: Option<File>,
},
}
use revolt_database::{util::reference::Reference, Channel, Database, Invite};
use revolt_models::v0;
use revolt_result::Result;
use rocket::{serde::json::Json, State};
/// # Fetch Invite
///
/// Fetch an invite by its id.
#[openapi(tag = "Invites")]
#[get("/<target>")]
pub async fn req(db: &Db, target: Ref) -> Result<Json<InviteResponse>> {
pub async fn fetch(db: &State<Database>, target: Reference) -> Result<Json<v0::InviteResponse>> {
Ok(Json(match target.as_invite(db).await? {
Invite::Server {
channel, creator, ..
@@ -90,19 +33,19 @@ pub async fn req(db: &Db, target: Ref) -> Result<Json<InviteResponse>> {
} => {
let server = db.fetch_server(&server).await?;
InviteResponse::Server {
v0::InviteResponse::Server {
code: target.id,
member_count: db.fetch_member_count(&server.id).await? as i64,
server_id: server.id,
server_name: server.name,
server_icon: server.icon,
server_banner: server.banner,
server_icon: server.icon.map(|f| f.into()),
server_banner: server.banner.map(|f| f.into()),
server_flags: server.flags,
channel_id: id,
channel_name: name,
channel_description: description,
user_name: user.username,
user_avatar: user.avatar,
user_avatar: user.avatar.map(|f| f.into()),
}
}
_ => unreachable!(),
@@ -120,13 +63,13 @@ pub async fn req(db: &Db, target: Ref) -> Result<Json<InviteResponse>> {
name,
description,
..
} => InviteResponse::Group {
} => v0::InviteResponse::Group {
code: target.id,
channel_id: id,
channel_name: name,
channel_description: description,
user_name: user.username,
user_avatar: user.avatar,
user_avatar: user.avatar.map(|f| f.into()),
},
_ => unreachable!(),
}

View File

@@ -1,47 +1,54 @@
use revolt_quark::{
models::{Channel, Invite, Server, User},
variables::delta::MAX_SERVER_COUNT,
Db, Error, Ref, Result,
};
use rocket::serde::json::Json;
use serde::Serialize;
/// # Join Response
#[derive(Serialize, JsonSchema)]
#[serde(tag = "type")]
pub enum InviteJoinResponse {
Server {
/// Channels in the server
channels: Vec<Channel>,
/// Server we are joining
server: Server,
},
}
use futures::future::join_all;
use revolt_database::{util::reference::Reference, Channel, Database, Invite, Member, User};
use revolt_models::v0::{self, InviteJoinResponse};
use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State};
/// # Join Invite
///
/// Join an invite by its ID.
/// Join an invite by its ID
#[openapi(tag = "Invites")]
#[post("/<target>")]
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<InviteJoinResponse>> {
pub async fn join(
db: &State<Database>,
user: User,
target: Reference,
) -> Result<Json<v0::InviteJoinResponse>> {
if user.bot.is_some() {
return Err(Error::IsBot);
return Err(create_error!(IsBot));
}
if !user.can_acquire_server(db).await? {
return Err(Error::TooManyServers {
max: *MAX_SERVER_COUNT,
});
}
user.can_acquire_server(db).await?;
let invite = target.as_invite(db).await?;
match &invite {
Invite::Server { server, .. } => {
let server = db.fetch_server(server).await?;
let channels = server.create_member(db, user, None).await?;
Ok(Json(InviteJoinResponse::Server { channels, server }))
let channels = Member::create(db, &server, &user, None).await?;
Ok(Json(InviteJoinResponse::Server {
channels: channels.into_iter().map(|c| c.into()).collect(),
server: server.into(),
}))
}
Invite::Group {
channel, creator, ..
} => {
let mut channel = db.fetch_channel(channel).await?;
channel.add_user_to_group(db, &user, creator).await?;
if let Channel::Group { recipients, .. } = &channel {
Ok(Json(InviteJoinResponse::Group {
users: join_all(
db.fetch_users(&recipients)
.await?
.into_iter()
.map(|other_user| other_user.into_known(&user)),
)
.await,
channel: channel.into(),
}))
} else {
unreachable!()
}
}
_ => unreachable!(),
}
}

View File

@@ -6,5 +6,9 @@ mod invite_fetch;
mod invite_join;
pub fn routes() -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![invite_fetch::req, invite_join::req, invite_delete::req]
openapi_get_routes_spec![
invite_fetch::fetch,
invite_join::join,
invite_delete::delete
]
}