chore: update routes to use utoipa

This commit is contained in:
Zomatree
2025-11-17 22:13:07 +00:00
parent ac60b2c795
commit 43c94b68b0
110 changed files with 891 additions and 231 deletions

View File

@@ -15,7 +15,7 @@ use crate::{CoalescionServiceConfig, Error};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
/// # Coalescion service /// Coalescion service
/// ///
/// See module description for example usage. /// See module description for example usage.
pub struct CoalescionService<Id: Hash + Clone + Eq> { pub struct CoalescionService<Id: Hash + Clone + Eq> {

View File

@@ -25,6 +25,10 @@ pub use mongodb;
#[macro_use] #[macro_use]
extern crate bson; extern crate bson;
#[cfg(feature = "utoipa")]
#[macro_use]
extern crate utoipa;
#[cfg(not(feature = "async-std-runtime"))] #[cfg(not(feature = "async-std-runtime"))]
compile_error!("async-std-runtime feature must be enabled."); compile_error!("async-std-runtime feature must be enabled.");

View File

@@ -15,7 +15,7 @@ use serde_json::json;
use ulid::Ulid; use ulid::Ulid;
auto_derived_partial!( auto_derived_partial!(
/// # User /// User
pub struct User { pub struct User {
/// Unique Id /// Unique Id
#[serde(rename = "_id")] #[serde(rename = "_id")]

View File

@@ -10,16 +10,16 @@ use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct IdempotencyKey { #[cfg_attr(feature = "utoipa", derive(IntoParams))]
key: String, #[cfg_attr(feature = "utoipa", into_params(names("Idempotency-Key"), parameter_in=Header))]
} pub struct IdempotencyKey(String);
static TOKEN_CACHE: Lazy<Mutex<lru::LruCache<String, ()>>> = static TOKEN_CACHE: Lazy<Mutex<lru::LruCache<String, ()>>> =
Lazy::new(|| Mutex::new(lru::LruCache::new(NonZeroUsize::new(1000).unwrap()))); Lazy::new(|| Mutex::new(lru::LruCache::new(NonZeroUsize::new(1000).unwrap())));
impl IdempotencyKey { impl IdempotencyKey {
pub fn unchecked_from_string(key: String) -> Self { pub fn unchecked_from_string(key: String) -> Self {
Self { key } Self(key)
} }
// Backwards compatibility. // Backwards compatibility.
@@ -32,14 +32,14 @@ impl IdempotencyKey {
} }
cache.put(v.clone(), ()); cache.put(v.clone(), ());
self.key = v; self.0 = v;
} }
Ok(()) Ok(())
} }
pub fn into_key(self) -> String { pub fn into_key(self) -> String {
self.key self.0
} }
} }
@@ -110,18 +110,16 @@ impl<'r> FromRequest<'r> for IdempotencyKey {
)); ));
} }
let idempotency = IdempotencyKey { key }; let idempotency = IdempotencyKey(key);
let mut cache = TOKEN_CACHE.lock().await; let mut cache = TOKEN_CACHE.lock().await;
if cache.get(&idempotency.key).is_some() { if cache.get(&idempotency.0).is_some() {
return Outcome::Error((Status::Conflict, create_error!(DuplicateNonce))); return Outcome::Error((Status::Conflict, create_error!(DuplicateNonce)));
} }
cache.put(idempotency.key.clone(), ()); cache.put(idempotency.0.clone(), ());
return Outcome::Success(idempotency); return Outcome::Success(idempotency);
} }
Outcome::Success(IdempotencyKey { Outcome::Success(IdempotencyKey(ulid::Ulid::new().to_string()))
key: ulid::Ulid::new().to_string(),
})
} }
} }

View File

