chore: update everything to work with utoipa
This commit is contained in:
@@ -35,7 +35,7 @@ nanoid = "0.4.0"
|
||||
serde_json = "1.0.57"
|
||||
serde = { version = "1.0.115", features = ["derive"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
iso8601-timestamp = { version = "0.2.11", features = [] }
|
||||
iso8601-timestamp = { version = "0.4.0", features = [] }
|
||||
|
||||
# async
|
||||
futures = "0.3.8"
|
||||
@@ -60,8 +60,8 @@ rocket_authifier = { version = "1.0.15" }
|
||||
rocket_prometheus = "0.10.0-rc.3"
|
||||
|
||||
# spec generation
|
||||
schemars = "0.8.8"
|
||||
revolt_rocket_okapi = { version = "0.10.0", features = ["swagger"] }
|
||||
utoipa = { version = "5.4.0", features = ["rocket_extras"] }
|
||||
utoipa-scalar = { version = "0.3.0", features = ["rocket"] }
|
||||
|
||||
# rabbit
|
||||
amqprs = { version = "1.7.0" }
|
||||
@@ -72,15 +72,16 @@ revolt-config = { path = "../core/config" }
|
||||
revolt-database = { path = "../core/database", features = [
|
||||
"rocket-impl",
|
||||
"redis-is-patched",
|
||||
"utoipa"
|
||||
] }
|
||||
revolt-models = { path = "../core/models", features = [
|
||||
"schemas",
|
||||
"utoipa",
|
||||
"validator",
|
||||
"rocket",
|
||||
] }
|
||||
revolt-presence = { path = "../core/presence" }
|
||||
revolt-result = { path = "../core/result", features = ["rocket", "okapi"] }
|
||||
revolt-permissions = { path = "../core/permissions", features = ["schemas"] }
|
||||
revolt-result = { path = "../core/result", features = ["rocket", "utoipa"] }
|
||||
revolt-permissions = { path = "../core/permissions", features = ["utoipa"] }
|
||||
revolt-ratelimits = { path = "../core/ratelimits", features = ["rocket"] }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
#[macro_use]
|
||||
extern crate revolt_rocket_okapi;
|
||||
extern crate utoipa;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
@@ -15,6 +15,8 @@ use revolt_ratelimits::rocket as ratelimiter;
|
||||
use rocket::{Build, Rocket};
|
||||
use rocket_cors::{AllowedOrigins, CorsOptions};
|
||||
use rocket_prometheus::PrometheusMetrics;
|
||||
use utoipa::OpenApi;
|
||||
use utoipa_scalar::{Scalar, Servable};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -73,22 +75,6 @@ pub async fn web() -> Rocket<Build> {
|
||||
.to_cors()
|
||||
.expect("Failed to create CORS.");
|
||||
|
||||
// Configure Swagger
|
||||
let swagger = revolt_rocket_okapi::swagger_ui::make_swagger_ui(
|
||||
&revolt_rocket_okapi::swagger_ui::SwaggerUIConfig {
|
||||
url: "/openapi.json".to_owned(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.into();
|
||||
|
||||
let swagger_0_8 = revolt_rocket_okapi::swagger_ui::make_swagger_ui(
|
||||
&revolt_rocket_okapi::swagger_ui::SwaggerUIConfig {
|
||||
url: "/0.8/openapi.json".to_owned(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.into();
|
||||
|
||||
// Configure Rabbit
|
||||
let connection = Connection::open(&OpenConnectionArguments::new(
|
||||
@@ -131,8 +117,7 @@ pub async fn web() -> Rocket<Build> {
|
||||
.mount("/metrics", prometheus)
|
||||
.mount("/", rocket_cors::catch_all_options_routes())
|
||||
.mount("/", ratelimiter::routes())
|
||||
.mount("/swagger/", swagger)
|
||||
.mount("/0.8/swagger/", swagger_0_8)
|
||||
.mount("/", Scalar::with_url("/scalar", routes::ApiDoc::openapi()))
|
||||
.manage(authifier)
|
||||
.manage(db)
|
||||
.manage(amqp)
|
||||
|
||||
@@ -8,7 +8,7 @@ use validator::Validate;
|
||||
/// # Create Bot
|
||||
///
|
||||
/// Create a new Revolt bot.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[post("/create", data = "<info>")]
|
||||
pub async fn create_bot(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete Bot
|
||||
///
|
||||
/// Delete a bot by its id.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn delete_bot(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -9,7 +9,7 @@ use validator::Validate;
|
||||
/// # Edit Bot
|
||||
///
|
||||
/// Edit bot details by its id.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit_bot(
|
||||
db: &State<Database>,
|
||||
@@ -60,15 +60,8 @@ pub async fn edit_bot(
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
bot.update(
|
||||
db,
|
||||
partial,
|
||||
remove
|
||||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect(),
|
||||
)
|
||||
.await?;
|
||||
bot.update(db, partial, remove.into_iter().map(|v| v.into()).collect())
|
||||
.await?;
|
||||
|
||||
Ok(Json(v0::BotWithUserResponse {
|
||||
bot: bot.into(),
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Bot
|
||||
///
|
||||
/// Fetch details of a bot you own by its id.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[get("/<bot>")]
|
||||
pub async fn fetch_bot(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Fetch Owned Bots
|
||||
///
|
||||
/// Fetch all of the bots that you have control over.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[get("/@me")]
|
||||
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?;
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Fetch Public Bot
|
||||
///
|
||||
/// Fetch details of a public (or owned) bot by its id.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[get("/<target>/invite")]
|
||||
pub async fn fetch_public_bot(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -14,7 +14,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Invite Bot
|
||||
///
|
||||
/// Invite a bot to a server or group by its id.`
|
||||
#[openapi(tag = "Bots")]
|
||||
#[utoipa::path(tag = "Bots")]
|
||||
#[post("/<target>/invite", data = "<dest>")]
|
||||
pub async fn invite_bot(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod create;
|
||||
@@ -9,8 +8,22 @@ mod fetch_owned;
|
||||
mod fetch_public;
|
||||
mod invite;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
create::create_bot,
|
||||
invite::invite_bot,
|
||||
fetch_public::fetch_public_bot,
|
||||
fetch::fetch_bot,
|
||||
fetch_owned::fetch_owned_bots,
|
||||
edit::edit_bot,
|
||||
delete::delete_bot,
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
create::create_bot,
|
||||
invite::invite_bot,
|
||||
fetch_public::fetch_public_bot,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Acknowledge Message
|
||||
///
|
||||
/// Lets the server and all other clients know that we've seen this message id in this channel.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[put("/<target>/ack/<message>")]
|
||||
pub async fn ack(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Close Channel
|
||||
///
|
||||
/// Deletes a server channel, leaves a group or closes a group.
|
||||
#[openapi(tag = "Channel Information")]
|
||||
#[utoipa::path(tag = "Channel Information")]
|
||||
#[delete("/<target>?<options..>")]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use validator::Validate;
|
||||
/// # Edit Channel
|
||||
///
|
||||
/// Edit a channel object by its id.
|
||||
#[openapi(tag = "Channel Information")]
|
||||
#[utoipa::path(tag = "Channel Information")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Channel
|
||||
///
|
||||
/// Fetch channel by its id.
|
||||
#[openapi(tag = "Channel Information")]
|
||||
#[utoipa::path(tag = "Channel Information")]
|
||||
#[get("/<target>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Add Member to Group
|
||||
///
|
||||
/// Adds another user to the group.
|
||||
#[openapi(tag = "Groups")]
|
||||
#[utoipa::path(tag = "Groups")]
|
||||
#[put("/<group_id>/recipients/<member_id>")]
|
||||
pub async fn add_member(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -9,7 +9,7 @@ use validator::Validate;
|
||||
/// # Create Group
|
||||
///
|
||||
/// Create a new group channel.
|
||||
#[openapi(tag = "Groups")]
|
||||
#[utoipa::path(tag = "Groups")]
|
||||
#[post("/create", data = "<data>")]
|
||||
pub async fn create_group(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Remove Member from Group
|
||||
///
|
||||
/// Removes a user from the group.
|
||||
#[openapi(tag = "Groups")]
|
||||
#[utoipa::path(tag = "Groups")]
|
||||
#[delete("/<target>/recipients/<member>")]
|
||||
pub async fn remove_member(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -13,7 +13,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// Creates an invite to this channel.
|
||||
///
|
||||
/// Channel must be a `TextChannel`.
|
||||
#[openapi(tag = "Channel Invites")]
|
||||
#[utoipa::path(tag = "Channel Invites")]
|
||||
#[post("/<target>/invites")]
|
||||
pub async fn create_invite(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// 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")]
|
||||
#[utoipa::path(tag = "Groups")]
|
||||
#[get("/<target>/members")]
|
||||
pub async fn fetch_members(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -17,7 +17,7 @@ use validator::Validate;
|
||||
/// 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.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[delete("/<target>/messages/bulk", data = "<options>", rank = 1)]
|
||||
pub async fn bulk_delete_messages(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// Remove your own, someone else's or all of a given reaction.
|
||||
///
|
||||
/// Requires `ManageMessages` permission.
|
||||
#[openapi(tag = "Interactions")]
|
||||
#[utoipa::path(tag = "Interactions")]
|
||||
#[delete("/<target>/messages/<msg>/reactions")]
|
||||
pub async fn clear_reactions(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete Message
|
||||
///
|
||||
/// Delete a message you've sent or one you have permission to delete.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[delete("/<target>/messages/<msg>", rank = 2)]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -13,7 +13,7 @@ use validator::Validate;
|
||||
/// # Edit Message
|
||||
///
|
||||
/// Edits a message that you've previously sent.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[patch("/<target>/messages/<msg>", data = "<edit>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Message
|
||||
///
|
||||
/// Retrieves a message by its id.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[get("/<target>/messages/<msg>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Pins a message
|
||||
///
|
||||
/// Pins a message by its id.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[post("/<target>/messages/<msg>/pin")]
|
||||
pub async fn message_pin(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use validator::Validate;
|
||||
/// # Fetch Messages
|
||||
///
|
||||
/// Fetch multiple messages.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[get("/<target>/messages?<options..>")]
|
||||
pub async fn query(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Add Reaction to Message
|
||||
///
|
||||
/// React to a given message.
|
||||
#[openapi(tag = "Interactions")]
|
||||
#[utoipa::path(tag = "Interactions")]
|
||||
#[put("/<target>/messages/<msg>/reactions/<emoji>")]
|
||||
pub async fn react_message(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use validator::Validate;
|
||||
/// # Search for Messages
|
||||
///
|
||||
/// This route searches for messages within the given parameters.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[post("/<target>/search", data = "<options>")]
|
||||
pub async fn search(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -15,7 +15,7 @@ use validator::Validate;
|
||||
/// # Send Message
|
||||
///
|
||||
/// Sends a message to the given channel.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[post("/<target>/messages", data = "<data>")]
|
||||
pub async fn message_send(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Unpins a message
|
||||
///
|
||||
/// Unpins a message by its id.
|
||||
#[openapi(tag = "Messaging")]
|
||||
#[utoipa::path(tag = "Messaging")]
|
||||
#[delete("/<target>/messages/<msg>/pin")]
|
||||
pub async fn message_unpin(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -13,7 +13,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// Remove your own, someone else's or all of a given reaction.
|
||||
///
|
||||
/// Requires `ManageMessages` if changing others' reactions.
|
||||
#[openapi(tag = "Interactions")]
|
||||
#[utoipa::path(tag = "Interactions")]
|
||||
#[delete("/<target>/messages/<msg>/reactions/<emoji>?<options..>")]
|
||||
pub async fn unreact_message(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod channel_ack;
|
||||
@@ -28,8 +27,41 @@ mod voice_join;
|
||||
mod webhook_create;
|
||||
mod webhook_fetch_all;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
channel_ack::ack,
|
||||
channel_fetch::fetch,
|
||||
members_fetch::fetch_members,
|
||||
channel_delete::delete,
|
||||
channel_edit::edit,
|
||||
invite_create::create_invite,
|
||||
message_send::message_send,
|
||||
message_query::query,
|
||||
message_search::search,
|
||||
message_pin::message_pin,
|
||||
message_fetch::fetch,
|
||||
message_edit::edit,
|
||||
message_bulk_delete::bulk_delete_messages,
|
||||
message_delete::delete,
|
||||
message_unpin::message_unpin,
|
||||
group_create::create_group,
|
||||
group_add_member::add_member,
|
||||
group_remove_member::remove_member,
|
||||
voice_join::call,
|
||||
permissions_set::set_role_permissions,
|
||||
permissions_set_default::set_default_channel_permissions,
|
||||
message_react::react_message,
|
||||
message_unreact::unreact_message,
|
||||
message_clear_reactions::clear_reactions,
|
||||
webhook_create::create_webhook,
|
||||
webhook_fetch_all::fetch_webhooks,
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
channel_ack::ack,
|
||||
channel_fetch::fetch,
|
||||
members_fetch::fetch_members,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// Sets permissions for the specified role in this channel.
|
||||
///
|
||||
/// Channel must be a `TextChannel` or `VoiceChannel`.
|
||||
#[openapi(tag = "Channel Permissions")]
|
||||
#[utoipa::path(tag = "Channel Permissions")]
|
||||
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
|
||||
pub async fn set_role_permissions(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// Sets permissions for the default role in this channel.
|
||||
///
|
||||
/// Channel must be a `Group`, `TextChannel` or `VoiceChannel`.
|
||||
#[openapi(tag = "Channel Permissions")]
|
||||
#[utoipa::path(tag = "Channel Permissions")]
|
||||
#[put("/<target>/permissions/default", data = "<data>", rank = 1)]
|
||||
pub async fn set_default_channel_permissions(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Join Call
|
||||
///
|
||||
/// Asks the voice server for a token to join the call.
|
||||
#[openapi(tag = "Voice")]
|
||||
#[utoipa::path(tag = "Voice")]
|
||||
#[post("/<target>/join_call")]
|
||||
pub async fn call(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -14,7 +14,7 @@ use validator::Validate;
|
||||
/// # Creates a webhook
|
||||
///
|
||||
/// Creates a webhook which 3rd party platforms can use to send messages
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[utoipa::path(tag = "Webhooks")]
|
||||
#[post("/<target>/webhooks", data = "<data>")]
|
||||
pub async fn create_webhook(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Gets all webhooks
|
||||
///
|
||||
/// Gets all webhooks inside the channel
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[utoipa::path(tag = "Webhooks")]
|
||||
#[get("/<channel_id>/webhooks")]
|
||||
pub async fn fetch_webhooks(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Create New Emoji
|
||||
///
|
||||
/// Create an emoji by its Autumn upload id.
|
||||
#[openapi(tag = "Emojis")]
|
||||
#[utoipa::path(tag = "Emojis")]
|
||||
#[put("/emoji/<id>", data = "<data>")]
|
||||
pub async fn create_emoji(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete Emoji
|
||||
///
|
||||
/// Delete an emoji by its id.
|
||||
#[openapi(tag = "Emojis")]
|
||||
#[utoipa::path(tag = "Emojis")]
|
||||
#[delete("/emoji/<emoji_id>")]
|
||||
pub async fn delete_emoji(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -7,7 +7,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Emoji
|
||||
///
|
||||
/// Fetch an emoji by its id.
|
||||
#[openapi(tag = "Emojis")]
|
||||
#[utoipa::path(tag = "Emojis")]
|
||||
#[get("/emoji/<emoji_id>")]
|
||||
pub async fn fetch_emoji(db: &State<Database>, emoji_id: Reference<'_>) -> Result<Json<v0::Emoji>> {
|
||||
emoji_id
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod emoji_create;
|
||||
mod emoji_delete;
|
||||
mod emoji_fetch;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
emoji_create::create_emoji,
|
||||
emoji_delete::delete_emoji,
|
||||
emoji_fetch::fetch_emoji
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
emoji_create::create_emoji,
|
||||
emoji_delete::delete_emoji,
|
||||
emoji_fetch::fetch_emoji
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete Invite
|
||||
///
|
||||
/// Delete an invite by its id.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[utoipa::path(tag = "Invites")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn delete(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> {
|
||||
let invite = target.as_invite(db).await?;
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Invite
|
||||
///
|
||||
/// Fetch an invite by its id.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[utoipa::path(tag = "Invites")]
|
||||
#[get("/<target>")]
|
||||
pub async fn fetch(db: &State<Database>, target: Reference<'_>) -> Result<Json<v0::InviteResponse>> {
|
||||
Ok(Json(match target.as_invite(db).await? {
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Join Invite
|
||||
///
|
||||
/// Join an invite by its ID
|
||||
#[openapi(tag = "Invites")]
|
||||
#[utoipa::path(tag = "Invites")]
|
||||
#[post("/<target>")]
|
||||
pub async fn join(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod invite_delete;
|
||||
mod invite_fetch;
|
||||
mod invite_join;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
invite_fetch::fetch,
|
||||
invite_join::join,
|
||||
invite_delete::delete
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
invite_fetch::fetch,
|
||||
invite_join::join,
|
||||
invite_delete::delete
|
||||
|
||||
+304
-346
@@ -1,8 +1,13 @@
|
||||
use revolt_config::Settings;
|
||||
use revolt_rocket_okapi::{revolt_okapi::openapi3::OpenApi, settings::OpenApiSettings};
|
||||
use revolt_database::{util::utoipa::TokenSecurity};
|
||||
pub use rocket::http::Status;
|
||||
pub use rocket::response::Redirect;
|
||||
use rocket::{Build, Rocket};
|
||||
use rocket_authifier::SecurityAddon;
|
||||
use utoipa::{
|
||||
openapi::{extensions::ExtensionsBuilder, OpenApi},
|
||||
Modify,
|
||||
};
|
||||
|
||||
mod bots;
|
||||
mod channels;
|
||||
@@ -19,358 +24,311 @@ mod users;
|
||||
mod webhooks;
|
||||
|
||||
pub fn mount(config: Settings, mut rocket: Rocket<Build>) -> Rocket<Build> {
|
||||
let settings = OpenApiSettings::default();
|
||||
rocket = rocket
|
||||
.mount("/", routes![root::root])
|
||||
.mount("/users", users::routes())
|
||||
.mount("/bots", bots::routes())
|
||||
.mount("/channels", channels::routes())
|
||||
.mount("/servers", servers::routes())
|
||||
.mount("/invites", invites::routes())
|
||||
.mount("/custom", customisation::routes())
|
||||
.mount("/safety", safety::routes())
|
||||
.mount("/auth/account", rocket_authifier::routes::account::routes())
|
||||
.mount("/auth/session", rocket_authifier::routes::session::routes())
|
||||
.mount("/auth/mfa", rocket_authifier::routes::mfa::routes())
|
||||
.mount("/onboard", onboard::routes())
|
||||
.mount("/policy", policy::routes())
|
||||
.mount("/push", push::routes())
|
||||
.mount("/sync", sync::routes());
|
||||
|
||||
if config.features.webhooks_enabled {
|
||||
mount_endpoints_and_merged_docs! {
|
||||
rocket, "/".to_owned(), settings,
|
||||
"/" => (vec![], custom_openapi_spec()),
|
||||
"" => openapi_get_routes_spec![root::root],
|
||||
"/users" => users::routes(),
|
||||
"/bots" => bots::routes(),
|
||||
"/channels" => channels::routes(),
|
||||
"/servers" => servers::routes(),
|
||||
"/invites" => invites::routes(),
|
||||
"/custom" => customisation::routes(),
|
||||
"/safety" => safety::routes(),
|
||||
"/auth/account" => rocket_authifier::routes::account::routes(),
|
||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||
"/onboard" => onboard::routes(),
|
||||
"/policy" => policy::routes(),
|
||||
"/push" => push::routes(),
|
||||
"/sync" => sync::routes(),
|
||||
"/webhooks" => webhooks::routes()
|
||||
};
|
||||
} else {
|
||||
mount_endpoints_and_merged_docs! {
|
||||
rocket, "/".to_owned(), settings,
|
||||
"/" => (vec![], custom_openapi_spec()),
|
||||
"" => openapi_get_routes_spec![root::root],
|
||||
"/users" => users::routes(),
|
||||
"/bots" => bots::routes(),
|
||||
"/channels" => channels::routes(),
|
||||
"/servers" => servers::routes(),
|
||||
"/invites" => invites::routes(),
|
||||
"/custom" => customisation::routes(),
|
||||
"/safety" => safety::routes(),
|
||||
"/auth/account" => rocket_authifier::routes::account::routes(),
|
||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||
"/onboard" => onboard::routes(),
|
||||
"/policy" => policy::routes(),
|
||||
"/push" => push::routes(),
|
||||
"/sync" => sync::routes()
|
||||
};
|
||||
}
|
||||
|
||||
if config.features.webhooks_enabled {
|
||||
mount_endpoints_and_merged_docs! {
|
||||
rocket, "/0.8".to_owned(), settings,
|
||||
"/" => (vec![], custom_openapi_spec()),
|
||||
"" => openapi_get_routes_spec![root::root],
|
||||
"/users" => users::routes(),
|
||||
"/bots" => bots::routes(),
|
||||
"/channels" => channels::routes(),
|
||||
"/servers" => servers::routes(),
|
||||
"/invites" => invites::routes(),
|
||||
"/custom" => customisation::routes(),
|
||||
"/safety" => safety::routes(),
|
||||
"/auth/account" => rocket_authifier::routes::account::routes(),
|
||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||
"/onboard" => onboard::routes(),
|
||||
"/push" => push::routes(),
|
||||
"/sync" => sync::routes(),
|
||||
"/webhooks" => webhooks::routes()
|
||||
};
|
||||
} else {
|
||||
mount_endpoints_and_merged_docs! {
|
||||
rocket, "/0.8".to_owned(), settings,
|
||||
"/" => (vec![], custom_openapi_spec()),
|
||||
"" => openapi_get_routes_spec![root::root],
|
||||
"/users" => users::routes(),
|
||||
"/bots" => bots::routes(),
|
||||
"/channels" => channels::routes(),
|
||||
"/servers" => servers::routes(),
|
||||
"/invites" => invites::routes(),
|
||||
"/custom" => customisation::routes(),
|
||||
"/safety" => safety::routes(),
|
||||
"/auth/account" => rocket_authifier::routes::account::routes(),
|
||||
"/auth/session" => rocket_authifier::routes::session::routes(),
|
||||
"/auth/mfa" => rocket_authifier::routes::mfa::routes(),
|
||||
"/onboard" => onboard::routes(),
|
||||
"/push" => push::routes(),
|
||||
"/sync" => sync::routes()
|
||||
};
|
||||
}
|
||||
rocket = rocket.mount("/webhooks", webhooks::routes());
|
||||
};
|
||||
|
||||
rocket
|
||||
}
|
||||
|
||||
fn custom_openapi_spec() -> OpenApi {
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::*;
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "Stoat API",
|
||||
description = "Open source user-first chat platform.",
|
||||
terms_of_service = "https://stoat.chat/terms",
|
||||
contact(
|
||||
name = "Stoat Support",
|
||||
url = "https://stoat.chat",
|
||||
email = "contact@stoat.chat",
|
||||
),
|
||||
license(
|
||||
name = "AGPLv3",
|
||||
url = "https://github.com/stoatchat/stoatchat/blob/master/LICENSE",
|
||||
),
|
||||
),
|
||||
servers(
|
||||
(
|
||||
description = "Stoat Production",
|
||||
url = "https://stoat.chat/api",
|
||||
),
|
||||
(
|
||||
description = "Stoat Production",
|
||||
url = "https://api.stoat.chat"
|
||||
)
|
||||
),
|
||||
external_docs(
|
||||
url = "https://developers.stoat.chat",
|
||||
description = "Revolt Developer Documentation",
|
||||
),
|
||||
tags(
|
||||
(
|
||||
name = "Core",
|
||||
description = "Use in your applications to determine information about the Revolt node"
|
||||
),
|
||||
(
|
||||
name = "User Information",
|
||||
description = "Query and fetch users on Revolt"
|
||||
),
|
||||
(
|
||||
name = "Direct Messaging",
|
||||
description = "Direct message other users on Revolt"
|
||||
),
|
||||
(
|
||||
name = "Relationships",
|
||||
description = "Manage your friendships and block list on the platform"
|
||||
),
|
||||
(
|
||||
name = "Bots",
|
||||
description = "Create and edit bots"
|
||||
),
|
||||
(
|
||||
name = "Channel Information",
|
||||
description = "Query and fetch channels on Revolt"
|
||||
),
|
||||
(
|
||||
name = "Channel Invites",
|
||||
description = "Create and manage invites for channels"
|
||||
),
|
||||
(
|
||||
name = "Channel Permissions",
|
||||
description = "Manage permissions for channels"
|
||||
),
|
||||
(
|
||||
name = "Messaging",
|
||||
description = "Send and manipulate messages"
|
||||
),
|
||||
(
|
||||
name = "Groups",
|
||||
description = "Create, invite users and manipulate groups"
|
||||
),
|
||||
(
|
||||
name = "Voice",
|
||||
description = "Join and talk with other users"
|
||||
),
|
||||
(
|
||||
name = "Server Information",
|
||||
description = "Query and fetch servers on Revolt"
|
||||
),
|
||||
(
|
||||
name = "Server Members",
|
||||
description = "Find and edit server members"
|
||||
),
|
||||
(
|
||||
name = "Server Permissions",
|
||||
description = "Manage permissions for servers"
|
||||
),
|
||||
(
|
||||
name = "Invites",
|
||||
description = "View, join and delete invites"
|
||||
),
|
||||
(
|
||||
name = "Account",
|
||||
description = "Manage your account"
|
||||
),
|
||||
(
|
||||
name = "Session",
|
||||
description = "Create and manage sessions"
|
||||
),
|
||||
(
|
||||
name = "MFA",
|
||||
description = "Multi-factor Authentication"
|
||||
),
|
||||
(
|
||||
name = "Onboarding",
|
||||
description = "After signing up to Revolt, users must pick a unique username"
|
||||
),
|
||||
(
|
||||
name = "Sync",
|
||||
description = "Upload and retrieve any JSON data between clients"
|
||||
),
|
||||
(
|
||||
name = "Web Push",
|
||||
description = "Subscribe to and receive Revolt push notifications while offline"
|
||||
),
|
||||
(
|
||||
name = "Webhooks",
|
||||
description = "Send messages from 3rd party services"
|
||||
),
|
||||
),
|
||||
paths(
|
||||
root::root,
|
||||
),
|
||||
nest(
|
||||
(
|
||||
path = "/users",
|
||||
api = users::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/bots",
|
||||
api = bots::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/channels",
|
||||
api = channels::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/servers",
|
||||
api = servers::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/invites",
|
||||
api = invites::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/custom",
|
||||
api = customisation::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/safety",
|
||||
api = safety::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/auth/account",
|
||||
api = rocket_authifier::routes::account::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/auth/session",
|
||||
api = rocket_authifier::routes::session::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/auth/mfa",
|
||||
api = rocket_authifier::routes::mfa::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/onboard",
|
||||
api = onboard::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/policy",
|
||||
api = policy::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/push",
|
||||
api = push::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/sync",
|
||||
api = sync::ApiDoc,
|
||||
),
|
||||
(
|
||||
path = "/webhooks",
|
||||
api = webhooks::ApiDoc,
|
||||
),
|
||||
|
||||
let mut extensions = schemars::Map::new();
|
||||
extensions.insert(
|
||||
"x-logo".to_owned(),
|
||||
json!({
|
||||
"url": "https://revolt.chat/header.png",
|
||||
"altText": "Revolt Header"
|
||||
}),
|
||||
);
|
||||
),
|
||||
modifiers(
|
||||
&Extensions,
|
||||
&SecurityAddon,
|
||||
&TokenSecurity,
|
||||
),
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
extensions.insert(
|
||||
"x-tagGroups".to_owned(),
|
||||
json!([
|
||||
{
|
||||
"name": "Revolt",
|
||||
"tags": [
|
||||
"Core"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Users",
|
||||
"tags": [
|
||||
"User Information",
|
||||
"Direct Messaging",
|
||||
"Relationships"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Bots",
|
||||
"tags": [
|
||||
"Bots"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Channels",
|
||||
"tags": [
|
||||
"Channel Information",
|
||||
"Channel Invites",
|
||||
"Channel Permissions",
|
||||
"Messaging",
|
||||
"Interactions",
|
||||
"Groups",
|
||||
"Voice",
|
||||
"Webhooks",
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Servers",
|
||||
"tags": [
|
||||
"Server Information",
|
||||
"Server Members",
|
||||
"Server Permissions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Invites",
|
||||
"tags": [
|
||||
"Invites"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Customisation",
|
||||
"tags": [
|
||||
"Emojis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Platform Administration",
|
||||
"tags": [
|
||||
"Admin",
|
||||
"User Safety"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Authentication",
|
||||
"tags": [
|
||||
"Account",
|
||||
"Session",
|
||||
"Onboarding",
|
||||
"MFA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Miscellaneous",
|
||||
"tags": [
|
||||
"Sync",
|
||||
"Web Push"
|
||||
]
|
||||
}
|
||||
]),
|
||||
);
|
||||
|
||||
OpenApi {
|
||||
openapi: OpenApi::default_version(),
|
||||
info: Info {
|
||||
title: "Revolt API".to_owned(),
|
||||
description: Some("Open source user-first chat platform.".to_owned()),
|
||||
terms_of_service: Some("https://revolt.chat/terms".to_owned()),
|
||||
contact: Some(Contact {
|
||||
name: Some("Revolt Support".to_owned()),
|
||||
url: Some("https://revolt.chat".to_owned()),
|
||||
email: Some("contact@revolt.chat".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
license: Some(License {
|
||||
name: "AGPLv3".to_owned(),
|
||||
url: Some("https://github.com/revoltchat/delta/blob/master/LICENSE".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
servers: vec![
|
||||
Server {
|
||||
url: "https://api.revolt.chat".to_owned(),
|
||||
description: Some("Revolt Production".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Server {
|
||||
url: "https://revolt.chat/api".to_owned(),
|
||||
description: Some("Revolt Staging".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Server {
|
||||
url: "http://local.revolt.chat:14702".to_owned(),
|
||||
description: Some("Local Revolt Environment".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Server {
|
||||
url: "http://local.revolt.chat:14702/0.8".to_owned(),
|
||||
description: Some("Local Revolt Environment (v0.8)".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
external_docs: Some(ExternalDocs {
|
||||
url: "https://developers.revolt.chat".to_owned(),
|
||||
description: Some("Revolt Developer Documentation".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
extensions,
|
||||
tags: vec![
|
||||
Tag {
|
||||
name: "Core".to_owned(),
|
||||
description: Some(
|
||||
"Use in your applications to determine information about the Revolt node"
|
||||
.to_owned(),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "User Information".to_owned(),
|
||||
description: Some("Query and fetch users on Revolt".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Direct Messaging".to_owned(),
|
||||
description: Some("Direct message other users on Revolt".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Relationships".to_owned(),
|
||||
description: Some(
|
||||
"Manage your friendships and block list on the platform".to_owned(),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Bots".to_owned(),
|
||||
description: Some("Create and edit bots".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Channel Information".to_owned(),
|
||||
description: Some("Query and fetch channels on Revolt".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Channel Invites".to_owned(),
|
||||
description: Some("Create and manage invites for channels".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Channel Permissions".to_owned(),
|
||||
description: Some("Manage permissions for channels".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Messaging".to_owned(),
|
||||
description: Some("Send and manipulate messages".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Groups".to_owned(),
|
||||
description: Some("Create, invite users and manipulate groups".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Voice".to_owned(),
|
||||
description: Some("Join and talk with other users".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Server Information".to_owned(),
|
||||
description: Some("Query and fetch servers on Revolt".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Server Members".to_owned(),
|
||||
description: Some("Find and edit server members".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Server Permissions".to_owned(),
|
||||
description: Some("Manage permissions for servers".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Invites".to_owned(),
|
||||
description: Some("View, join and delete invites".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Account".to_owned(),
|
||||
description: Some("Manage your account".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Session".to_owned(),
|
||||
description: Some("Create and manage sessions".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "MFA".to_owned(),
|
||||
description: Some("Multi-factor Authentication".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Onboarding".to_owned(),
|
||||
description: Some(
|
||||
"After signing up to Revolt, users must pick a unique username".to_owned(),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Sync".to_owned(),
|
||||
description: Some("Upload and retrieve any JSON data between clients".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Web Push".to_owned(),
|
||||
description: Some(
|
||||
"Subscribe to and receive Revolt push notifications while offline".to_owned(),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
Tag {
|
||||
name: "Webhooks".to_owned(),
|
||||
description: Some("Send messages from 3rd party services".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
struct Extensions;
|
||||
impl Modify for Extensions {
|
||||
fn modify(&self, utoipa: &mut OpenApi) {
|
||||
utoipa.extensions = Some(
|
||||
ExtensionsBuilder::new()
|
||||
.add(
|
||||
"tagGroups",
|
||||
json!([
|
||||
{
|
||||
"name": "Revolt",
|
||||
"tags": [
|
||||
"Core"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Users",
|
||||
"tags": [
|
||||
"User Information",
|
||||
"Direct Messaging",
|
||||
"Relationships"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Bots",
|
||||
"tags": [
|
||||
"Bots"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Channels",
|
||||
"tags": [
|
||||
"Channel Information",
|
||||
"Channel Invites",
|
||||
"Channel Permissions",
|
||||
"Messaging",
|
||||
"Interactions",
|
||||
"Groups",
|
||||
"Voice",
|
||||
"Webhooks",
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Servers",
|
||||
"tags": [
|
||||
"Server Information",
|
||||
"Server Members",
|
||||
"Server Permissions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Invites",
|
||||
"tags": [
|
||||
"Invites"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Customisation",
|
||||
"tags": [
|
||||
"Emojis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Platform Administration",
|
||||
"tags": [
|
||||
"Admin",
|
||||
"User Safety"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Authentication",
|
||||
"tags": [
|
||||
"Account",
|
||||
"Session",
|
||||
"Onboarding",
|
||||
"MFA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Miscellaneous",
|
||||
"tags": [
|
||||
"Sync",
|
||||
"Web Push"
|
||||
]
|
||||
}
|
||||
]),
|
||||
)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use validator::Validate;
|
||||
pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
|
||||
|
||||
/// # New User Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Validate, Serialize, Deserialize, ToSchema)]
|
||||
pub struct DataOnboard {
|
||||
/// New username which will be used to identify the user on the platform
|
||||
#[validate(length(min = 2, max = 32), regex = "RE_USERNAME")]
|
||||
@@ -26,7 +26,7 @@ pub struct DataOnboard {
|
||||
/// # Complete Onboarding
|
||||
///
|
||||
/// This sets a new username, completes onboarding and allows a user to start using Revolt.
|
||||
#[openapi(tag = "Onboarding")]
|
||||
#[utoipa::path(tag = "Onboarding")]
|
||||
#[post("/complete", data = "<data>")]
|
||||
pub async fn complete(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -5,7 +5,7 @@ use rocket::serde::json::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
/// # Onboarding Status
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct DataHello {
|
||||
/// Whether onboarding is required
|
||||
onboarding: bool,
|
||||
@@ -14,7 +14,7 @@ pub struct DataHello {
|
||||
/// # 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.
|
||||
#[openapi(tag = "Onboarding")]
|
||||
#[utoipa::path(tag = "Onboarding")]
|
||||
#[get("/hello")]
|
||||
pub async fn hello(_session: Session, user: Option<User>) -> Json<DataHello> {
|
||||
Json(DataHello {
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod complete;
|
||||
mod hello;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![hello::hello, complete::complete]
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
hello::hello, complete::complete
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![hello::hello, complete::complete]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::State;
|
||||
/// # Acknowledge Policy Changes
|
||||
///
|
||||
/// Accept/acknowledge changes to platform policy.
|
||||
#[openapi(tag = "Policy")]
|
||||
#[utoipa::path(tag = "Policy")]
|
||||
#[post("/acknowledge")]
|
||||
pub async fn acknowledge_policy_changes(db: &State<Database>, user: User) -> Result<()> {
|
||||
db.acknowledge_policy_changes(&user.id).await
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod acknowledge_policy_changes;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
acknowledge_policy_changes::acknowledge_policy_changes
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
// Policy
|
||||
acknowledge_policy_changes::acknowledge_policy_changes,
|
||||
]
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod subscribe;
|
||||
mod unsubscribe;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![subscribe::subscribe, unsubscribe::unsubscribe]
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
subscribe::subscribe,
|
||||
unsubscribe::unsubscribe
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![subscribe::subscribe, unsubscribe::unsubscribe]
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// Create a new Web Push subscription.
|
||||
///
|
||||
/// If an existing subscription exists on this session, it will be removed.
|
||||
#[openapi(tag = "Web Push")]
|
||||
#[utoipa::path(tag = "Web Push")]
|
||||
#[post("/subscribe", data = "<data>")]
|
||||
pub async fn subscribe(
|
||||
authifier: &State<Authifier>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Unsubscribe
|
||||
///
|
||||
/// Remove the Web Push subscription associated with the current session.
|
||||
#[openapi(tag = "Web Push")]
|
||||
#[utoipa::path(tag = "Web Push")]
|
||||
#[post("/unsubscribe")]
|
||||
pub async fn unsubscribe(
|
||||
authifier: &State<Authifier>,
|
||||
|
||||
@@ -1,112 +1,34 @@
|
||||
use revolt_config::config;
|
||||
use revolt_models::v0;
|
||||
use revolt_result::Result;
|
||||
use rocket::serde::json::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
/// # hCaptcha Configuration
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct CaptchaFeature {
|
||||
/// Whether captcha is enabled
|
||||
pub enabled: bool,
|
||||
/// Client key used for solving captcha
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
/// # Generic Service Configuration
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct Feature {
|
||||
/// Whether the service is enabled
|
||||
pub enabled: bool,
|
||||
/// URL pointing to the service
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
/// # Voice Server Configuration
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct VoiceFeature {
|
||||
/// Whether voice is enabled
|
||||
pub enabled: bool,
|
||||
/// URL pointing to the voice API
|
||||
pub url: String,
|
||||
/// URL pointing to the voice WebSocket server
|
||||
pub ws: String,
|
||||
}
|
||||
|
||||
/// # Feature Configuration
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct RevoltFeatures {
|
||||
/// hCaptcha configuration
|
||||
pub captcha: CaptchaFeature,
|
||||
/// Whether email verification is enabled
|
||||
pub email: bool,
|
||||
/// Whether this server is invite only
|
||||
pub invite_only: bool,
|
||||
/// File server service configuration
|
||||
pub autumn: Feature,
|
||||
/// Proxy service configuration
|
||||
pub january: Feature,
|
||||
/// Voice server configuration
|
||||
pub voso: VoiceFeature,
|
||||
}
|
||||
|
||||
/// # Build Information
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct BuildInformation {
|
||||
/// Commit Hash
|
||||
pub commit_sha: String,
|
||||
/// Commit Timestamp
|
||||
pub commit_timestamp: String,
|
||||
/// Git Semver
|
||||
pub semver: String,
|
||||
/// Git Origin URL
|
||||
pub origin_url: String,
|
||||
/// Build Timestamp
|
||||
pub timestamp: String,
|
||||
}
|
||||
|
||||
/// # Server Configuration
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct RevoltConfig {
|
||||
/// Revolt API Version
|
||||
pub revolt: String,
|
||||
/// Features enabled on this Revolt node
|
||||
pub features: RevoltFeatures,
|
||||
/// WebSocket URL
|
||||
pub ws: String,
|
||||
/// URL pointing to the client serving this node
|
||||
pub app: String,
|
||||
/// Web Push VAPID public key
|
||||
pub vapid: String,
|
||||
/// Build information
|
||||
pub build: BuildInformation,
|
||||
}
|
||||
|
||||
/// # Query Node
|
||||
///
|
||||
/// Fetch the server configuration for this Revolt instance.
|
||||
#[openapi(tag = "Core")]
|
||||
#[utoipa::path(tag = "Core")]
|
||||
#[get("/")]
|
||||
pub async fn root() -> Result<Json<RevoltConfig>> {
|
||||
pub async fn root() -> Result<Json<v0::RevoltConfig>> {
|
||||
let config = config().await;
|
||||
|
||||
Ok(Json(RevoltConfig {
|
||||
Ok(Json(v0::RevoltConfig {
|
||||
revolt: env!("CARGO_PKG_VERSION").to_string(),
|
||||
features: RevoltFeatures {
|
||||
captcha: CaptchaFeature {
|
||||
features: v0::RevoltFeatures {
|
||||
captcha: v0::CaptchaFeature {
|
||||
enabled: !config.api.security.captcha.hcaptcha_key.is_empty(),
|
||||
key: config.api.security.captcha.hcaptcha_sitekey,
|
||||
},
|
||||
email: !config.api.smtp.host.is_empty(),
|
||||
invite_only: config.api.registration.invite_only,
|
||||
autumn: Feature {
|
||||
autumn: v0::Feature {
|
||||
enabled: !config.hosts.autumn.is_empty(),
|
||||
url: config.hosts.autumn,
|
||||
},
|
||||
january: Feature {
|
||||
january: v0::Feature {
|
||||
enabled: !config.hosts.january.is_empty(),
|
||||
url: config.hosts.january,
|
||||
},
|
||||
voso: VoiceFeature {
|
||||
voso: v0::VoiceFeature {
|
||||
enabled: !config.hosts.voso_legacy.is_empty(),
|
||||
url: config.hosts.voso_legacy,
|
||||
ws: config.hosts.voso_legacy_ws,
|
||||
@@ -115,7 +37,7 @@ pub async fn root() -> Result<Json<RevoltConfig>> {
|
||||
ws: config.hosts.events,
|
||||
app: config.hosts.app,
|
||||
vapid: config.pushd.vapid.public_key,
|
||||
build: BuildInformation {
|
||||
build: v0::BuildInformation {
|
||||
commit_sha: option_env!("VERGEN_GIT_SHA")
|
||||
.unwrap_or_else(|| "<failed to generate>")
|
||||
.to_string(),
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod report_content;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
report_content::report_content
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
// Reports
|
||||
report_content::report_content,
|
||||
]
|
||||
|
||||
@@ -8,7 +8,7 @@ use validator::Validate;
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Report Data
|
||||
#[derive(Validate, Deserialize, JsonSchema)]
|
||||
#[derive(Validate, Deserialize, ToSchema)]
|
||||
pub struct DataReportContent {
|
||||
/// Content being reported
|
||||
content: ReportedContent,
|
||||
@@ -21,7 +21,7 @@ pub struct DataReportContent {
|
||||
/// # Report Content
|
||||
///
|
||||
/// Report a piece of content to the moderation team.
|
||||
#[openapi(tag = "User Safety")]
|
||||
#[utoipa::path(tag = "User Safety")]
|
||||
#[post("/report", data = "<data>")]
|
||||
pub async fn report_content(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use validator::Validate;
|
||||
/// # Ban User
|
||||
///
|
||||
/// Ban a user by their id.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[put("/<server>/bans/<target>", data = "<data>")]
|
||||
pub async fn ban(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::State;
|
||||
/// # Fetch Bans
|
||||
///
|
||||
/// Fetch all bans on a server.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[get("/<target>/bans")]
|
||||
pub async fn list(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Unban user
|
||||
///
|
||||
/// Remove a user's ban.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[delete("/<server>/bans/<target>")]
|
||||
pub async fn unban(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use validator::Validate;
|
||||
/// # Create Channel
|
||||
///
|
||||
/// Create a new Text or Voice channel.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[post("/<server>/channels", data = "<data>")]
|
||||
pub async fn create_server_channel(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Server Emoji
|
||||
///
|
||||
/// Fetch all emoji on a server.
|
||||
#[openapi(tag = "Server Customisation")]
|
||||
#[utoipa::path(tag = "Server Customisation")]
|
||||
#[get("/<target>/emojis")]
|
||||
pub async fn list_emoji(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Invites
|
||||
///
|
||||
/// Fetch all server invites.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[get("/<target>/invites")]
|
||||
pub async fn invites(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -14,7 +14,7 @@ use validator::Validate;
|
||||
/// # Edit Member
|
||||
///
|
||||
/// Edit a member by their id.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[patch("/<server>/members/<member>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// # Query Parameters
|
||||
#[derive(Deserialize, JsonSchema, FromForm)]
|
||||
#[derive(Deserialize, ToSchema, FromForm)]
|
||||
pub struct OptionsQueryMembers {
|
||||
/// String to search for
|
||||
query: String,
|
||||
@@ -20,7 +20,7 @@ pub struct OptionsQueryMembers {
|
||||
}
|
||||
|
||||
/// # Query members by name
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct MemberQueryResponse {
|
||||
/// List of members
|
||||
members: Vec<v0::Member>,
|
||||
@@ -31,7 +31,7 @@ pub struct MemberQueryResponse {
|
||||
/// # Query members by name
|
||||
///
|
||||
/// Query members by a given name, this API is not stable and will be removed in the future.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[get("/<target>/members_experimental_query?<options..>")]
|
||||
pub async fn member_experimental_query(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Member
|
||||
///
|
||||
/// Retrieve a member.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[get("/<target>/members/<member>?<roles>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Members
|
||||
///
|
||||
/// Fetch all server members.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[get("/<target>/members?<options..>")]
|
||||
pub async fn fetch_all(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Kick Member
|
||||
///
|
||||
/// Removes a member from the server.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[utoipa::path(tag = "Server Members")]
|
||||
#[delete("/<target>/members/<member>")]
|
||||
pub async fn kick(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod ban_create;
|
||||
@@ -25,8 +24,38 @@ mod server_delete;
|
||||
mod server_edit;
|
||||
mod server_fetch;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
server_create::create_server,
|
||||
server_delete::delete,
|
||||
server_fetch::fetch,
|
||||
server_edit::edit,
|
||||
server_ack::ack,
|
||||
channel_create::create_server_channel,
|
||||
member_fetch_all::fetch_all,
|
||||
member_remove::kick,
|
||||
member_fetch::fetch,
|
||||
member_edit::edit,
|
||||
member_experimental_query::member_experimental_query,
|
||||
ban_create::ban,
|
||||
ban_remove::unban,
|
||||
ban_list::list,
|
||||
invites_fetch::invites,
|
||||
roles_create::create,
|
||||
roles_edit::edit,
|
||||
roles_fetch::fetch,
|
||||
roles_delete::delete,
|
||||
permissions_set::set_role_permission,
|
||||
permissions_set_default::set_default_server_permissions,
|
||||
emoji_list::list_emoji,
|
||||
roles_edit_positions::edit_role_ranks
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
server_create::create_server,
|
||||
server_delete::delete,
|
||||
server_fetch::fetch,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Set Role Permission
|
||||
///
|
||||
/// Sets permissions for the specified role in the server.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
|
||||
pub async fn set_role_permission(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Set Default Permission
|
||||
///
|
||||
/// Sets permissions for the default role in this server.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[put("/<target>/permissions/default", data = "<data>", rank = 1)]
|
||||
pub async fn set_default_server_permissions(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use validator::Validate;
|
||||
/// # Create Role
|
||||
///
|
||||
/// Creates a new server role.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[post("/<target>/roles", data = "<data>")]
|
||||
pub async fn create(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete Role
|
||||
///
|
||||
/// Delete a server role by its id.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[delete("/<target>/roles/<role_id>")]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use validator::Validate;
|
||||
/// # Edit Role
|
||||
///
|
||||
/// Edit a role by its id.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[patch("/<target>/roles/<role_id>", data = "<data>", rank = 1)]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Edits server roles ranks
|
||||
///
|
||||
/// Edit's server role's ranks.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[patch("/<target>/roles/ranks", data = "<data>")]
|
||||
pub async fn edit_role_ranks(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Role
|
||||
///
|
||||
/// Fetch a role by its id.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[utoipa::path(tag = "Server Permissions")]
|
||||
#[get("/<target>/roles/<role_id>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Mark Server As Read
|
||||
///
|
||||
/// Mark all channels in a server as read.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[put("/<target>/ack")]
|
||||
pub async fn ack(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> {
|
||||
if user.bot.is_some() {
|
||||
|
||||
@@ -9,7 +9,7 @@ use validator::Validate;
|
||||
/// # Create Server
|
||||
///
|
||||
/// Create a new server.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[post("/create", data = "<data>")]
|
||||
pub async fn create_server(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket_empty::EmptyResponse;
|
||||
/// # Delete / Leave Server
|
||||
///
|
||||
/// Deletes a server if owner otherwise leaves.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[delete("/<target>?<options..>")]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -13,7 +13,7 @@ use validator::Validate;
|
||||
/// # Edit Server
|
||||
///
|
||||
/// Edit a server by its id.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Server
|
||||
///
|
||||
/// Fetch a server by its id.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[utoipa::path(tag = "Server Information")]
|
||||
#[get("/<target>?<options..>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -9,7 +9,7 @@ use rocket::State;
|
||||
/// 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.
|
||||
#[openapi(tag = "Sync")]
|
||||
#[utoipa::path(tag = "Sync")]
|
||||
#[post("/settings/fetch", data = "<options>")]
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -7,7 +7,7 @@ use rocket::State;
|
||||
/// # Fetch Unreads
|
||||
///
|
||||
/// Fetch information about unread state on channels.
|
||||
#[openapi(tag = "Sync")]
|
||||
#[utoipa::path(tag = "Sync")]
|
||||
#[get("/unreads")]
|
||||
pub async fn unreads(db: &State<Database>, user: User) -> Result<Json<Vec<v0::ChannelUnread>>> {
|
||||
db.fetch_unreads(&user.id)
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod get_settings;
|
||||
mod get_unreads;
|
||||
mod set_settings;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![get_settings::fetch, set_settings::set, get_unreads::unreads]
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
get_settings::fetch,
|
||||
set_settings::set,
|
||||
get_unreads::unreads
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![get_settings::fetch, set_settings::set, get_unreads::unreads]
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type Data = HashMap<String, String>;
|
||||
/// # Set Settings
|
||||
///
|
||||
/// Upload data to save to settings.
|
||||
#[openapi(tag = "Sync")]
|
||||
#[utoipa::path(tag = "Sync")]
|
||||
#[post("/settings/set?<options..>", data = "<data>")]
|
||||
pub async fn set(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Accept Friend Request
|
||||
///
|
||||
/// Accept another user's friend request.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[utoipa::path(tag = "Relationships")]
|
||||
#[put("/<target>/friend")]
|
||||
pub async fn add(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Block User
|
||||
///
|
||||
/// Block another user by their id.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[utoipa::path(tag = "Relationships")]
|
||||
#[put("/<target>/block")]
|
||||
pub async fn block(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -15,7 +15,7 @@ use validator::Validate;
|
||||
pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
|
||||
|
||||
/// # Username Information
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Validate, Serialize, Deserialize, ToSchema)]
|
||||
pub struct DataChangeUsername {
|
||||
/// New username
|
||||
#[validate(length(min = 2, max = 32), regex = "RE_USERNAME")]
|
||||
@@ -28,7 +28,7 @@ pub struct DataChangeUsername {
|
||||
/// # Change Username
|
||||
///
|
||||
/// Change your username.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[patch("/@me/username", data = "<data>")]
|
||||
pub async fn change_username(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -9,7 +9,7 @@ use validator::Validate;
|
||||
/// # Edit User
|
||||
///
|
||||
/// Edit currently authenticated user.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch Direct Message Channels
|
||||
///
|
||||
/// This fetches your direct messages, including any DM and group DM conversations.
|
||||
#[openapi(tag = "Direct Messaging")]
|
||||
#[utoipa::path(tag = "Direct Messaging")]
|
||||
#[get("/dms")]
|
||||
pub async fn direct_messages(db: &State<Database>, user: User) -> Result<Json<Vec<v0::Channel>>> {
|
||||
db.find_direct_messages(&user.id)
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// Retrieve a user's profile data.
|
||||
///
|
||||
/// Will fail if you do not have permission to access the other user's profile.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[get("/<target>/profile")]
|
||||
pub async fn profile(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::serde::json::Json;
|
||||
/// # Fetch Self
|
||||
///
|
||||
/// Retrieve your user information.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[get("/@me")]
|
||||
pub async fn fetch(user: User) -> Result<Json<v0::User>> {
|
||||
Ok(Json(user.into_self(false).await))
|
||||
|
||||
@@ -11,9 +11,13 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch User
|
||||
///
|
||||
/// Retrieve a user's information.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[get("/<target>")]
|
||||
pub async fn fetch(db: &State<Database>, user: User, target: Reference<'_>) -> Result<Json<v0::User>> {
|
||||
pub async fn fetch(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
target: Reference<'_>,
|
||||
) -> Result<Json<v0::User>> {
|
||||
if user.id == target.id {
|
||||
return Ok(Json(user.into_self(false).await));
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// # Fetch User Flags
|
||||
///
|
||||
/// Retrieve a user's flags.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[get("/<target>/flags")]
|
||||
pub async fn fetch_user_flags(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -11,7 +11,7 @@ use rocket::State;
|
||||
/// # Fetch Mutual Friends, Servers, Groups and DMs
|
||||
///
|
||||
/// Retrieve a list of mutual friends, servers, groups and DMs with another user.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[utoipa::path(tag = "Relationships")]
|
||||
#[get("/<target>/mutual")]
|
||||
pub async fn mutual(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::{self, MediaType, RefOr};
|
||||
use rocket::http::ContentType;
|
||||
use rocket::response::{self, Responder};
|
||||
use rocket::{Request, Response};
|
||||
use schemars::schema::{InstanceType, SchemaObject, SingleOrVec};
|
||||
|
||||
pub struct CachedFile((ContentType, Vec<u8>));
|
||||
#[derive(ToSchema)]
|
||||
pub struct CachedFile(Vec<u8>);
|
||||
|
||||
pub static CACHE_CONTROL: &str = "public, max-age=31536000, immutable";
|
||||
|
||||
@@ -16,50 +15,15 @@ impl<'r> Responder<'r, 'static> for CachedFile {
|
||||
}
|
||||
}
|
||||
|
||||
impl revolt_rocket_okapi::response::OpenApiResponderInner for CachedFile {
|
||||
fn responses(
|
||||
_gen: &mut revolt_rocket_okapi::gen::OpenApiGenerator,
|
||||
) -> std::result::Result<openapi3::Responses, revolt_rocket_okapi::OpenApiError> {
|
||||
let mut responses = schemars::Map::new();
|
||||
let mut content = schemars::Map::new();
|
||||
|
||||
content.insert(
|
||||
"image/png".to_owned(),
|
||||
MediaType {
|
||||
schema: Some(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||
format: Some("binary".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
responses.insert(
|
||||
"200".to_string(),
|
||||
RefOr::Object(openapi3::Response {
|
||||
description: "Default Avatar Picture".to_string(),
|
||||
content,
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(openapi3::Responses {
|
||||
responses,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// # Fetch Default Avatar
|
||||
///
|
||||
/// This returns a default avatar based on the given id.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[utoipa::path(tag = "User Information")]
|
||||
#[get("/<target>/default_avatar")]
|
||||
pub async fn default_avatar(target: String) -> CachedFile {
|
||||
CachedFile((
|
||||
pub async fn default_avatar(target: String) -> (ContentType, CachedFile) {
|
||||
(
|
||||
ContentType::PNG,
|
||||
match target.chars().last().unwrap() {
|
||||
CachedFile(match target.chars().last().unwrap() {
|
||||
'0' | '1' | '2' | '3' | 'S' | 'Z' => include_bytes!("avatars/2.png").to_vec(),
|
||||
'4' | '5' | '6' | '7' | 'T' => include_bytes!("avatars/3.png").to_vec(),
|
||||
'8' | '9' | 'A' | 'B' => include_bytes!("avatars/4.png").to_vec(),
|
||||
@@ -67,6 +31,6 @@ pub async fn default_avatar(target: String) -> CachedFile {
|
||||
'G' | 'H' | 'J' | 'K' | 'W' => include_bytes!("avatars/6.png").to_vec(),
|
||||
'M' | 'N' | 'P' | 'Q' | 'X' => include_bytes!("avatars/7.png").to_vec(),
|
||||
_ => include_bytes!("avatars/1.png").to_vec(),
|
||||
},
|
||||
))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod add_friend;
|
||||
@@ -17,8 +16,30 @@ mod remove_friend;
|
||||
mod send_friend_request;
|
||||
mod unblock_user;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
fetch_self::fetch,
|
||||
fetch_user::fetch,
|
||||
fetch_user_flags::fetch_user_flags,
|
||||
edit_user::edit,
|
||||
change_username::change_username,
|
||||
get_default_avatar::default_avatar,
|
||||
fetch_profile::profile,
|
||||
fetch_dms::direct_messages,
|
||||
open_dm::open_dm,
|
||||
find_mutual::mutual,
|
||||
add_friend::add,
|
||||
remove_friend::remove,
|
||||
block_user::block,
|
||||
unblock_user::unblock,
|
||||
send_friend_request::send_friend_request,
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
// User Information
|
||||
fetch_self::fetch,
|
||||
fetch_user::fetch,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rocket::{serde::json::Json, State};
|
||||
/// Open a DM with another user.
|
||||
///
|
||||
/// If the target is oneself, a saved messages channel is returned.
|
||||
#[openapi(tag = "Direct Messaging")]
|
||||
#[utoipa::path(tag = "Direct Messaging")]
|
||||
#[get("/<target>/dm")]
|
||||
pub async fn open_dm(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Deny Friend Request / Remove Friend
|
||||
///
|
||||
/// Denies another user's friend request or removes an existing friend.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[utoipa::path(tag = "Relationships")]
|
||||
#[delete("/<target>/friend")]
|
||||
pub async fn remove(
|
||||
db: &State<Database>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use rocket::State;
|
||||
/// # Send Friend Request
|
||||
///
|
||||
/// Send a friend request to another user.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[utoipa::path(tag = "Relationships")]
|
||||
#[post("/friend", data = "<data>")]
|
||||
pub async fn send_friend_request(
|
||||
db: &State<Database>,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user