mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 05:26:59 +00:00
chore(doc): implement remainder of documentation
This commit is contained in:
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -2793,6 +2793,37 @@ dependencies = [
|
||||
"wither",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rauth"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/insertish/rauth?rev=611b11baa9e199bcefd0ca5bd3302f9d6904a2c6#611b11baa9e199bcefd0ca5bd3302f9d6904a2c6"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"base32",
|
||||
"chrono",
|
||||
"futures",
|
||||
"handlebars",
|
||||
"json",
|
||||
"lazy_static",
|
||||
"lettre",
|
||||
"mongodb 1.2.3",
|
||||
"nanoid",
|
||||
"okapi",
|
||||
"rand 0.8.4",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
"rocket_okapi",
|
||||
"rust-argon2",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"totp-lite",
|
||||
"ulid 0.4.1",
|
||||
"validator",
|
||||
"wither",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
@@ -2989,7 +3020,7 @@ dependencies = [
|
||||
"num_enum",
|
||||
"once_cell",
|
||||
"phf",
|
||||
"rauth",
|
||||
"rauth 1.0.0 (git+https://github.com/insertish/rauth?rev=611b11baa9e199bcefd0ca5bd3302f9d6904a2c6)",
|
||||
"redis 0.21.2",
|
||||
"regex",
|
||||
"reqwest",
|
||||
@@ -3029,7 +3060,7 @@ dependencies = [
|
||||
"ops",
|
||||
"optional_struct",
|
||||
"pretty_env_logger",
|
||||
"rauth",
|
||||
"rauth 1.0.0 (git+https://github.com/insertish/rauth?rev=501d445e7b42a1c229bfa88c01fa6415f4cb7992)",
|
||||
"redis-kiss",
|
||||
"rocket",
|
||||
"rocket_okapi",
|
||||
|
||||
@@ -50,7 +50,7 @@ async-std = { version = "1.8.0", features = ["tokio1", "tokio02", "attributes"]
|
||||
web-push = "0.7.2"
|
||||
many-to-many = "0.1.2"
|
||||
lettre = "0.10.0-alpha.4"
|
||||
rauth = { git = "https://github.com/insertish/rauth", rev = "501d445e7b42a1c229bfa88c01fa6415f4cb7992" }
|
||||
rauth = { git = "https://github.com/insertish/rauth", rev = "611b11baa9e199bcefd0ca5bd3302f9d6904a2c6" }
|
||||
hive_pubsub = { git = "https://gitlab.insrt.uk/insert/hive", rev = "b0f3db9d33990530d7640d4bbb309c8d9eb5c0cf", features = ["redis-backend"] }
|
||||
|
||||
# redis
|
||||
|
||||
@@ -22,6 +22,8 @@ pub struct DataEditBot {
|
||||
/// Whether the bot can be added by anyone
|
||||
public: Option<bool>,
|
||||
/// Whether analytics should be gathered for this bot
|
||||
///
|
||||
/// Must be enabled in order to show up on [Revolt Discover](https://rvlt.gg).
|
||||
analytics: Option<bool>,
|
||||
/// Interactions URL
|
||||
#[validate(length(min = 1, max = 2048))]
|
||||
@@ -36,7 +38,12 @@ pub struct DataEditBot {
|
||||
/// Edit bot details by its id.
|
||||
#[openapi(tag = "Bots")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit_bot(db: &Db, user: User, target: Ref, data: Json<DataEditBot>) -> Result<Json<Bot>> {
|
||||
pub async fn edit_bot(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
data: Json<DataEditBot>,
|
||||
) -> Result<Json<Bot>> {
|
||||
if user.bot.is_some() {
|
||||
return Err(Error::IsBot);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::util::idempotency::IdempotencyKey;
|
||||
pub struct DataMessageSend {
|
||||
/// Unique token to prevent duplicate message sending
|
||||
///
|
||||
/// **This is deprecated and replaced by Idempotency-Token!**
|
||||
/// **This is deprecated and replaced by `Idempotency-Key`!**
|
||||
nonce: Option<String>,
|
||||
|
||||
/// Message content to send
|
||||
|
||||
@@ -3,6 +3,10 @@ use revolt_quark::{
|
||||
perms, Db, EmptyResponse, Permission, Ref, Result,
|
||||
};
|
||||
|
||||
/// # Delete Invite
|
||||
///
|
||||
/// Delete an invite by its id.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
|
||||
let invite = target.as_invite(db).await?;
|
||||
|
||||
@@ -4,37 +4,59 @@ use revolt_quark::{Db, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
/// # Invite
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[derive(Serialize, Debug, Clone, JsonSchema)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum InviteResponse {
|
||||
/// Server channel invite
|
||||
Server {
|
||||
/// Id of the server
|
||||
server_id: String,
|
||||
/// Name of the server
|
||||
server_name: String,
|
||||
/// Attachment for server icon
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
server_icon: Option<File>,
|
||||
/// Attachment for server banner
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
server_banner: Option<File>,
|
||||
/// Id of server channel
|
||||
channel_id: String,
|
||||
/// Name of server channel
|
||||
channel_name: String,
|
||||
/// Description of server channel
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
channel_description: Option<String>,
|
||||
/// Name of user who created the invite
|
||||
user_name: String,
|
||||
/// Avatar of the user who created the invite
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
user_avatar: Option<File>,
|
||||
/// Number of members in this server
|
||||
member_count: i64,
|
||||
},
|
||||
/// Group channel invite
|
||||
Group {
|
||||
/// Id of group channel
|
||||
channel_id: String,
|
||||
/// Name of group channel
|
||||
channel_name: String,
|
||||
/// Description of group channel
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
channel_description: Option<String>,
|
||||
/// Name of user who created the invite
|
||||
user_name: String,
|
||||
/// Avatar of the user who created the invite
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
user_avatar: Option<File>,
|
||||
},
|
||||
}
|
||||
|
||||
/// # Fetch Invite
|
||||
///
|
||||
/// Fetch an invite by its id.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[get("/<target>")]
|
||||
pub async fn req(db: &Db, target: Ref) -> Result<Json<InviteResponse>> {
|
||||
Ok(Json(match target.as_invite(db).await? {
|
||||
|
||||
@@ -7,6 +7,10 @@ use rocket::serde::json::Value;
|
||||
|
||||
use crate::util::variables::MAX_SERVER_COUNT;
|
||||
|
||||
/// # Join Invite
|
||||
///
|
||||
/// Join an invite by its ID.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[post("/<target>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Value> {
|
||||
if user.bot.is_some() {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod invite_delete;
|
||||
mod invite_fetch;
|
||||
mod invite_join;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![invite_fetch::req, invite_join::req, invite_delete::req]
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![invite_fetch::req, invite_join::req, invite_delete::req]
|
||||
}
|
||||
|
||||
@@ -20,19 +20,19 @@ pub fn mount(mut rocket: Rocket<Build>) -> Rocket<Build> {
|
||||
rocket, "/".to_owned(), settings,
|
||||
"/" => (vec![], custom_openapi_spec()),
|
||||
"" => openapi_get_routes_spec![root::root, root::ping],
|
||||
"/users" => users::routes(),
|
||||
"/bots" => bots::routes(),
|
||||
"/channels" => channels::routes(),
|
||||
"/servers" => servers::routes(),
|
||||
"/invites" => invites::routes(),
|
||||
"/auth/account" => rauth::web::account::routes(),
|
||||
"/auth/session" => rauth::web::session::routes(),
|
||||
"/onboard" => onboard::routes(),
|
||||
"/push" => push::routes(),
|
||||
"/sync" => sync::routes(),
|
||||
};
|
||||
|
||||
rocket
|
||||
.mount("/auth/account", rauth::web::account::routes())
|
||||
.mount("/auth/session", rauth::web::session::routes())
|
||||
.mount("/onboard", onboard::routes())
|
||||
.mount("/users", users::routes())
|
||||
.mount("/servers", servers::routes())
|
||||
.mount("/invites", invites::routes())
|
||||
.mount("/push", push::routes())
|
||||
.mount("/sync", sync::routes())
|
||||
}
|
||||
|
||||
fn custom_openapi_spec() -> OpenApi {
|
||||
@@ -51,7 +51,9 @@ fn custom_openapi_spec() -> OpenApi {
|
||||
openapi: OpenApi::default_version(),
|
||||
info: Info {
|
||||
title: "Revolt API".to_owned(),
|
||||
description: Some("User-first privacy focused chat platform.".to_owned()),
|
||||
description: Some(
|
||||
"User-first privacy focused chat platform.\n\n<!-- ReDoc-Inject: <security-definitions> -->".to_owned(),
|
||||
),
|
||||
terms_of_service: Some("https://revolt.chat/terms".to_owned()),
|
||||
contact: Some(Contact {
|
||||
name: Some("Revolt Support".to_owned()),
|
||||
@@ -71,8 +73,24 @@ fn custom_openapi_spec() -> OpenApi {
|
||||
url: "https://api.revolt.chat".to_owned(),
|
||||
description: Some("Revolt API".to_owned()),
|
||||
..Default::default()
|
||||
}, Server {
|
||||
url: "http://local.revolt.chat:8000".to_owned(),
|
||||
description: Some("Local Revolt Environment".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: "aaa".to_owned(),
|
||||
description: Some("aaa".to_owned()),
|
||||
..Default::default()
|
||||
}
|
||||
],*/
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,24 @@ use rocket::{serde::json::Json, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # New User Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
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")]
|
||||
username: String,
|
||||
}
|
||||
|
||||
/// # Complete Onboarding
|
||||
///
|
||||
/// This sets a new username, completes onboarding and allows a user to start using Revolt.
|
||||
#[openapi(tag = "Onboarding")]
|
||||
#[post("/complete", data = "<data>")]
|
||||
pub async fn req(
|
||||
db: &State<Database>,
|
||||
session: Session,
|
||||
user: Option<User>,
|
||||
data: Json<Data>,
|
||||
data: Json<DataOnboard>,
|
||||
) -> Result<EmptyResponse> {
|
||||
if user.is_some() {
|
||||
return Err(Error::AlreadyOnboarded);
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
use rauth::entities::Session;
|
||||
use revolt_quark::models::User;
|
||||
use rocket::serde::json::Value;
|
||||
use rocket::serde::json::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
/// # Onboarding Status
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
pub struct DataHello {
|
||||
/// Whether onboarding is required
|
||||
onboarding: bool,
|
||||
}
|
||||
|
||||
/// # 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")]
|
||||
#[get("/hello")]
|
||||
pub async fn req(_session: Session, user: Option<User>) -> Value {
|
||||
json!({
|
||||
"onboarding": user.is_none()
|
||||
pub async fn req(_session: Session, user: Option<User>) -> Json<DataHello> {
|
||||
Json(DataHello {
|
||||
onboarding: user.is_none(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod complete;
|
||||
mod hello;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![hello::req, complete::req]
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![hello::req, complete::req]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod subscribe;
|
||||
mod unsubscribe;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![subscribe::req, unsubscribe::req]
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![subscribe::req, unsubscribe::req]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ use rauth::{
|
||||
};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Push Subscribe
|
||||
///
|
||||
/// Create a new Web Push subscription.
|
||||
///
|
||||
/// If an existing subscription exists on this session, it will be removed.
|
||||
#[openapi(tag = "Web Push")]
|
||||
#[post("/subscribe", data = "<data>")]
|
||||
pub async fn req(
|
||||
auth: &State<Auth>,
|
||||
|
||||
@@ -6,6 +6,10 @@ use rauth::{
|
||||
};
|
||||
use rocket::State;
|
||||
|
||||
/// # Unsubscribe
|
||||
///
|
||||
/// Remove the Web Push subscription associated with the current session.
|
||||
#[openapi(tag = "Web Push")]
|
||||
#[post("/unsubscribe")]
|
||||
pub async fn req(auth: &State<Auth>, mut session: Session) -> Result<EmptyResponse> {
|
||||
session.subscription = None;
|
||||
|
||||
@@ -7,19 +7,25 @@ use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Ban Information
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataBanCreate {
|
||||
/// Ban reason
|
||||
#[validate(length(min = 1, max = 1024))]
|
||||
reason: Option<String>,
|
||||
}
|
||||
|
||||
/// # Ban User
|
||||
///
|
||||
/// Ban a user by their id.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[put("/<server>/bans/<target>", data = "<data>")]
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
server: Ref,
|
||||
target: Ref,
|
||||
data: Json<Data>,
|
||||
data: Json<DataBanCreate>,
|
||||
) -> Result<Json<ServerBan>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
|
||||
@@ -4,20 +4,33 @@ use revolt_quark::{perms, Db, Permission, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// # Banned User
|
||||
///
|
||||
/// Just enoguh user information to list bans.
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
struct BannedUser {
|
||||
/// Id of the banned user
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
/// Username of the banned user
|
||||
pub username: String,
|
||||
/// Avatar of the banned user
|
||||
pub avatar: Option<File>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// # Ban List Result
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct BanListResult {
|
||||
/// Users objects
|
||||
users: Vec<BannedUser>,
|
||||
/// Ban objects
|
||||
bans: Vec<ServerBan>,
|
||||
}
|
||||
|
||||
/// # Fetch Bans
|
||||
///
|
||||
/// Fetch all bans on a server.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[get("/<target>/bans")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<BanListResult>> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::User, perms, Db, EmptyResponse, Permission, Ref, Result};
|
||||
|
||||
/// # Unban user
|
||||
///
|
||||
/// Remove a user's ban.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[delete("/<server>/bans/<target>")]
|
||||
pub async fn req(db: &Db, user: User, server: Ref, target: Ref) -> Result<EmptyResponse> {
|
||||
let server = server.as_server(db).await?;
|
||||
|
||||
@@ -10,9 +10,12 @@ use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// # Channel Type
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
enum ChannelType {
|
||||
/// Text Channel
|
||||
Text,
|
||||
/// Voice Channel
|
||||
Voice,
|
||||
}
|
||||
|
||||
@@ -22,20 +25,34 @@ impl Default for ChannelType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Channel Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataCreateChannel {
|
||||
/// Channel type
|
||||
#[serde(rename = "type", default = "ChannelType::default")]
|
||||
channel_type: ChannelType,
|
||||
/// Channel name
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: String,
|
||||
/// Channel description
|
||||
#[validate(length(min = 0, max = 1024))]
|
||||
description: Option<String>,
|
||||
/// Whether this channel is age restricted
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
nsfw: Option<bool>,
|
||||
}
|
||||
|
||||
/// # Create Channel
|
||||
///
|
||||
/// Create a new Text or Voice channel.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[post("/<target>/channels", data = "<info>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, info: Json<Data>) -> Result<Json<Channel>> {
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
info: Json<DataCreateChannel>,
|
||||
) -> Result<Json<Channel>> {
|
||||
let info = info.into_inner();
|
||||
info.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
@@ -50,7 +67,7 @@ pub async fn req(db: &Db, user: User, target: Ref, info: Json<Data>) -> Result<J
|
||||
let mut channels = server.channels.clone();
|
||||
channels.push(id.clone());
|
||||
|
||||
let Data {
|
||||
let DataCreateChannel {
|
||||
name,
|
||||
description,
|
||||
nsfw,
|
||||
|
||||
@@ -4,16 +4,11 @@ use revolt_quark::{
|
||||
};
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ServerInvite {
|
||||
#[serde(rename = "_id")]
|
||||
code: String,
|
||||
creator: String,
|
||||
channel: String,
|
||||
}
|
||||
|
||||
/// # Fetch Invites
|
||||
///
|
||||
/// Fetch all server invites.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[get("/<target>/invites")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<Vec<Invite>>> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -10,23 +10,32 @@ use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Member Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataMemberEdit {
|
||||
/// Member nickname
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
nickname: Option<String>,
|
||||
/// Attachment Id to set for avatar
|
||||
avatar: Option<String>,
|
||||
/// Array of role ids
|
||||
roles: Option<Vec<String>>,
|
||||
/// Fields to remove from channel object
|
||||
#[validate(length(min = 1))]
|
||||
remove: Option<Vec<FieldsMember>>,
|
||||
}
|
||||
|
||||
/// # Edit Member
|
||||
///
|
||||
/// Edit a member by their id.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[patch("/<server>/members/<target>", data = "<data>")]
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
server: Ref,
|
||||
target: Ref,
|
||||
data: Json<Data>,
|
||||
data: Json<DataMemberEdit>,
|
||||
) -> Result<Json<Member>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
@@ -37,7 +46,7 @@ pub async fn req(
|
||||
|
||||
let mut member = target.as_member(db, &server.id).await?;
|
||||
|
||||
let Data {
|
||||
let DataMemberEdit {
|
||||
nickname,
|
||||
avatar,
|
||||
roles,
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{
|
||||
};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Member
|
||||
///
|
||||
/// Retrieve a member.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[get("/<target>/members/<member>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, member: Ref) -> Result<Json<Member>> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -2,12 +2,16 @@ use revolt_quark::{models::User, perms, presence::presence_filter_online, Db, Re
|
||||
|
||||
use rocket::serde::json::Value;
|
||||
|
||||
/// # Fetch Members
|
||||
///
|
||||
/// Fetch all server members.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[get("/<target>/members")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Value> {
|
||||
let server = target.as_server(db).await?;
|
||||
perms(&user).server(&server).calc(db).await?;
|
||||
|
||||
let members = db.fetch_all_members(&server.id).await?;
|
||||
let mut members = db.fetch_all_members(&server.id).await?;
|
||||
|
||||
let mut user_ids = vec![];
|
||||
for member in &members {
|
||||
@@ -15,7 +19,7 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<Value> {
|
||||
}
|
||||
|
||||
let online_ids = presence_filter_online(&user_ids).await;
|
||||
let users = db
|
||||
let mut users = db
|
||||
.fetch_users(&user_ids)
|
||||
.await?
|
||||
.into_iter()
|
||||
@@ -25,6 +29,10 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<Value> {
|
||||
})
|
||||
.collect::<Vec<User>>();
|
||||
|
||||
// Ensure the lists match up exactly.
|
||||
members.sort_by(|a, b| a.id.user.cmp(&b.id.user));
|
||||
users.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
|
||||
Ok(json!({
|
||||
"members": members,
|
||||
"users": users
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::User, perms, Db, EmptyResponse, Error, Permission, Ref, Result};
|
||||
|
||||
/// # Kick Member
|
||||
///
|
||||
/// Removes a member from the server.
|
||||
#[openapi(tag = "Server Members")]
|
||||
#[delete("/<target>/members/<member>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, member: Ref) -> Result<EmptyResponse> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod server_ack;
|
||||
mod server_create;
|
||||
@@ -25,8 +26,8 @@ mod roles_create;
|
||||
mod roles_delete;
|
||||
mod roles_edit;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
server_create::req,
|
||||
server_delete::req,
|
||||
server_fetch::req,
|
||||
|
||||
@@ -6,18 +6,24 @@ use revolt_quark::{
|
||||
perms, Db, Error, Override, Permission, Ref, Result,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Permission Value
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct DataSetServerRolePermission {
|
||||
/// Allow / deny values for the role in this server.
|
||||
permissions: Override,
|
||||
}
|
||||
|
||||
/// # Set Role Permission
|
||||
///
|
||||
/// Sets permissions for the specified role in the server.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
role_id: String,
|
||||
data: Json<Data>,
|
||||
data: Json<DataSetServerRolePermission>,
|
||||
) -> Result<Json<Server>> {
|
||||
let data = data.into_inner();
|
||||
|
||||
|
||||
@@ -6,13 +6,24 @@ use revolt_quark::{
|
||||
perms, Db, Permission, Ref, Result,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Permission Value
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct DataSetServerDefaultPermission {
|
||||
/// Default member permission value
|
||||
permissions: u64,
|
||||
}
|
||||
|
||||
/// # Set Default Permission
|
||||
///
|
||||
/// Sets permissions for the default role in this server.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[put("/<target>/permissions/default", data = "<data>", rank = 1)]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<Json<Server>> {
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
data: Json<DataSetServerDefaultPermission>,
|
||||
) -> Result<Json<Server>> {
|
||||
let data = data.into_inner();
|
||||
|
||||
let mut server = target.as_server(db).await?;
|
||||
|
||||
@@ -7,15 +7,24 @@ use rocket::serde::json::{Json, Value};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Role Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataCreateRole {
|
||||
/// Role name
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: String,
|
||||
/// Ranking position
|
||||
///
|
||||
/// Smaller values take priority.
|
||||
rank: Option<i64>,
|
||||
}
|
||||
|
||||
/// # Create Role
|
||||
///
|
||||
/// Creates a new server role.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[post("/<target>/roles", data = "<data>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<Value> {
|
||||
pub async fn req(db: &Db, user: User, target: Ref, data: Json<DataCreateRole>) -> Result<Value> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::User, perms, Db, EmptyResponse, Error, Permission, Ref, Result};
|
||||
|
||||
/// # Delete Role
|
||||
///
|
||||
/// Delete a server role by its id.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[delete("/<target>/roles/<role_id>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, role_id: String) -> Result<EmptyResponse> {
|
||||
let mut server = target.as_server(db).await?;
|
||||
|
||||
@@ -10,25 +10,37 @@ use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Role Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataEditRole {
|
||||
/// Role name
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: Option<String>,
|
||||
/// Role colour
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
colour: Option<String>,
|
||||
/// Whether this role should be displayed separately
|
||||
hoist: Option<bool>,
|
||||
/// Ranking position
|
||||
///
|
||||
/// Smaller values take priority.
|
||||
rank: Option<i64>,
|
||||
/// Fields to remove from role object
|
||||
#[validate(length(min = 1))]
|
||||
remove: Option<Vec<FieldsRole>>,
|
||||
}
|
||||
|
||||
/// # Edit Role
|
||||
///
|
||||
/// Edit a role by its id.
|
||||
#[openapi(tag = "Server Permissions")]
|
||||
#[patch("/<target>/roles/<role_id>", data = "<data>")]
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
role_id: String,
|
||||
data: Json<Data>,
|
||||
data: Json<DataEditRole>,
|
||||
) -> Result<Json<Role>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
@@ -44,7 +56,7 @@ pub async fn req(
|
||||
let member_rank = permissions.get_member_rank().unwrap_or(i64::MIN);
|
||||
|
||||
if let Some(mut role) = server.roles.remove(&role_id) {
|
||||
let Data {
|
||||
let DataEditRole {
|
||||
name,
|
||||
colour,
|
||||
hoist,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::User, perms, Db, EmptyResponse, Ref, Result};
|
||||
|
||||
/// # Mark Server As Read
|
||||
///
|
||||
/// Mark all channels in a server as read.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[put("/<target>/ack")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -12,18 +12,26 @@ use validator::Validate;
|
||||
|
||||
use crate::util::variables::MAX_SERVER_COUNT;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Server Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataCreateServer {
|
||||
/// Server name
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: String,
|
||||
/// Server description
|
||||
#[validate(length(min = 0, max = 1024))]
|
||||
description: Option<String>,
|
||||
/// Whether this server is age-restricted
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
nsfw: Option<bool>,
|
||||
}
|
||||
|
||||
/// # Create Server
|
||||
///
|
||||
/// Create a new server.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[post("/create", data = "<info>")]
|
||||
pub async fn req(db: &Db, user: User, info: Json<Data>) -> Result<Json<Server>> {
|
||||
pub async fn req(db: &Db, user: User, info: Json<DataCreateServer>) -> Result<Json<Server>> {
|
||||
let info = info.into_inner();
|
||||
info.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
@@ -34,7 +42,7 @@ pub async fn req(db: &Db, user: User, info: Json<Data>) -> Result<Json<Server>>
|
||||
});
|
||||
}
|
||||
|
||||
let Data {
|
||||
let DataCreateServer {
|
||||
name,
|
||||
description,
|
||||
nsfw,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::User, Db, EmptyResponse, Ref, Result};
|
||||
|
||||
/// # Delete / Leave Server
|
||||
///
|
||||
/// Deletes a server if owner otherwise leaves.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -10,29 +10,50 @@ use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Server Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataEditServer {
|
||||
/// Server name
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: Option<String>,
|
||||
/// Server description
|
||||
#[validate(length(min = 0, max = 1024))]
|
||||
description: Option<String>,
|
||||
|
||||
/// Attachment Id for icon
|
||||
icon: Option<String>,
|
||||
/// Attachment Id for banner
|
||||
banner: Option<String>,
|
||||
|
||||
/// Category structure for server
|
||||
#[validate]
|
||||
categories: Option<Vec<Category>>,
|
||||
/// System message configuration
|
||||
system_messages: Option<SystemMessageChannels>,
|
||||
|
||||
nsfw: Option<bool>,
|
||||
// Whether this server is age-restricted
|
||||
// nsfw: Option<bool>,
|
||||
/// Whether analytics should be collected for this server
|
||||
///
|
||||
/// Must be enabled in order to show up on [Revolt Discover](https://rvlt.gg).
|
||||
analytics: Option<bool>,
|
||||
|
||||
/// Fields to remove from server object
|
||||
#[validate(length(min = 1))]
|
||||
remove: Option<Vec<FieldsServer>>,
|
||||
}
|
||||
|
||||
/// # Edit Server
|
||||
///
|
||||
/// Edit a server by its id.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<Json<Server>> {
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
data: Json<DataEditServer>,
|
||||
) -> Result<Json<Server>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
@@ -48,7 +69,7 @@ pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<J
|
||||
&& data.banner.is_none()
|
||||
&& data.system_messages.is_none()
|
||||
&& data.categories.is_none()
|
||||
&& data.nsfw.is_none()
|
||||
// && data.nsfw.is_none()
|
||||
&& data.analytics.is_none()
|
||||
&& data.remove.is_none()
|
||||
{
|
||||
@@ -58,7 +79,7 @@ pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<J
|
||||
|| data.icon.is_some()
|
||||
|| data.banner.is_some()
|
||||
|| data.system_messages.is_some()
|
||||
|| data.nsfw.is_some()
|
||||
// || data.nsfw.is_some()
|
||||
|| data.analytics.is_some()
|
||||
|| data.remove.is_some()
|
||||
{
|
||||
@@ -73,14 +94,14 @@ pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<J
|
||||
.await?;
|
||||
}
|
||||
|
||||
let Data {
|
||||
let DataEditServer {
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
banner,
|
||||
categories,
|
||||
system_messages,
|
||||
nsfw,
|
||||
// nsfw,
|
||||
analytics,
|
||||
remove,
|
||||
} = data;
|
||||
@@ -90,7 +111,7 @@ pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<J
|
||||
description,
|
||||
categories,
|
||||
system_messages,
|
||||
nsfw,
|
||||
// nsfw,
|
||||
analytics,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{
|
||||
};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Server
|
||||
///
|
||||
/// Fetch a server by its id.
|
||||
#[openapi(tag = "Server Information")]
|
||||
#[get("/<target>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<Server>> {
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
@@ -6,13 +6,25 @@ use revolt_quark::{
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Options {
|
||||
/// # Fetch Options
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OptionsFetchSettings {
|
||||
/// Keys to fetch
|
||||
keys: Vec<String>,
|
||||
}
|
||||
|
||||
/// # Fetch Settings
|
||||
///
|
||||
/// 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")]
|
||||
#[post("/settings/fetch", data = "<options>")]
|
||||
pub async fn req(db: &Db, user: User, options: Json<Options>) -> Result<Json<UserSettings>> {
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
options: Json<OptionsFetchSettings>,
|
||||
) -> Result<Json<UserSettings>> {
|
||||
db.fetch_user_settings(&user.id, &options.into_inner().keys)
|
||||
.await
|
||||
.map(Json)
|
||||
|
||||
@@ -5,6 +5,10 @@ use revolt_quark::{
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Unreads
|
||||
///
|
||||
/// Fetch information about unread state on channels.
|
||||
#[openapi(tag = "Sync")]
|
||||
#[get("/unreads")]
|
||||
pub async fn req(db: &Db, user: User) -> Result<Json<Vec<ChannelUnread>>> {
|
||||
db.fetch_unreads(&user.id).await.map(Json)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod get_settings;
|
||||
mod get_unreads;
|
||||
mod set_settings;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![get_settings::req, set_settings::req, get_unreads::req]
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![get_settings::req, set_settings::req, get_unreads::req]
|
||||
}
|
||||
|
||||
@@ -9,13 +9,26 @@ use std::collections::HashMap;
|
||||
|
||||
type Data = HashMap<String, String>;
|
||||
|
||||
#[derive(FromForm, Serialize, Deserialize)]
|
||||
pub struct Options {
|
||||
/// # Set Options
|
||||
#[derive(FromForm, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OptionsSetSettings {
|
||||
/// Timestamp of settings change.
|
||||
///
|
||||
/// Used to avoid feedback loops.
|
||||
timestamp: Option<i64>,
|
||||
}
|
||||
|
||||
/// # Set Settings
|
||||
///
|
||||
/// Upload data to save to settings.
|
||||
#[openapi(tag = "Sync")]
|
||||
#[post("/settings/set?<options..>", data = "<data>")]
|
||||
pub async fn req(db: &Db, user: User, data: Json<Data>, options: Options) -> Result<EmptyResponse> {
|
||||
pub async fn req(
|
||||
db: &Db,
|
||||
user: User,
|
||||
data: Json<Data>,
|
||||
options: OptionsSetSettings,
|
||||
) -> Result<EmptyResponse> {
|
||||
let data = data.into_inner();
|
||||
let current_time = Utc::now().timestamp_millis();
|
||||
let timestamp = if let Some(timestamp) = options.timestamp {
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{Database, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
|
||||
/// # Send Friend Request / Accept Request
|
||||
///
|
||||
/// Send a friend request to another user or accept another user's friend request.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[put("/<username>/friend")]
|
||||
pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> {
|
||||
let mut target = db.fetch_user_by_username(&username).await?;
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{Database, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
|
||||
/// # Block User
|
||||
///
|
||||
/// Block another user by their id.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[put("/<target>/block")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: String) -> Result<Json<User>> {
|
||||
let mut target = db.fetch_user(&target).await?;
|
||||
|
||||
@@ -5,20 +5,27 @@ use rocket::{serde::json::Json, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # Username Information
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataChangeUsername {
|
||||
/// New username
|
||||
#[validate(length(min = 2, max = 32), regex = "RE_USERNAME")]
|
||||
username: String,
|
||||
/// Current account password
|
||||
#[validate(length(min = 8, max = 1024))]
|
||||
password: String,
|
||||
}
|
||||
|
||||
/// # Change Username
|
||||
///
|
||||
/// Change your username.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[patch("/@me/username", data = "<data>")]
|
||||
pub async fn req(
|
||||
db: &State<Database>,
|
||||
account: Account,
|
||||
mut user: User,
|
||||
data: Json<Data>,
|
||||
data: Json<DataChangeUsername>,
|
||||
) -> Result<Json<User>> {
|
||||
let data = data.into_inner();
|
||||
account
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Edit currently authenticated user.
|
||||
|
||||
use revolt_quark::models::user::{FieldsUser, PartialUser, User};
|
||||
use revolt_quark::models::File;
|
||||
use revolt_quark::{Database, Error, Result};
|
||||
@@ -10,30 +8,48 @@ use rocket::State;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize, Debug)]
|
||||
/// # Profile Data
|
||||
#[derive(Validate, Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct UserProfileData {
|
||||
/// Text to set as user profile description
|
||||
#[validate(length(min = 0, max = 2000))]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
content: Option<String>,
|
||||
/// Attachment Id for background
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
background: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// # User Data
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct DataEditUser {
|
||||
/// New user status
|
||||
#[validate]
|
||||
status: Option<UserStatus>,
|
||||
/// New user profile data
|
||||
///
|
||||
/// This is applied as a partial.
|
||||
#[validate]
|
||||
profile: Option<UserProfileData>,
|
||||
/// Attachment Id for avatar
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
avatar: Option<String>,
|
||||
/// Fields to remove from user object
|
||||
#[validate(length(min = 1))]
|
||||
remove: Option<Vec<FieldsUser>>,
|
||||
}
|
||||
|
||||
/// # Edit User
|
||||
///
|
||||
/// Edit currently authenticated user.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[patch("/@me", data = "<data>")]
|
||||
pub async fn req(db: &State<Database>, mut user: User, data: Json<Data>) -> Result<Json<User>> {
|
||||
pub async fn req(
|
||||
db: &State<Database>,
|
||||
mut user: User,
|
||||
data: Json<DataEditUser>,
|
||||
) -> Result<Json<User>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
//! Fetch direct messages that the current user is involved in
|
||||
//!
|
||||
//! This includes group DMs and "active" 1:1 DMs.
|
||||
|
||||
use revolt_quark::{
|
||||
models::{Channel, User},
|
||||
Database, Result,
|
||||
@@ -9,6 +5,10 @@ use revolt_quark::{
|
||||
|
||||
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")]
|
||||
#[get("/dms")]
|
||||
pub async fn req(db: &State<Database>, user: User) -> Result<Json<Vec<Channel>>> {
|
||||
db.find_direct_messages(&user.id).await.map(Json)
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
//! Fetch another user's profile
|
||||
//!
|
||||
//! Will fail if the authenticated user does not
|
||||
//! have permission to access the other user's profile.
|
||||
|
||||
use revolt_quark::{
|
||||
models::{user::UserProfile, User},
|
||||
perms, Database, Error, Ref, Result,
|
||||
@@ -10,6 +5,12 @@ use revolt_quark::{
|
||||
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Fetch User Profile
|
||||
///
|
||||
/// 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")]
|
||||
#[get("/<target>/profile")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<UserProfile>> {
|
||||
let target = target.as_user(db).await?;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
//! Fetch the currently authenticated session's user account
|
||||
|
||||
use revolt_quark::models::User;
|
||||
use revolt_quark::Result;
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Fetch Self
|
||||
///
|
||||
/// Retrieve your user information.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[get("/@me")]
|
||||
pub async fn req(user: User) -> Result<Json<User>> {
|
||||
Ok(Json(user.foreign()))
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
//! Fetch another user
|
||||
//!
|
||||
//! Will fail if the authenticated user does not
|
||||
//! have permission to access the other user.
|
||||
|
||||
use revolt_quark::{models::User, perms, Database, Error, Ref, Result};
|
||||
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Fetch User
|
||||
///
|
||||
/// Retrieve a user's information.
|
||||
#[openapi(tag = "User Information")]
|
||||
#[get("/<target>")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<User>> {
|
||||
let target = target.as_user(db).await?;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
//! Fetch IDs of servers and friends that are mutually shared between the
|
||||
//! authenticated user and the target user
|
||||
|
||||
use revolt_quark::models::User;
|
||||
use revolt_quark::{perms, Database, Error, Ref, Result};
|
||||
|
||||
use rocket::serde::json::Value;
|
||||
use rocket::State;
|
||||
|
||||
/// # Fetch Mutual Friends And Servers
|
||||
///
|
||||
/// Retrieve a list of mutual friends and servers with another user.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[get("/<target>/mutual")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Value> {
|
||||
let target = target.as_user(db).await?;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use rocket::http::ContentType;
|
||||
use rocket::response::{self, Responder};
|
||||
use rocket::{Request, Response};
|
||||
use rocket_okapi::okapi::openapi3::{self, MediaType, RefOr};
|
||||
use schemars::schema::{InstanceType, SchemaObject, SingleOrVec};
|
||||
|
||||
pub struct CachedFile((ContentType, Vec<u8>));
|
||||
|
||||
@@ -14,13 +16,51 @@ impl<'r> Responder<'r, 'static> for CachedFile {
|
||||
}
|
||||
}
|
||||
|
||||
// Charset: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
|
||||
impl rocket_okapi::response::OpenApiResponderInner for CachedFile {
|
||||
fn responses(
|
||||
_gen: &mut rocket_okapi::gen::OpenApiGenerator,
|
||||
) -> std::result::Result<openapi3::Responses, 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")]
|
||||
#[get("/<target>/default_avatar")]
|
||||
pub async fn req(target: String) -> CachedFile {
|
||||
CachedFile((
|
||||
ContentType::PNG,
|
||||
match target.chars().last().unwrap() {
|
||||
// 0123456789ABCDEFGHJKMNPQRSTVWXYZ
|
||||
'0' | '1' | '2' | '3' | 'S' | 'Z' => {
|
||||
include_bytes!("../../../assets/user/2.png").to_vec()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rocket::Route;
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
mod add_friend;
|
||||
mod block_user;
|
||||
@@ -14,8 +15,8 @@ mod open_dm;
|
||||
mod remove_friend;
|
||||
mod unblock_user;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
// User Information
|
||||
fetch_self::req,
|
||||
fetch_user::req,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Open a direct message with another user
|
||||
|
||||
use revolt_quark::{
|
||||
models::{Channel, User},
|
||||
perms, Database, Error, Ref, Result, UserPermission,
|
||||
@@ -8,6 +6,10 @@ use revolt_quark::{
|
||||
use rocket::{serde::json::Json, State};
|
||||
use ulid::Ulid;
|
||||
|
||||
/// # Open Direct Message
|
||||
///
|
||||
/// Open a DM with another user.
|
||||
#[openapi(tag = "Direct Messaging")]
|
||||
#[get("/<target>/dm")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<Channel>> {
|
||||
let target = target.as_user(db).await?;
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{Database, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
|
||||
/// # Deny Friend Request / Remove Friend
|
||||
///
|
||||
/// Denies another user's friend request or removes an existing friend.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[delete("/<target>/friend")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: String) -> Result<Json<User>> {
|
||||
let mut target = db.fetch_user(&target).await?;
|
||||
|
||||
@@ -4,6 +4,10 @@ use revolt_quark::{Database, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
|
||||
/// # Unblock User
|
||||
///
|
||||
/// Unblock another user by their id.
|
||||
#[openapi(tag = "Relationships")]
|
||||
#[delete("/<target>/block")]
|
||||
pub async fn req(db: &State<Database>, user: User, target: String) -> Result<Json<User>> {
|
||||
let mut target = db.fetch_user(&target).await?;
|
||||
|
||||
@@ -55,7 +55,7 @@ impl<'r> OpenApiFromRequest<'r> for IdempotencyKey {
|
||||
required: false,
|
||||
deprecated: false,
|
||||
extensions: schemars::Map::new(),
|
||||
location: "sus".to_string(),
|
||||
location: "header".to_string(),
|
||||
value: ParameterValue::Schema {
|
||||
allow_reserved: false,
|
||||
example: None,
|
||||
|
||||
Reference in New Issue
Block a user