@@ -283,6 +283,7 @@ auto_derived!(
/// Options when deleting a channel /// Options when deleting a channel
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsChannelDelete { pub struct OptionsChannelDelete {
/// Whether to not send a leave message /// Whether to not send a leave message
pub leave_silently: Option<bool>, pub leave_silently: Option<bool>,

View File

@@ -1,5 +1,5 @@
auto_derived!( auto_derived!(
/// # hCaptcha Configuration /// hCaptcha Configuration
pub struct CaptchaFeature { pub struct CaptchaFeature {
/// Whether captcha is enabled /// Whether captcha is enabled
pub enabled: bool, pub enabled: bool,
@@ -7,7 +7,7 @@ auto_derived!(
pub key: String, pub key: String,
} }
/// # Generic Service Configuration /// Generic Service Configuration
pub struct Feature { pub struct Feature {
/// Whether the service is enabled /// Whether the service is enabled
pub enabled: bool, pub enabled: bool,
@@ -15,7 +15,7 @@ auto_derived!(
pub url: String, pub url: String,
} }
/// # Voice Server Configuration /// Voice Server Configuration
pub struct VoiceFeature { pub struct VoiceFeature {
/// Whether voice is enabled /// Whether voice is enabled
pub enabled: bool, pub enabled: bool,
@@ -25,7 +25,7 @@ auto_derived!(
pub ws: String, pub ws: String,
} }
/// # Feature Configuration /// Feature Configuration
pub struct RevoltFeatures { pub struct RevoltFeatures {
/// hCaptcha configuration /// hCaptcha configuration
pub captcha: CaptchaFeature, pub captcha: CaptchaFeature,
@@ -41,7 +41,7 @@ auto_derived!(
pub voso: VoiceFeature, pub voso: VoiceFeature,
} }
/// # Build Information /// Build Information
pub struct BuildInformation { pub struct BuildInformation {
/// Commit Hash /// Commit Hash
pub commit_sha: String, pub commit_sha: String,
@@ -55,7 +55,7 @@ auto_derived!(
pub timestamp: String, pub timestamp: String,
} }
/// # Server Configuration /// Server Configuration
pub struct RevoltConfig { pub struct RevoltConfig {
/// Revolt API Version /// Revolt API Version
pub revolt: String, pub revolt: String,

View File

@@ -279,6 +279,7 @@ auto_derived!(
/// Options for querying messages /// Options for querying messages
#[cfg_attr(feature = "validator", derive(Validate))] #[cfg_attr(feature = "validator", derive(Validate))]
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsQueryMessages { pub struct OptionsQueryMessages {
/// Maximum number of messages to fetch /// Maximum number of messages to fetch
/// ///
@@ -357,6 +358,7 @@ auto_derived!(
/// Options for removing reaction /// Options for removing reaction
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsUnreact { pub struct OptionsUnreact {
/// Remove a specific user's reaction /// Remove a specific user's reaction
pub user_id: Option<String>, pub user_id: Option<String>,

View File

@@ -99,6 +99,7 @@ auto_derived!(
/// Options for fetching all members /// Options for fetching all members
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsFetchAllMembers { pub struct OptionsFetchAllMembers {
/// Whether to exclude offline users /// Whether to exclude offline users
pub exclude_offline: Option<bool>, pub exclude_offline: Option<bool>,

View File

@@ -198,6 +198,7 @@ auto_derived!(
/// Options when fetching server /// Options when fetching server
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsFetchServer { pub struct OptionsFetchServer {
/// Whether to include channels /// Whether to include channels
pub include_channels: Option<bool>, pub include_channels: Option<bool>,
@@ -284,6 +285,7 @@ auto_derived!(
/// Options when leaving a server /// Options when leaving a server
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsServerDelete { pub struct OptionsServerDelete {
/// Whether to not send a leave message /// Whether to not send a leave message
pub leave_silently: Option<bool>, pub leave_silently: Option<bool>,

View File

@@ -17,6 +17,7 @@ auto_derived!(
/// Additional options for inserting settings /// Additional options for inserting settings
#[cfg_attr(feature = "rocket", derive(FromForm))] #[cfg_attr(feature = "rocket", derive(FromForm))]
#[cfg_attr(feature = "utoipa", derive(IntoParams))]
pub struct OptionsSetSettings { pub struct OptionsSetSettings {
/// Timestamp of settings change. /// Timestamp of settings change.
/// ///

View File

@@ -5,8 +5,9 @@ use std::fmt::Display;
extern crate serde; extern crate serde;
#[cfg(feature = "utoipa")] #[cfg(feature = "utoipa")]
#[macro_use] mod utoipa_impl;
extern crate utoipa; #[cfg(feature = "utoipa")]
pub use crate::utoipa_impl::*;
#[cfg(feature = "rocket")] #[cfg(feature = "rocket")]
pub mod rocket; pub mod rocket;
@@ -19,7 +20,7 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
/// Error information /// Error information
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "utoipa", derive(ToSchema))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Error { pub struct Error {
/// Type of error and additional information /// Type of error and additional information
@@ -41,7 +42,7 @@ impl std::error::Error for Error {}
/// Possible error types /// Possible error types
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type"))] #[cfg_attr(feature = "serde", serde(tag = "type"))]
#[cfg_attr(feature = "utoipa", derive(ToSchema))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ErrorType { pub enum ErrorType {
/// This error was not labeled :( /// This error was not labeled :(

View File

@@ -0,0 +1,52 @@
use utoipa::{Modify, openapi::{Content, OpenApi, Ref, RefOr, ResponseBuilder}};
pub struct ErrorAddon;
impl Modify for ErrorAddon {
fn modify(&self, utoipa: &mut OpenApi) {
let response = ResponseBuilder::new()
.description("An error occurred")
.content(
"application/json",
Content::new(Some(RefOr::Ref(Ref::from_schema_name("Error")))),
)
.build();
for path in utoipa.paths.paths.values_mut() {
if let Some(route) = path.get.as_mut() {
route
.responses
.responses
.insert("default".to_string(), RefOr::T(response.clone()));
};
if let Some(route) = path.delete.as_mut() {
route
.responses
.responses
.insert("default".to_string(), RefOr::T(response.clone()));
};
if let Some(route) = path.patch.as_mut() {
route
.responses
.responses
.insert("default".to_string(), RefOr::T(response.clone()));
};
if let Some(route) = path.post.as_mut() {
route
.responses
.responses
.insert("default".to_string(), RefOr::T(response.clone()));
};
if let Some(route) = path.put.as_mut() {
route
.responses
.responses
.insert("default".to_string(), RefOr::T(response.clone()));
};
}
}
}

View File

@@ -5,10 +5,16 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Create Bot /// Create Bot
/// ///
/// Create a new Revolt bot. /// Create a new Revolt bot.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::BotWithUserResponse),
),
)]
#[post("/create", data = "<info>")] #[post("/create", data = "<info>")]
pub async fn create_bot( pub async fn create_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,10 +3,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete Bot /// Delete Bot
/// ///
/// Delete a bot by its id. /// Delete a bot by its id.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>")] #[delete("/<target>")]
pub async fn delete_bot( pub async fn delete_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -6,10 +6,16 @@ use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use validator::Validate; use validator::Validate;
/// # Edit Bot /// Edit Bot
/// ///
/// Edit bot details by its id. /// Edit bot details by its id.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::BotWithUserResponse),
),
)]
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn edit_bot( pub async fn edit_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,10 +3,16 @@ use revolt_models::v0::FetchBotResponse;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Bot /// Fetch Bot
/// ///
/// Fetch details of a bot you own by its id. /// Fetch details of a bot you own by its id.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 200, body = FetchBotResponse),
),
)]
#[get("/<bot>")] #[get("/<bot>")]
pub async fn fetch_bot( pub async fn fetch_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Owned Bots /// Fetch Owned Bots
/// ///
/// Fetch all of the bots that you have control over. /// Fetch all of the bots that you have control over.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 200, body = OwnedBotsResponse),
),
)]
#[get("/@me")] #[get("/@me")]
pub async fn fetch_owned_bots(db: &State<Database>, user: User) -> Result<Json<OwnedBotsResponse>> { pub async fn fetch_owned_bots(db: &State<Database>, user: User) -> Result<Json<OwnedBotsResponse>> {
let mut bots = db.fetch_bots_by_user(&user.id).await?; let mut bots = db.fetch_bots_by_user(&user.id).await?;

View File

@@ -5,10 +5,16 @@ use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Public Bot /// Fetch Public Bot
/// ///
/// Fetch details of a public (or owned) bot by its id. /// Fetch details of a public (or owned) bot by its id.
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = []), ()),
responses(
(status = 200, body = PublicBot),
),
)]
#[get("/<target>/invite")] #[get("/<target>/invite")]
pub async fn fetch_public_bot( pub async fn fetch_public_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -11,10 +11,16 @@ use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Invite Bot /// Invite Bot
/// ///
/// Invite a bot to a server or group by its id.` /// Invite a bot to a server or group by its id.`
#[utoipa::path(tag = "Bots")] #[utoipa::path(
tag = "Bots",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::BotWithUserResponse),
),
)]
#[post("/<target>/invite", data = "<dest>")] #[post("/<target>/invite", data = "<dest>")]
pub async fn invite_bot( pub async fn invite_bot(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Acknowledge Message /// Acknowledge Message
/// ///
/// Lets the server and all other clients know that we've seen this message id in this channel. /// Lets the server and all other clients know that we've seen this message id in this channel.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = [])),
responses(
(status = 204)
)
)]
#[put("/<target>/ack/<message>")] #[put("/<target>/ack/<message>")]
pub async fn ack( pub async fn ack(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,17 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Close Channel /// Close Channel
/// ///
/// Deletes a server channel, leaves a group or closes a group. /// Deletes a server channel, leaves a group or closes a group.
#[utoipa::path(tag = "Channel Information")] #[utoipa::path(
tag = "Channel Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsChannelDelete),
responses(
(status = 204),
),
)]
#[delete("/<target>?<options..>")] #[delete("/<target>?<options..>")]
pub async fn delete( pub async fn delete(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Edit Channel /// Edit Channel
/// ///
/// Edit a channel object by its id. /// Edit a channel object by its id.
#[utoipa::path(tag = "Channel Information")] #[utoipa::path(
tag = "Channel Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Channel /// Fetch Channel
/// ///
/// Fetch channel by its id. /// Fetch channel by its id.
#[utoipa::path(tag = "Channel Information")] #[utoipa::path(
tag = "Channel Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[get("/<target>")] #[get("/<target>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Add Member to Group /// Add Member to Group
/// ///
/// Adds another user to the group. /// Adds another user to the group.
#[utoipa::path(tag = "Groups")] #[utoipa::path(
tag = "Groups",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[put("/<group_id>/recipients/<member_id>")] #[put("/<group_id>/recipients/<member_id>")]
pub async fn add_member( pub async fn add_member(
db: &State<Database>, db: &State<Database>,

View File

@@ -6,10 +6,16 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Create Group /// Create Group
/// ///
/// Create a new group channel. /// Create a new group channel.
#[utoipa::path(tag = "Groups")] #[utoipa::path(
tag = "Groups",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[post("/create", data = "<data>")] #[post("/create", data = "<data>")]
pub async fn create_group( pub async fn create_group(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Remove Member from Group /// Remove Member from Group
/// ///
/// Removes a user from the group. /// Removes a user from the group.
#[utoipa::path(tag = "Groups")] #[utoipa::path(
tag = "Groups",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/recipients/<member>")] #[delete("/<target>/recipients/<member>")]
pub async fn remove_member( pub async fn remove_member(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,12 +8,18 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Create Invite /// Create Invite
/// ///
/// Creates an invite to this channel. /// Creates an invite to this channel.
/// ///
/// Channel must be a `TextChannel`. /// Channel must be a `TextChannel`.
#[utoipa::path(tag = "Channel Invites")] #[utoipa::path(
tag = "Channel Invites",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::Invite),
),
)]
#[post("/<target>/invites")] #[post("/<target>/invites")]
pub async fn create_invite( pub async fn create_invite(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,12 +7,18 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Group Members /// Fetch Group Members
/// ///
/// Retrieves all users who are part of this group. /// 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. /// This may not return full user information if users are not friends but have mutual connections.
#[utoipa::path(tag = "Groups")] #[utoipa::path(
tag = "Groups",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = Vec<v0::User>),
),
)]
#[get("/<target>/members")] #[get("/<target>/members")]
pub async fn fetch_members( pub async fn fetch_members(
db: &State<Database>, db: &State<Database>,

View File

@@ -10,14 +10,20 @@ use rocket::{serde::json::Json, State};
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
use validator::Validate; use validator::Validate;
/// # Bulk Delete Messages /// Bulk Delete Messages
/// ///
/// Delete multiple messages you've sent or one you have permission to delete. /// Delete multiple messages you've sent or one you have permission to delete.
/// ///
/// This will always require `ManageMessages` permission regardless of whether you own the message or not. /// This will always require `ManageMessages` permission regardless of whether you own the message or not.
/// ///
/// Messages must have been sent within the past 1 week. /// Messages must have been sent within the past 1 week.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/messages/bulk", data = "<options>", rank = 1)] #[delete("/<target>/messages/bulk", data = "<options>", rank = 1)]
pub async fn bulk_delete_messages( pub async fn bulk_delete_messages(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,12 +7,18 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Remove All Reactions from Message /// Remove All Reactions from Message
/// ///
/// Remove your own, someone else's or all of a given reaction. /// Remove your own, someone else's or all of a given reaction.
/// ///
/// Requires `ManageMessages` permission. /// Requires `ManageMessages` permission.
#[utoipa::path(tag = "Interactions")] #[utoipa::path(
tag = "Interactions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/messages/<msg>/reactions")] #[delete("/<target>/messages/<msg>/reactions")]
pub async fn clear_reactions( pub async fn clear_reactions(
db: &State<Database>, db: &State<Database>,
@@ -37,7 +43,7 @@ pub async fn clear_reactions(
reactions: Some(Default::default()), reactions: Some(Default::default()),
..Default::default() ..Default::default()
}, },
vec![] vec![],
) )
.await .await
.map(|_| EmptyResponse) .map(|_| EmptyResponse)

View File

@@ -7,10 +7,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete Message /// Delete Message
/// ///
/// Delete a message you've sent or one you have permission to delete. /// Delete a message you've sent or one you have permission to delete.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/messages/<msg>", rank = 2)] #[delete("/<target>/messages/<msg>", rank = 2)]
pub async fn delete( pub async fn delete(
db: &State<Database>, db: &State<Database>,

View File

@@ -10,10 +10,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Edit Message /// Edit Message
/// ///
/// Edits a message that you've previously sent. /// Edits a message that you've previously sent.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Message),
),
)]
#[patch("/<target>/messages/<msg>", data = "<edit>")] #[patch("/<target>/messages/<msg>", data = "<edit>")]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Message /// Fetch Message
/// ///
/// Retrieves a message by its id. /// Retrieves a message by its id.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Message),
),
)]
#[get("/<target>/messages/<msg>")] #[get("/<target>/messages/<msg>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Pins a message /// Pins a message
/// ///
/// Pins a message by its id. /// Pins a message by its id.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[post("/<target>/messages/<msg>/pin")] #[post("/<target>/messages/<msg>/pin")]
pub async fn message_pin( pub async fn message_pin(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,17 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Fetch Messages /// Fetch Messages
/// ///
/// Fetch multiple messages. /// Fetch multiple messages.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsQueryMessages),
responses(
(status = 200, body = v0::BulkMessageResponse),
),
)]
#[get("/<target>/messages?<options..>")] #[get("/<target>/messages?<options..>")]
pub async fn query( pub async fn query(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Add Reaction to Message /// Add Reaction to Message
/// ///
/// React to a given message. /// React to a given message.
#[utoipa::path(tag = "Interactions")] #[utoipa::path(
tag = "Interactions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[put("/<target>/messages/<msg>/reactions/<emoji>")] #[put("/<target>/messages/<msg>/reactions/<emoji>")]
pub async fn react_message( pub async fn react_message(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Search for Messages /// Search for Messages
/// ///
/// This route searches for messages within the given parameters. /// This route searches for messages within the given parameters.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::BulkMessageResponse),
),
)]
#[post("/<target>/search", data = "<options>")] #[post("/<target>/search", data = "<options>")]
pub async fn search( pub async fn search(
db: &State<Database>, db: &State<Database>,
@@ -31,7 +37,7 @@ pub async fn search(
})?; })?;
if options.query.is_some() && options.pinned.is_some() { if options.query.is_some() && options.pinned.is_some() {
return Err(create_error!(InvalidOperation)) return Err(create_error!(InvalidOperation));
} }
let channel = target.as_channel(db).await?; let channel = target.as_channel(db).await?;

View File

@@ -12,10 +12,17 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Send Message /// Send Message
/// ///
/// Sends a message to the given channel. /// Sends a message to the given channel.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(IdempotencyKey),
responses(
(status = 200, body = v0::Message),
),
)]
#[post("/<target>/messages", data = "<data>")] #[post("/<target>/messages", data = "<data>")]
pub async fn message_send( pub async fn message_send(
db: &State<Database>, db: &State<Database>,

View File

@@ -1,14 +1,23 @@
use revolt_database::{util::{permissions::DatabasePermissionQuery, reference::Reference}, Channel, Database, FieldsMessage, PartialMessage, SystemMessage, User, AMQP}; use revolt_database::{
util::{permissions::DatabasePermissionQuery, reference::Reference},
Channel, Database, FieldsMessage, PartialMessage, SystemMessage, User, AMQP,
};
use revolt_models::v0::MessageAuthor; use revolt_models::v0::MessageAuthor;
use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Unpins a message /// Unpins a message
/// ///
/// Unpins a message by its id. /// Unpins a message by its id.
#[utoipa::path(tag = "Messaging")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/messages/<msg>/pin")] #[delete("/<target>/messages/<msg>/pin")]
pub async fn message_unpin( pub async fn message_unpin(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,12 +8,19 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Remove Reaction(s) to Message /// Remove Reaction(s) to Message
/// ///
/// Remove your own, someone else's or all of a given reaction. /// Remove your own, someone else's or all of a given reaction.
/// ///
/// Requires `ManageMessages` if changing others' reactions. /// Requires `ManageMessages` if changing others' reactions.
#[utoipa::path(tag = "Interactions")] #[utoipa::path(
tag = "Interactions",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsUnreact),
responses(
(status = 204),
),
)]
#[delete("/<target>/messages/<msg>/reactions/<emoji>?<options..>")] #[delete("/<target>/messages/<msg>/reactions/<emoji>?<options..>")]
pub async fn unreact_message( pub async fn unreact_message(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,12 +7,18 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission, Overr
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Set Role Permission /// Set Role Permission
/// ///
/// Sets permissions for the specified role in this channel. /// Sets permissions for the specified role in this channel.
/// ///
/// Channel must be a `TextChannel` or `VoiceChannel`. /// Channel must be a `TextChannel` or `VoiceChannel`.
#[utoipa::path(tag = "Channel Permissions")] #[utoipa::path(
tag = "Channel Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)] #[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
pub async fn set_role_permissions( pub async fn set_role_permissions(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,12 +7,18 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Set Default Permission /// Set Default Permission
/// ///
/// Sets permissions for the default role in this channel. /// Sets permissions for the default role in this channel.
/// ///
/// Channel must be a `Group`, `TextChannel` or `VoiceChannel`. /// Channel must be a `Group`, `TextChannel` or `VoiceChannel`.
#[utoipa::path(tag = "Channel Permissions")] #[utoipa::path(
tag = "Channel Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[put("/<target>/permissions/default", data = "<data>", rank = 1)] #[put("/<target>/permissions/default", data = "<data>", rank = 1)]
pub async fn set_default_channel_permissions( pub async fn set_default_channel_permissions(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Join Call /// Join Call
/// ///
/// Asks the voice server for a token to join the call. /// Asks the voice server for a token to join the call.
#[utoipa::path(tag = "Voice")] #[utoipa::path(
tag = "Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::LegacyCreateVoiceUserResponse),
),
)]
#[post("/<target>/join_call")] #[post("/<target>/join_call")]
pub async fn call( pub async fn call(
db: &State<Database>, db: &State<Database>,

View File

@@ -11,10 +11,16 @@ use rocket::{serde::json::Json, State};
use ulid::Ulid; use ulid::Ulid;
use validator::Validate; use validator::Validate;
/// # Creates a webhook /// Creates a webhook
/// ///
/// Creates a webhook which 3rd party platforms can use to send messages /// Creates a webhook which 3rd party platforms can use to send messages
#[utoipa::path(tag = "Webhooks")] #[utoipa::path(
tag = "Webhooks",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Webhook),
),
)]
#[post("/<target>/webhooks", data = "<data>")] #[post("/<target>/webhooks", data = "<data>")]
pub async fn create_webhook( pub async fn create_webhook(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Gets all webhooks /// Gets all webhooks
/// ///
/// Gets all webhooks inside the channel /// Gets all webhooks inside the channel
#[utoipa::path(tag = "Webhooks")] #[utoipa::path(
tag = "Webhooks",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = Vec<Webhook>),
),
)]
#[get("/<channel_id>/webhooks")] #[get("/<channel_id>/webhooks")]
pub async fn fetch_webhooks( pub async fn fetch_webhooks(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use validator::Validate;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Create New Emoji /// Create New Emoji
/// ///
/// Create an emoji by its Autumn upload id. /// Create an emoji by its Autumn upload id.
#[utoipa::path(tag = "Emojis")] #[utoipa::path(
tag = "Emojis",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Emoji),
),
)]
#[put("/emoji/<id>", data = "<data>")] #[put("/emoji/<id>", data = "<data>")]
pub async fn create_emoji( pub async fn create_emoji(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete Emoji /// Delete Emoji
/// ///
/// Delete an emoji by its id. /// Delete an emoji by its id.
#[utoipa::path(tag = "Emojis")] #[utoipa::path(
tag = "Emojis",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/emoji/<emoji_id>")] #[delete("/emoji/<emoji_id>")]
pub async fn delete_emoji( pub async fn delete_emoji(
db: &State<Database>, db: &State<Database>,

View File

@@ -4,10 +4,16 @@ use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Emoji /// Fetch Emoji
/// ///
/// Fetch an emoji by its id. /// Fetch an emoji by its id.
#[utoipa::path(tag = "Emojis")] #[utoipa::path(
tag = "Emojis",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Emoji),
),
)]
#[get("/emoji/<emoji_id>")] #[get("/emoji/<emoji_id>")]
pub async fn fetch_emoji(db: &State<Database>, emoji_id: Reference<'_>) -> Result<Json<v0::Emoji>> { pub async fn fetch_emoji(db: &State<Database>, emoji_id: Reference<'_>) -> Result<Json<v0::Emoji>> {
emoji_id emoji_id

View File

@@ -7,10 +7,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete Invite /// Delete Invite
/// ///
/// Delete an invite by its id. /// Delete an invite by its id.
#[utoipa::path(tag = "Invites")] #[utoipa::path(
tag = "Invites",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>")] #[delete("/<target>")]
pub async fn delete(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> { pub async fn delete(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> {
let invite = target.as_invite(db).await?; let invite = target.as_invite(db).await?;

View File

@@ -3,10 +3,16 @@ use revolt_models::v0;
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Invite /// Fetch Invite
/// ///
/// Fetch an invite by its id. /// Fetch an invite by its id.
#[utoipa::path(tag = "Invites")] #[utoipa::path(
tag = "Invites",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::InviteResponse),
),
)]
#[get("/<target>")] #[get("/<target>")]
pub async fn fetch(db: &State<Database>, target: Reference<'_>) -> Result<Json<v0::InviteResponse>> { pub async fn fetch(db: &State<Database>, target: Reference<'_>) -> Result<Json<v0::InviteResponse>> {
Ok(Json(match target.as_invite(db).await? { Ok(Json(match target.as_invite(db).await? {

View File

@@ -3,10 +3,16 @@ use revolt_models::v0::{self, InviteJoinResponse};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Join Invite /// Join Invite
/// ///
/// Join an invite by its ID /// Join an invite by its ID
#[utoipa::path(tag = "Invites")] #[utoipa::path(
tag = "Invites",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::InviteJoinResponse),
),
)]
#[post("/<target>")] #[post("/<target>")]
pub async fn join( pub async fn join(
db: &State<Database>, db: &State<Database>,

View File

@@ -1,5 +1,6 @@
use revolt_config::Settings; use revolt_config::Settings;
use revolt_database::{util::utoipa::TokenSecurity}; use revolt_database::util::utoipa::TokenSecurity;
use revolt_result::ErrorAddon;
pub use rocket::http::Status; pub use rocket::http::Status;
pub use rocket::response::Redirect; pub use rocket::response::Redirect;
use rocket::{Build, Rocket}; use rocket::{Build, Rocket};
@@ -236,8 +237,12 @@ pub fn mount(config: Settings, mut rocket: Rocket<Build>) -> Rocket<Build> {
), ),
modifiers( modifiers(
&Extensions, &Extensions,
// TODO: merge these together when authifier is moved into the backend
&SecurityAddon, &SecurityAddon,
&TokenSecurity, &TokenSecurity,
&ErrorAddon,
), ),
)] )]
pub struct ApiDoc; pub struct ApiDoc;

View File

@@ -15,7 +15,7 @@ use validator::Validate;
/// Block lookalike characters /// Block lookalike characters
pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap()); pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
/// # New User Data /// New User Data
#[derive(Validate, Serialize, Deserialize, ToSchema)] #[derive(Validate, Serialize, Deserialize, ToSchema)]
pub struct DataOnboard { pub struct DataOnboard {
/// New username which will be used to identify the user on the platform /// New username which will be used to identify the user on the platform
@@ -23,10 +23,16 @@ pub struct DataOnboard {
username: String, username: String,
} }
/// # Complete Onboarding /// Complete Onboarding
/// ///
/// This sets a new username, completes onboarding and allows a user to start using Revolt. /// This sets a new username, completes onboarding and allows a user to start using Revolt.
#[utoipa::path(tag = "Onboarding")] #[utoipa::path(
tag = "Onboarding",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[post("/complete", data = "<data>")] #[post("/complete", data = "<data>")]
pub async fn complete( pub async fn complete(
db: &State<Database>, db: &State<Database>,

View File

@@ -4,17 +4,23 @@ use revolt_database::User;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::Serialize; use serde::Serialize;
/// # Onboarding Status /// Onboarding Status
#[derive(Serialize, ToSchema)] #[derive(Serialize, ToSchema)]
pub struct DataHello { pub struct DataHello {
/// Whether onboarding is required /// Whether onboarding is required
onboarding: bool, onboarding: bool,
} }
/// # Check Onboarding Status /// Check Onboarding Status
/// ///
/// This will tell you whether the current account requires onboarding or whether you can continue to send requests as usual. You may skip calling this if you're restoring an existing session. /// This will tell you whether the current account requires onboarding or whether you can continue to send requests as usual. You may skip calling this if you're restoring an existing session.
#[utoipa::path(tag = "Onboarding")] #[utoipa::path(
tag = "Onboarding",
security(("Session-Token" = [])),
responses(
(status = 200, body = DataHello),
),
)]
#[get("/hello")] #[get("/hello")]
pub async fn hello(_session: Session, user: Option<User>) -> Json<DataHello> { pub async fn hello(_session: Session, user: Option<User>) -> Json<DataHello> {
Json(DataHello { Json(DataHello {

View File

@@ -3,10 +3,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
/// # Acknowledge Policy Changes /// Acknowledge Policy Changes
/// ///
/// Accept/acknowledge changes to platform policy. /// Accept/acknowledge changes to platform policy.
#[utoipa::path(tag = "Policy")] #[utoipa::path(
tag = "Policy",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[post("/acknowledge")] #[post("/acknowledge")]
pub async fn acknowledge_policy_changes(db: &State<Database>, user: User) -> Result<()> { pub async fn acknowledge_policy_changes(db: &State<Database>, user: User) -> Result<()> {
db.acknowledge_policy_changes(&user.id).await db.acknowledge_policy_changes(&user.id).await

View File

@@ -6,12 +6,18 @@ use revolt_result::{create_database_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Push Subscribe /// Push Subscribe
/// ///
/// Create a new Web Push subscription. /// Create a new Web Push subscription.
/// ///
/// If an existing subscription exists on this session, it will be removed. /// If an existing subscription exists on this session, it will be removed.
#[utoipa::path(tag = "Web Push")] #[utoipa::path(
tag = "Web Push",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[post("/subscribe", data = "<data>")] #[post("/subscribe", data = "<data>")]
pub async fn subscribe( pub async fn subscribe(
authifier: &State<Authifier>, authifier: &State<Authifier>,

View File

@@ -5,10 +5,16 @@ use rocket_empty::EmptyResponse;
use rocket::State; use rocket::State;
/// # Unsubscribe /// Unsubscribe
/// ///
/// Remove the Web Push subscription associated with the current session. /// Remove the Web Push subscription associated with the current session.
#[utoipa::path(tag = "Web Push")] #[utoipa::path(
tag = "Web Push",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[post("/unsubscribe")] #[post("/unsubscribe")]
pub async fn unsubscribe( pub async fn unsubscribe(
authifier: &State<Authifier>, authifier: &State<Authifier>,

View File

@@ -3,10 +3,13 @@ use revolt_models::v0;
use revolt_result::Result; use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
/// # Query Node /// Query Node
/// ///
/// Fetch the server configuration for this Revolt instance. /// Fetch the server configuration for this Revolt instance.
#[utoipa::path(tag = "Core")] #[utoipa::path(
tag = "Core",
responses((status = 200, body = v0::RevoltConfig))
)]
#[get("/")] #[get("/")]
pub async fn root() -> Result<Json<v0::RevoltConfig>> { pub async fn root() -> Result<Json<v0::RevoltConfig>> {
let config = config().await; let config = config().await;

View File

@@ -7,7 +7,7 @@ use validator::Validate;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Report Data /// Report Data
#[derive(Validate, Deserialize, ToSchema)] #[derive(Validate, Deserialize, ToSchema)]
pub struct DataReportContent { pub struct DataReportContent {
/// Content being reported /// Content being reported
@@ -18,10 +18,16 @@ pub struct DataReportContent {
additional_context: String, additional_context: String,
} }
/// # Report Content /// Report Content
/// ///
/// Report a piece of content to the moderation team. /// Report a piece of content to the moderation team.
#[utoipa::path(tag = "User Safety")] #[utoipa::path(
tag = "User Safety",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[post("/report", data = "<data>")] #[post("/report", data = "<data>")]
pub async fn report_content( pub async fn report_content(
db: &State<Database>, db: &State<Database>,

View File

@@ -9,10 +9,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Ban User /// Ban User
/// ///
/// Ban a user by their id. /// Ban a user by their id.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::ServerBan),
),
)]
#[put("/<server>/bans/<target>", data = "<data>")] #[put("/<server>/bans/<target>", data = "<data>")]
pub async fn ban( pub async fn ban(
db: &State<Database>, db: &State<Database>,

View File

@@ -9,10 +9,16 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Bans /// Fetch Bans
/// ///
/// Fetch all bans on a server. /// Fetch all bans on a server.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::BanListResult),
),
)]
#[get("/<target>/bans")] #[get("/<target>/bans")]
pub async fn list( pub async fn list(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::Result;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Unban user /// Unban user
/// ///
/// Remove a user's ban. /// Remove a user's ban.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<server>/bans/<target>")] #[delete("/<server>/bans/<target>")]
pub async fn unban( pub async fn unban(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Create Channel /// Create Channel
/// ///
/// Create a new Text or Voice channel. /// Create a new Text or Voice channel.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[post("/<server>/channels", data = "<data>")] #[post("/<server>/channels", data = "<data>")]
pub async fn create_server_channel( pub async fn create_server_channel(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::PermissionQuery;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Server Emoji /// Fetch Server Emoji
/// ///
/// Fetch all emoji on a server. /// Fetch all emoji on a server.
#[utoipa::path(tag = "Server Customisation")] #[utoipa::path(
tag = "Server Customisation",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = Vec<v0::Emoji>),
),
)]
#[get("/<target>/emojis")] #[get("/<target>/emojis")]
pub async fn list_emoji( pub async fn list_emoji(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::{calculate_server_permissions, ChannelPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Invites /// Fetch Invites
/// ///
/// Fetch all server invites. /// Fetch all server invites.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = Vec<v0::Invite>),
),
)]
#[get("/<target>/invites")] #[get("/<target>/invites")]
pub async fn invites( pub async fn invites(
db: &State<Database>, db: &State<Database>,

View File

@@ -11,10 +11,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Edit Member /// Edit Member
/// ///
/// Edit a member by their id. /// Edit a member by their id.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Member),
),
)]
#[patch("/<server>/members/<member>", data = "<data>")] #[patch("/<server>/members/<member>", data = "<data>")]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,
@@ -40,7 +46,9 @@ pub async fn edit(
let permissions = calculate_server_permissions(&mut query).await; let permissions = calculate_server_permissions(&mut query).await;
// Fetch target permissions // Fetch target permissions
let mut target_query = DatabasePermissionQuery::new(db, &target_user).server(&server).member(&member); let mut target_query = DatabasePermissionQuery::new(db, &target_user)
.server(&server)
.member(&member);
let target_permissions = calculate_server_permissions(&mut target_query).await; let target_permissions = calculate_server_permissions(&mut target_query).await;
// Check permissions in server // Check permissions in server
@@ -71,7 +79,7 @@ pub async fn edit(
} }
if target_permissions.has_channel_permission(ChannelPermission::TimeoutMembers) { if target_permissions.has_channel_permission(ChannelPermission::TimeoutMembers) {
return Err(create_error!(IsElevated)) return Err(create_error!(IsElevated));
} }
} }

View File

@@ -9,8 +9,8 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// # Query Parameters /// Query Parameters
#[derive(Deserialize, ToSchema, FromForm)] #[derive(Deserialize, ToSchema, FromForm, IntoParams)]
pub struct OptionsQueryMembers { pub struct OptionsQueryMembers {
/// String to search for /// String to search for
query: String, query: String,
@@ -19,8 +19,8 @@ pub struct OptionsQueryMembers {
experimental_api: bool, experimental_api: bool,
} }
/// # Query members by name /// Query members by name
#[derive(Serialize, ToSchema)] #[derive(Serialize, ToSchema, IntoParams)]
pub struct MemberQueryResponse { pub struct MemberQueryResponse {
/// List of members /// List of members
members: Vec<v0::Member>, members: Vec<v0::Member>,
@@ -28,10 +28,17 @@ pub struct MemberQueryResponse {
users: Vec<v0::User>, users: Vec<v0::User>,
} }
/// # Query members by name /// Query members by name
/// ///
/// Query members by a given name, this API is not stable and will be removed in the future. /// Query members by a given name, this API is not stable and will be removed in the future.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(OptionsQueryMembers),
responses(
(status = 200, body = MemberQueryResponse),
),
)]
#[get("/<target>/members_experimental_query?<options..>")] #[get("/<target>/members_experimental_query?<options..>")]
pub async fn member_experimental_query( pub async fn member_experimental_query(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,24 @@ use revolt_permissions::PermissionQuery;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Member /// Fetch Member
/// ///
/// Retrieve a member. /// Retrieve a member.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(
(
"roles" = bool,
Query,
description = "Whether to include roles in the response",
example = json!(true)
)
),
responses(
(status = 200, body = v0::MemberResponse),
),
)]
#[get("/<target>/members/<member>?<roles>")] #[get("/<target>/members/<member>?<roles>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,17 @@ use revolt_permissions::PermissionQuery;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Members /// Fetch Members
/// ///
/// Fetch all server members. /// Fetch all server members.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsFetchAllMembers),
responses(
(status = 200, body = v0::AllMemberResponse),
),
)]
#[get("/<target>/members?<options..>")] #[get("/<target>/members?<options..>")]
pub async fn fetch_all( pub async fn fetch_all(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Kick Member /// Kick Member
/// ///
/// Removes a member from the server. /// Removes a member from the server.
#[utoipa::path(tag = "Server Members")] #[utoipa::path(
tag = "Server Members",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/members/<member>")] #[delete("/<target>/members/<member>")]
pub async fn kick( pub async fn kick(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::{calculate_server_permissions, ChannelPermission, Overri
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Set Role Permission /// Set Role Permission
/// ///
/// Sets permissions for the specified role in the server. /// Sets permissions for the specified role in the server.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Server),
),
)]
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)] #[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
pub async fn set_role_permission( pub async fn set_role_permission(
db: &State<Database>, db: &State<Database>,

View File

@@ -9,10 +9,16 @@ use revolt_permissions::{
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Set Default Permission /// Set Default Permission
/// ///
/// Sets permissions for the default role in this server. /// Sets permissions for the default role in this server.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Server),
),
)]
#[put("/<target>/permissions/default", data = "<data>", rank = 1)] #[put("/<target>/permissions/default", data = "<data>", rank = 1)]
pub async fn set_default_server_permissions( pub async fn set_default_server_permissions(
db: &State<Database>, db: &State<Database>,

View File

@@ -9,10 +9,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Create Role /// Create Role
/// ///
/// Creates a new server role. /// Creates a new server role.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::NewRoleResponse),
),
)]
#[post("/<target>/roles", data = "<data>")] #[post("/<target>/roles", data = "<data>")]
pub async fn create( pub async fn create(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete Role /// Delete Role
/// ///
/// Delete a server role by its id. /// Delete a server role by its id.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 204),
),
)]
#[delete("/<target>/roles/<role_id>")] #[delete("/<target>/roles/<role_id>")]
pub async fn delete( pub async fn delete(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Edit Role /// Edit Role
/// ///
/// Edit a role by its id. /// Edit a role by its id.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Role),
),
)]
#[patch("/<target>/roles/<role_id>", data = "<data>", rank = 1)] #[patch("/<target>/roles/<role_id>", data = "<data>", rank = 1)]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::{calculate_server_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Edits server roles ranks /// Edits server roles ranks
/// ///
/// Edit's server role's ranks. /// Edit's server role's ranks.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Server),
),
)]
#[patch("/<target>/roles/ranks", data = "<data>")] #[patch("/<target>/roles/ranks", data = "<data>")]
pub async fn edit_role_ranks( pub async fn edit_role_ranks(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_permissions::PermissionQuery;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Role /// Fetch Role
/// ///
/// Fetch a role by its id. /// Fetch a role by its id.
#[utoipa::path(tag = "Server Permissions")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Role),
),
)]
#[get("/<target>/roles/<role_id>")] #[get("/<target>/roles/<role_id>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,16 @@ use revolt_result::{create_error, Result};
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Mark Server As Read /// Mark Server As Read
/// ///
/// Mark all channels in a server as read. /// Mark all channels in a server as read.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = [])),
responses(
(status = 204),
),
)]
#[put("/<target>/ack")] #[put("/<target>/ack")]
pub async fn ack(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> { pub async fn ack(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> {
if user.bot.is_some() { if user.bot.is_some() {

View File

@@ -6,10 +6,16 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Create Server /// Create Server
/// ///
/// Create a new server. /// Create a new server.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::CreateServerLegacyResponse),
),
)]
#[post("/create", data = "<data>")] #[post("/create", data = "<data>")]
pub async fn create_server( pub async fn create_server(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,17 @@ use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
/// # Delete / Leave Server /// Delete / Leave Server
/// ///
/// Deletes a server if owner otherwise leaves. /// Deletes a server if owner otherwise leaves.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Permissions",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsServerDelete),
responses(
(status = 204),
),
)]
#[delete("/<target>?<options..>")] #[delete("/<target>?<options..>")]
pub async fn delete( pub async fn delete(
db: &State<Database>, db: &State<Database>,

View File

@@ -10,10 +10,16 @@ use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use validator::Validate; use validator::Validate;
/// # Edit Server /// Edit Server
/// ///
/// Edit a server by its id. /// Edit a server by its id.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Server),
),
)]
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,

View File

@@ -7,10 +7,17 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission, Permi
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Server /// Fetch Server
/// ///
/// Fetch a server by its id. /// Fetch a server by its id.
#[utoipa::path(tag = "Server Information")] #[utoipa::path(
tag = "Server Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
params(v0::OptionsFetchServer),
responses(
(status = 200, body = v0::Server),
),
)]
#[get("/<target>?<options..>")] #[get("/<target>?<options..>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -4,12 +4,18 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Settings /// Fetch Settings
/// ///
/// Fetch settings from server filtered by keys. /// Fetch settings from server filtered by keys.
/// ///
/// This will return an object with the requested keys, each value is a tuple of `(timestamp, value)`, the value is the previously uploaded data. /// This will return an object with the requested keys, each value is a tuple of `(timestamp, value)`, the value is the previously uploaded data.
#[utoipa::path(tag = "Sync")] #[utoipa::path(
tag = "Sync",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::OptionsFetchSettings),
),
)]
#[post("/settings/fetch", data = "<options>")] #[post("/settings/fetch", data = "<options>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -4,10 +4,16 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Unreads /// Fetch Unreads
/// ///
/// Fetch information about unread state on channels. /// Fetch information about unread state on channels.
#[utoipa::path(tag = "Sync")] #[utoipa::path(
tag = "Sync",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::ChannelUnread),
),
)]
#[get("/unreads")] #[get("/unreads")]
pub async fn unreads(db: &State<Database>, user: User) -> Result<Json<Vec<v0::ChannelUnread>>> { pub async fn unreads(db: &State<Database>, user: User) -> Result<Json<Vec<v0::ChannelUnread>>> {
db.fetch_unreads(&user.id) db.fetch_unreads(&user.id)

View File

@@ -9,10 +9,22 @@ use std::collections::HashMap;
type Data = HashMap<String, String>; type Data = HashMap<String, String>;
/// # Set Settings /// Set Settings
/// ///
/// Upload data to save to settings. /// Upload data to save to settings.
#[utoipa::path(tag = "Sync")] #[utoipa::path(
tag = "Sync",
security(("Session-Token" = [])),
request_body(
content = Data,
content_type = "application/json",
example = json!({"servers": "[\"01F7ZSBSFHQ8TA81725KQCSDDP\"]"}),
),
params(v0::OptionsSetSettings),
responses(
(status = 204),
),
)]
#[post("/settings/set?<options..>", data = "<data>")] #[post("/settings/set?<options..>", data = "<data>")]
pub async fn set( pub async fn set(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Accept Friend Request /// Accept Friend Request
/// ///
/// Accept another user's friend request. /// Accept another user's friend request.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "Relationships",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[put("/<target>/friend")] #[put("/<target>/friend")]
pub async fn add( pub async fn add(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Block User /// Block User
/// ///
/// Block another user by their id. /// Block another user by their id.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "Relationships",
security(("Session-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[put("/<target>/block")] #[put("/<target>/block")]
pub async fn block( pub async fn block(
db: &State<Database>, db: &State<Database>,

View File

@@ -14,7 +14,7 @@ use validator::Validate;
/// Block lookalike characters /// Block lookalike characters
pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap()); pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
/// # Username Information /// Username Information
#[derive(Validate, Serialize, Deserialize, ToSchema)] #[derive(Validate, Serialize, Deserialize, ToSchema)]
pub struct DataChangeUsername { pub struct DataChangeUsername {
/// New username /// New username
@@ -25,10 +25,16 @@ pub struct DataChangeUsername {
password: String, password: String,
} }
/// # Change Username /// Change Username
/// ///
/// Change your username. /// Change your username.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[patch("/@me/username", data = "<data>")] #[patch("/@me/username", data = "<data>")]
pub async fn change_username( pub async fn change_username(
db: &State<Database>, db: &State<Database>,

View File

@@ -6,10 +6,16 @@ use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use validator::Validate; use validator::Validate;
/// # Edit User /// Edit User
/// ///
/// Edit currently authenticated user. /// Edit currently authenticated user.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn edit( pub async fn edit(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,10 +3,16 @@ use revolt_models::v0;
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch Direct Message Channels /// Fetch Direct Message Channels
/// ///
/// This fetches your direct messages, including any DM and group DM conversations. /// This fetches your direct messages, including any DM and group DM conversations.
#[utoipa::path(tag = "Direct Messaging")] #[utoipa::path(
tag = "Direct Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = Vec<v0::Channel>),
),
)]
#[get("/dms")] #[get("/dms")]
pub async fn direct_messages(db: &State<Database>, user: User) -> Result<Json<Vec<v0::Channel>>> { pub async fn direct_messages(db: &State<Database>, user: User) -> Result<Json<Vec<v0::Channel>>> {
db.find_direct_messages(&user.id) db.find_direct_messages(&user.id)

View File

@@ -7,12 +7,18 @@ use revolt_permissions::{calculate_user_permissions, UserPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch User Profile /// Fetch User Profile
/// ///
/// Retrieve a user's profile data. /// Retrieve a user's profile data.
/// ///
/// Will fail if you do not have permission to access the other user's profile. /// Will fail if you do not have permission to access the other user's profile.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::UserProfile),
),
)]
#[get("/<target>/profile")] #[get("/<target>/profile")]
pub async fn profile( pub async fn profile(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,10 +3,16 @@ use revolt_models::v0;
use revolt_result::Result; use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
/// # Fetch Self /// Fetch Self
/// ///
/// Retrieve your user information. /// Retrieve your user information.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[get("/@me")] #[get("/@me")]
pub async fn fetch(user: User) -> Result<Json<v0::User>> { pub async fn fetch(user: User) -> Result<Json<v0::User>> {
Ok(Json(user.into_self(false).await)) Ok(Json(user.into_self(false).await))

View File

@@ -8,10 +8,16 @@ use revolt_permissions::{calculate_user_permissions, UserPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch User /// Fetch User
/// ///
/// Retrieve a user's information. /// Retrieve a user's information.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[get("/<target>")] #[get("/<target>")]
pub async fn fetch( pub async fn fetch(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,10 +3,15 @@ use revolt_models::v0;
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Fetch User Flags /// Fetch User Flags
/// ///
/// Retrieve a user's flags. /// Retrieve a user's flags.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
responses(
(status = 200, body = v0::FlagResponse),
),
)]
#[get("/<target>/flags")] #[get("/<target>/flags")]
pub async fn fetch_user_flags( pub async fn fetch_user_flags(
db: &State<Database>, db: &State<Database>,

View File

@@ -8,10 +8,16 @@ use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Fetch Mutual Friends, Servers, Groups and DMs /// Fetch Mutual Friends, Servers, Groups and DMs
/// ///
/// Retrieve a list of mutual friends, servers, groups and DMs with another user. /// Retrieve a list of mutual friends, servers, groups and DMs with another user.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::MutualResponse),
),
)]
#[get("/<target>/mutual")] #[get("/<target>/mutual")]
pub async fn mutual( pub async fn mutual(
db: &State<Database>, db: &State<Database>,

View File

@@ -3,6 +3,7 @@ use rocket::response::{self, Responder};
use rocket::{Request, Response}; use rocket::{Request, Response};
#[derive(ToSchema)] #[derive(ToSchema)]
#[schema(format = "binary", value_type = String)]
pub struct CachedFile(Vec<u8>); pub struct CachedFile(Vec<u8>);
pub static CACHE_CONTROL: &str = "public, max-age=31536000, immutable"; pub static CACHE_CONTROL: &str = "public, max-age=31536000, immutable";
@@ -15,10 +16,21 @@ impl<'r> Responder<'r, 'static> for CachedFile {
} }
} }
/// # Fetch Default Avatar /// Fetch Default Avatar
/// ///
/// This returns a default avatar based on the given id. /// This returns a default avatar based on the given id.
#[utoipa::path(tag = "User Information")] #[utoipa::path(
tag = "User Information",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(
status = 200,
description = "PNG image with the users default avatar.",
content_type = "image/png",
body = CachedFile,
),
),
)]
#[get("/<target>/default_avatar")] #[get("/<target>/default_avatar")]
pub async fn default_avatar(target: String) -> (ContentType, CachedFile) { pub async fn default_avatar(target: String) -> (ContentType, CachedFile) {
( (

View File

@@ -7,12 +7,18 @@ use revolt_permissions::{calculate_user_permissions, UserPermission};
use revolt_result::Result; use revolt_result::Result;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
/// # Open Direct Message /// Open Direct Message
/// ///
/// Open a DM with another user. /// Open a DM with another user.
/// ///
/// If the target is oneself, a saved messages channel is returned. /// If the target is oneself, a saved messages channel is returned.
#[utoipa::path(tag = "Direct Messaging")] #[utoipa::path(
tag = "Direct Messaging",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::Channel),
),
)]
#[get("/<target>/dm")] #[get("/<target>/dm")]
pub async fn open_dm( pub async fn open_dm(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Deny Friend Request / Remove Friend /// Deny Friend Request / Remove Friend
/// ///
/// Denies another user's friend request or removes an existing friend. /// Denies another user's friend request or removes an existing friend.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "Relationships",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[delete("/<target>/friend")] #[delete("/<target>/friend")]
pub async fn remove( pub async fn remove(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Send Friend Request /// Send Friend Request
/// ///
/// Send a friend request to another user. /// Send a friend request to another user.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "Relationships",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[post("/friend", data = "<data>")] #[post("/friend", data = "<data>")]
pub async fn send_friend_request( pub async fn send_friend_request(
db: &State<Database>, db: &State<Database>,

View File

@@ -5,10 +5,16 @@ use revolt_result::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
/// # Unblock User /// Unblock User
/// ///
/// Unblock another user by their id. /// Unblock another user by their id.
#[utoipa::path(tag = "Relationships")] #[utoipa::path(
tag = "Relationships",
security(("Session-Token" = []), ("Bot-Token" = [])),
responses(
(status = 200, body = v0::User),
),
)]
#[delete("/<target>/block")] #[delete("/<target>/block")]
pub async fn unblock( pub async fn unblock(
db: &State<Database>, db: &State<Database>,

Some files were not shown because too many files have changed in this diff Show More