mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-08-30 23:07:27 +00:00
feat: implement discover endpoints (#940)
* feat: implement discover endpoints Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> Release-As: 0.15.2
This commit is contained in:
@@ -3,9 +3,10 @@ use std::{collections::HashMap, sync::Arc};
|
||||
use futures::lock::Mutex;
|
||||
|
||||
use crate::{
|
||||
Account, AccountInvite, AuditLogEntry, Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji,
|
||||
File, FileHash, Invite, MFATicket, Member, MemberCompositeKey, Message, PolicyChange,
|
||||
RatelimitEvent, Report, Server, ServerBan, Session, Snapshot, User, UserSettings, Webhook,
|
||||
Account, AccountInvite, AuditLogEntry, Bot, Channel, ChannelCompositeKey, ChannelUnread,
|
||||
DiscoverBan, DiscoverRequest, DiscoverRequestType, Emoji, File, FileHash, Invite, MFATicket,
|
||||
Member, MemberCompositeKey, Message, PolicyChange, RatelimitEvent, Report, Server, ServerBan,
|
||||
Session, Snapshot, User, UserSettings, Webhook,
|
||||
};
|
||||
|
||||
database_derived!(
|
||||
@@ -19,6 +20,8 @@ database_derived!(
|
||||
pub channel_unreads: Arc<Mutex<HashMap<ChannelCompositeKey, ChannelUnread>>>,
|
||||
pub channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
||||
pub emojis: Arc<Mutex<HashMap<String, Emoji>>>,
|
||||
pub discover_requests: Arc<Mutex<HashMap<(DiscoverRequestType, String), DiscoverRequest>>>,
|
||||
pub discover_bans: Arc<Mutex<HashMap<String, DiscoverBan>>>,
|
||||
pub file_hashes: Arc<Mutex<HashMap<String, FileHash>>>,
|
||||
pub files: Arc<Mutex<HashMap<String, File>>>,
|
||||
pub messages: Arc<Mutex<HashMap<String, Message>>>,
|
||||
|
||||
@@ -113,6 +113,10 @@ pub async fn create_database(db: &MongoDb) {
|
||||
.await
|
||||
.expect("Failed to create mfa_tickets collection.");
|
||||
|
||||
db.create_collection("discover_requests")
|
||||
.await
|
||||
.expect("Failed to create discover_requests collection");
|
||||
|
||||
db.run_command(doc! {
|
||||
"createIndexes": "users",
|
||||
"indexes": [
|
||||
@@ -414,5 +418,20 @@ pub async fn create_database(db: &MongoDb) {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
db.run_command(doc! {
|
||||
"createIndexes": "discover_requests",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {
|
||||
"request_type": 1,
|
||||
"request_id": 1
|
||||
},
|
||||
"name": "request_type_id"
|
||||
}
|
||||
]
|
||||
})
|
||||
.await
|
||||
.expect("Failed to create discover_requests index");
|
||||
|
||||
info!("Created database.");
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ struct MigrationInfo {
|
||||
revision: i32,
|
||||
}
|
||||
|
||||
pub const LATEST_REVISION: i32 = 52; // MUST BE +1 to last migration
|
||||
pub const LATEST_REVISION: i32 = 53; // MUST BE +1 to last migration
|
||||
|
||||
pub async fn migrate_database(db: &MongoDb) {
|
||||
let migrations = db.col::<Document>("migrations");
|
||||
@@ -1299,7 +1299,9 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
}
|
||||
|
||||
for session in sessions {
|
||||
let timestamp = iso8601_timestamp::Timestamp::from(Ulid::from_string(&session._id).unwrap().datetime());
|
||||
let timestamp = iso8601_timestamp::Timestamp::from(
|
||||
Ulid::from_string(&session._id).unwrap().datetime(),
|
||||
);
|
||||
|
||||
db.db()
|
||||
.collection::<Document>("sessions")
|
||||
@@ -1478,14 +1480,15 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
if revision <= 50 {
|
||||
info!("Running migration [revision 50 / 13-04-2026]: Rename invites collection to account_invites");
|
||||
|
||||
let result = db.db()
|
||||
let result = db
|
||||
.db()
|
||||
.client()
|
||||
.database("admin")
|
||||
.run_command(doc! {
|
||||
"renameCollection": "revolt.invites",
|
||||
"to": "revolt.account_invites",
|
||||
"dropTarget": true
|
||||
})
|
||||
"renameCollection": "revolt.invites",
|
||||
"to": "revolt.account_invites",
|
||||
"dropTarget": true
|
||||
})
|
||||
.await;
|
||||
|
||||
if let Err(e) = result {
|
||||
@@ -1496,7 +1499,7 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
if revision >= 51 {
|
||||
if revision <= 51 {
|
||||
info!("Running migration [revision 51 / 28-11-2025]: Add audit logs collection");
|
||||
|
||||
db.db()
|
||||
@@ -1529,6 +1532,35 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
.expect("Failed to create audit_logs index");
|
||||
};
|
||||
|
||||
if revision <= 52 {
|
||||
let config = revolt_config::config().await;
|
||||
if config.production {
|
||||
info!("Running migration [revision 52 / 20-08-2026]: Discover endpoints");
|
||||
db.db()
|
||||
.create_collection("discover_requests")
|
||||
.await
|
||||
.expect("Failed to create discover_requests collection");
|
||||
|
||||
db.db()
|
||||
.run_command(doc! {
|
||||
"createIndexes": "discover_requests",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {
|
||||
"request_type": 1,
|
||||
"request_id": 1
|
||||
},
|
||||
"name": "request_type_id"
|
||||
}
|
||||
]
|
||||
})
|
||||
.await
|
||||
.expect("Failed to create index");
|
||||
} else {
|
||||
info!("Skipping migration [revision 52 / 20-08-2026]: Discover endpoints");
|
||||
}
|
||||
}
|
||||
|
||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||
LATEST_REVISION.max(revision)
|
||||
}
|
||||
|
||||
5
crates/core/database/src/models/discover_requests/mod.rs
Normal file
5
crates/core/database/src/models/discover_requests/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod model;
|
||||
mod ops;
|
||||
|
||||
pub use model::*;
|
||||
pub use ops::*;
|
||||
36
crates/core/database/src/models/discover_requests/model.rs
Normal file
36
crates/core/database/src/models/discover_requests/model.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
auto_derived!(
|
||||
#[derive(Hash)]
|
||||
pub enum DiscoverRequestType {
|
||||
Bot,
|
||||
Server,
|
||||
}
|
||||
|
||||
pub enum DiscoverRequestStatus {
|
||||
Pending,
|
||||
UnderReview,
|
||||
Denied(Option<String>), // reason
|
||||
Approved(Option<String>), // reason
|
||||
}
|
||||
|
||||
/// Discover request
|
||||
pub struct DiscoverRequest {
|
||||
/// The type of request.
|
||||
#[serde(rename = "type")]
|
||||
pub request_type: DiscoverRequestType,
|
||||
/// The ID of the bot/server
|
||||
pub request_id: String,
|
||||
/// status of the request
|
||||
pub status: DiscoverRequestStatus,
|
||||
}
|
||||
|
||||
pub struct DiscoverBan {
|
||||
/// Ban Id
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
/// The type of item.
|
||||
#[serde(rename = "type")]
|
||||
pub item_type: DiscoverRequestType,
|
||||
/// The ID of the bot/server
|
||||
pub item_id: String,
|
||||
}
|
||||
);
|
||||
35
crates/core/database/src/models/discover_requests/ops.rs
Normal file
35
crates/core/database/src/models/discover_requests/ops.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::{DiscoverRequest, DiscoverRequestType};
|
||||
|
||||
#[cfg(feature = "mongodb")]
|
||||
mod mongodb;
|
||||
mod reference;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AbstractDiscoverRequest: Sync + Send {
|
||||
/// Insert discover request into database.
|
||||
/// Update an existing one if it was previously denied
|
||||
async fn insert_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest>;
|
||||
|
||||
/// Fetch Discover request by their parent id
|
||||
async fn fetch_discover_request_by_item_id(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest>;
|
||||
|
||||
/// Remove Discover request
|
||||
async fn delete_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Fetch if the item is banned from being requested. If the item is Some, then the item is banned.
|
||||
async fn get_discover_ban(&self, item_type: DiscoverRequestType, item: &str) -> Result<bool>;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::DiscoverBan;
|
||||
use crate::DiscoverRequest;
|
||||
use crate::DiscoverRequestStatus;
|
||||
use crate::DiscoverRequestType;
|
||||
use crate::MongoDb;
|
||||
|
||||
use super::AbstractDiscoverRequest;
|
||||
|
||||
static DISCOVER_COL: &str = "discover_requests";
|
||||
static DISCOVER_BANS_COL: &str = "discover_bans";
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractDiscoverRequest for MongoDb {
|
||||
/// Insert request into database.
|
||||
async fn insert_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest> {
|
||||
if let Ok(mut prev) = self
|
||||
.fetch_discover_request_by_item_id(request_type.clone(), item)
|
||||
.await
|
||||
{
|
||||
match prev.status {
|
||||
DiscoverRequestStatus::Approved(_)
|
||||
| DiscoverRequestStatus::Pending
|
||||
| DiscoverRequestStatus::UnderReview => return Err(create_error!(NoEffect)),
|
||||
_ => Ok(()),
|
||||
}?;
|
||||
self.col::<DiscoverRequest>(DISCOVER_COL).update_one(
|
||||
doc! {"request_type": bson::to_bson(&request_type).expect("failed to serialize"), "request_id": item},
|
||||
doc! {"$set": {"status": bson::to_bson(&DiscoverRequestStatus::Pending).expect("failed to serialize")}},
|
||||
).await.map_err(|_| create_database_error!("update_one", DISCOVER_COL))?;
|
||||
|
||||
prev.status = DiscoverRequestStatus::Pending;
|
||||
Ok(prev)
|
||||
} else {
|
||||
let ret = DiscoverRequest {
|
||||
request_type,
|
||||
request_id: item.to_string(),
|
||||
status: DiscoverRequestStatus::Pending,
|
||||
};
|
||||
self.col::<DiscoverRequest>(DISCOVER_COL)
|
||||
.insert_one(ret.clone())
|
||||
.await
|
||||
.map_err(|_| create_database_error!("insert_one", DISCOVER_COL))?;
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch discover by item type/id combo
|
||||
async fn fetch_discover_request_by_item_id(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest> {
|
||||
query!(
|
||||
self,
|
||||
find_one,
|
||||
DISCOVER_COL,
|
||||
doc! {"request_type": bson::to_bson(&request_type).expect("failed to serialize"), "request_id": item}
|
||||
)?.ok_or_else(|| create_database_error!("find_one", DISCOVER_COL))
|
||||
}
|
||||
|
||||
/// Remove discover request
|
||||
async fn delete_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<()> {
|
||||
query!(
|
||||
self,
|
||||
delete_one,
|
||||
DISCOVER_COL,
|
||||
doc! {"request_type": bson::to_bson(&request_type).expect("failed to serialize"), "request_id": item}
|
||||
).map(|_| ())
|
||||
}
|
||||
|
||||
/// Fetch if the item is banned from being requested
|
||||
async fn get_discover_ban(&self, item_type: DiscoverRequestType, item: &str) -> Result<bool> {
|
||||
query!(
|
||||
self,
|
||||
find_one,
|
||||
DISCOVER_BANS_COL,
|
||||
doc! {"request_type": bson::to_bson(&item_type).expect("failed to serialize"), "request_id": item}
|
||||
)?.ok_or_else(|| create_database_error!("find_one", DISCOVER_COL)).map(|_: DiscoverBan| true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::ReferenceDb;
|
||||
use crate::{DiscoverRequest, DiscoverRequestStatus, DiscoverRequestType};
|
||||
|
||||
use super::AbstractDiscoverRequest;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractDiscoverRequest for ReferenceDb {
|
||||
/// Insert request into database.
|
||||
async fn insert_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest> {
|
||||
let ret = DiscoverRequest {
|
||||
request_type: request_type.clone(),
|
||||
request_id: item.to_string(),
|
||||
status: DiscoverRequestStatus::Pending,
|
||||
};
|
||||
|
||||
let mut discover = self.discover_requests.lock().await;
|
||||
if let std::collections::hash_map::Entry::Vacant(e) =
|
||||
discover.entry((request_type, item.to_string()))
|
||||
{
|
||||
e.insert(ret.clone());
|
||||
Ok(ret)
|
||||
} else {
|
||||
Err(create_database_error!("insert", "discover_requests"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch discover by item type/id combo
|
||||
async fn fetch_discover_request_by_item_id(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<DiscoverRequest> {
|
||||
let discover = self.discover_requests.lock().await;
|
||||
discover
|
||||
.iter()
|
||||
.find(|(_, d)| d.request_id == item && d.request_type == request_type)
|
||||
.map(|(_, d)| d.clone())
|
||||
.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Remove discover request
|
||||
async fn delete_discover_request(
|
||||
&self,
|
||||
request_type: DiscoverRequestType,
|
||||
item: &str,
|
||||
) -> Result<()> {
|
||||
let discover = self.discover_requests.lock().await;
|
||||
let req = discover
|
||||
.iter()
|
||||
.find(|(_, d)| d.request_id == item && d.request_type == request_type)
|
||||
.map(|(id, _)| id);
|
||||
|
||||
if let Some(req) = req {
|
||||
let mut discover = self.discover_requests.lock().await;
|
||||
discover.remove_entry(req);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch if the item is banned from being requested
|
||||
async fn get_discover_ban(&self, item_type: DiscoverRequestType, item: &str) -> Result<bool> {
|
||||
let discover = self.discover_bans.lock().await;
|
||||
discover
|
||||
.iter()
|
||||
.find(|(_, d)| d.item_id == item && d.item_type == item_type)
|
||||
.map(|(_, _)| true)
|
||||
.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
mod account_invites;
|
||||
mod accounts;
|
||||
mod admin_migrations;
|
||||
mod audit_logs;
|
||||
mod bots;
|
||||
@@ -5,10 +7,12 @@ mod channel_invites;
|
||||
mod channel_unreads;
|
||||
mod channel_webhooks;
|
||||
mod channels;
|
||||
mod discover_requests;
|
||||
mod emojis;
|
||||
mod file_hashes;
|
||||
mod files;
|
||||
mod messages;
|
||||
mod mfa_tickets;
|
||||
mod policy_changes;
|
||||
mod ratelimit_events;
|
||||
mod safety_reports;
|
||||
@@ -16,13 +20,12 @@ mod safety_snapshots;
|
||||
mod server_bans;
|
||||
mod server_members;
|
||||
mod servers;
|
||||
mod sessions;
|
||||
mod user_settings;
|
||||
mod users;
|
||||
mod accounts;
|
||||
mod account_invites;
|
||||
mod sessions;
|
||||
mod mfa_tickets;
|
||||
|
||||
pub use account_invites::*;
|
||||
pub use accounts::*;
|
||||
pub use admin_migrations::*;
|
||||
pub use audit_logs::*;
|
||||
pub use bots::*;
|
||||
@@ -30,10 +33,12 @@ pub use channel_invites::*;
|
||||
pub use channel_unreads::*;
|
||||
pub use channel_webhooks::*;
|
||||
pub use channels::*;
|
||||
pub use discover_requests::*;
|
||||
pub use emojis::*;
|
||||
pub use file_hashes::*;
|
||||
pub use files::*;
|
||||
pub use messages::*;
|
||||
pub use mfa_tickets::*;
|
||||
pub use policy_changes::*;
|
||||
pub use ratelimit_events::*;
|
||||
pub use safety_reports::*;
|
||||
@@ -41,12 +46,9 @@ pub use safety_snapshots::*;
|
||||
pub use server_bans::*;
|
||||
pub use server_members::*;
|
||||
pub use servers::*;
|
||||
pub use sessions::*;
|
||||
pub use user_settings::*;
|
||||
pub use users::*;
|
||||
pub use accounts::*;
|
||||
pub use account_invites::*;
|
||||
pub use sessions::*;
|
||||
pub use mfa_tickets::*;
|
||||
|
||||
use crate::{Database, ReferenceDb};
|
||||
|
||||
@@ -80,6 +82,7 @@ pub trait AbstractDatabase:
|
||||
+ account_invites::AbstractAccountInvites
|
||||
+ sessions::AbstractSessions
|
||||
+ mfa_tickets::AbstractMFATickets
|
||||
+ discover_requests::AbstractDiscoverRequest
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,46 @@ impl From<crate::ChannelCompositeKey> for ChannelCompositeKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::DiscoverBan> for DiscoverBan {
|
||||
fn from(value: crate::DiscoverBan) -> Self {
|
||||
DiscoverBan {
|
||||
id: value.id,
|
||||
item_type: value.item_type.into(),
|
||||
item_id: value.item_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::DiscoverRequest> for DiscoverRequest {
|
||||
fn from(value: crate::DiscoverRequest) -> Self {
|
||||
DiscoverRequest {
|
||||
request_type: value.request_type.into(),
|
||||
request_id: value.request_id,
|
||||
status: value.status.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::DiscoverRequestType> for DiscoverRequestType {
|
||||
fn from(value: crate::DiscoverRequestType) -> Self {
|
||||
match value {
|
||||
crate::DiscoverRequestType::Bot => DiscoverRequestType::Bot,
|
||||
crate::DiscoverRequestType::Server => DiscoverRequestType::Server,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::DiscoverRequestStatus> for DiscoverRequestStatus {
|
||||
fn from(value: crate::DiscoverRequestStatus) -> Self {
|
||||
match value {
|
||||
crate::DiscoverRequestStatus::Approved(s) => DiscoverRequestStatus::Approved(s),
|
||||
crate::DiscoverRequestStatus::Denied(s) => DiscoverRequestStatus::Denied(s),
|
||||
crate::DiscoverRequestStatus::Pending => DiscoverRequestStatus::Pending,
|
||||
crate::DiscoverRequestStatus::UnderReview => DiscoverRequestStatus::UnderReview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Webhook> for Webhook {
|
||||
fn from(value: crate::Webhook) -> Self {
|
||||
Webhook {
|
||||
|
||||
35
crates/core/models/src/v0/discover.rs
Normal file
35
crates/core/models/src/v0/discover.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
auto_derived!(
|
||||
pub enum DiscoverRequestType {
|
||||
Bot,
|
||||
Server,
|
||||
}
|
||||
|
||||
pub enum DiscoverRequestStatus {
|
||||
Pending,
|
||||
UnderReview,
|
||||
Denied(Option<String>), // reason
|
||||
Approved(Option<String>), // reason
|
||||
}
|
||||
|
||||
/// Discover request
|
||||
pub struct DiscoverRequest {
|
||||
/// The type of request.
|
||||
#[serde(rename = "type")]
|
||||
pub request_type: DiscoverRequestType,
|
||||
/// The ID of the bot/server
|
||||
pub request_id: String,
|
||||
/// status of the request
|
||||
pub status: DiscoverRequestStatus,
|
||||
}
|
||||
|
||||
pub struct DiscoverBan {
|
||||
/// Ban Id
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
/// The type of item.
|
||||
#[serde(rename = "type")]
|
||||
pub item_type: DiscoverRequestType,
|
||||
/// The ID of the bot/server
|
||||
pub item_id: String,
|
||||
}
|
||||
);
|
||||
@@ -1,41 +1,43 @@
|
||||
mod accounts;
|
||||
mod audit_logs;
|
||||
mod bots;
|
||||
mod channel_invites;
|
||||
mod channel_unreads;
|
||||
mod channel_webhooks;
|
||||
mod channels;
|
||||
mod discover;
|
||||
mod embeds;
|
||||
mod emojis;
|
||||
mod files;
|
||||
mod messages;
|
||||
mod mfa_tickets;
|
||||
mod policy_changes;
|
||||
mod safety_reports;
|
||||
mod server_bans;
|
||||
mod server_members;
|
||||
mod servers;
|
||||
mod sessions;
|
||||
mod user_settings;
|
||||
mod users;
|
||||
mod accounts;
|
||||
mod mfa_tickets;
|
||||
mod sessions;
|
||||
|
||||
pub use accounts::*;
|
||||
pub use audit_logs::*;
|
||||
pub use bots::*;
|
||||
pub use channel_invites::*;
|
||||
pub use channel_unreads::*;
|
||||
pub use channel_webhooks::*;
|
||||
pub use channels::*;
|
||||
pub use discover::*;
|
||||
pub use embeds::*;
|
||||
pub use emojis::*;
|
||||
pub use files::*;
|
||||
pub use messages::*;
|
||||
pub use mfa_tickets::*;
|
||||
pub use policy_changes::*;
|
||||
pub use safety_reports::*;
|
||||
pub use server_bans::*;
|
||||
pub use server_members::*;
|
||||
pub use servers::*;
|
||||
pub use sessions::*;
|
||||
pub use user_settings::*;
|
||||
pub use users::*;
|
||||
pub use accounts::*;
|
||||
pub use mfa_tickets::*;
|
||||
pub use sessions::*;
|
||||
@@ -12,6 +12,8 @@ impl IntoResponse for Error {
|
||||
let status = match self.error_type {
|
||||
ErrorType::LabelMe => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
|
||||
ErrorType::ContactSupport { .. } => StatusCode::BAD_REQUEST,
|
||||
|
||||
ErrorType::AlreadyOnboarded => StatusCode::FORBIDDEN,
|
||||
|
||||
ErrorType::UnknownUser => StatusCode::NOT_FOUND,
|
||||
|
||||
@@ -57,6 +57,11 @@ pub enum ErrorType {
|
||||
/// This error was not labeled :(
|
||||
LabelMe,
|
||||
|
||||
// ? Support Errors
|
||||
ContactSupport {
|
||||
msg: String,
|
||||
},
|
||||
|
||||
// ? Onboarding related errors
|
||||
AlreadyOnboarded,
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ impl<'r> Responder<'r, 'static> for Error {
|
||||
let status = match self.error_type {
|
||||
ErrorType::LabelMe => Status::InternalServerError,
|
||||
|
||||
ErrorType::ContactSupport { .. } => Status::BadRequest,
|
||||
|
||||
ErrorType::AlreadyOnboarded => Status::Forbidden,
|
||||
|
||||
ErrorType::UnknownUser => Status::NotFound,
|
||||
|
||||
41
crates/delta/src/routes/bots/discover/discover_add_bot.rs
Normal file
41
crates/delta/src/routes/bots/discover/discover_add_bot.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{util::reference::Reference, Database, DiscoverRequestType, User};
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
|
||||
/// # Add bot to Discover
|
||||
///
|
||||
/// This puts your bot into the Discover request queue.
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[put("/<bot_id>/discover")]
|
||||
pub async fn discover_add_bot(
|
||||
db: &State<Database>,
|
||||
bot_id: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<EmptyResponse> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let bot = bot_id.as_bot(db).await?;
|
||||
if (bot.owner != user.id && bot.id != user.id) && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Bot, &bot.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
db.insert_discover_request(DiscoverRequestType::Bot, &bot.id)
|
||||
.await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
43
crates/delta/src/routes/bots/discover/discover_get_bot.rs
Normal file
43
crates/delta/src/routes/bots/discover/discover_get_bot.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{util::reference::Reference, Database, DiscoverRequestType, User};
|
||||
use revolt_models::v0;
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Get Discover request status
|
||||
///
|
||||
/// Fetches the status of your Discover request.
|
||||
/// If it has been approved or denied, the reason will be provided (if applicable).
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[get("/<bot_id>/discover")]
|
||||
pub async fn discover_get_bot(
|
||||
db: &State<Database>,
|
||||
bot_id: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<Json<v0::DiscoverRequest>> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let bot = bot_id.as_bot(db).await?;
|
||||
if (bot.owner != user.id && bot.id != user.id) && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Bot, &bot.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
let ret = db
|
||||
.fetch_discover_request_by_item_id(DiscoverRequestType::Bot, &bot.id)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ret.into()))
|
||||
}
|
||||
55
crates/delta/src/routes/bots/discover/discover_remove_bot.rs
Normal file
55
crates/delta/src/routes/bots/discover/discover_remove_bot.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::reference::Reference, Database, DiscoverRequestStatus, DiscoverRequestType, User,
|
||||
};
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
/// # Delete Discover request
|
||||
///
|
||||
/// This cannot be used if your request is no longer in the queue (ie approved or rejected).
|
||||
/// If you wish to reapply after a rejection, submit another POST.
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[delete("/<bot_id>/discover")]
|
||||
pub async fn discover_remove_bot(
|
||||
db: &State<Database>,
|
||||
bot_id: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<EmptyResponse> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let bot = bot_id.as_bot(db).await?;
|
||||
if (bot.owner != user.id && bot.id != user.id) && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Bot, &bot.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
let ret = db
|
||||
.fetch_discover_request_by_item_id(DiscoverRequestType::Bot, &bot.id)
|
||||
.await?;
|
||||
|
||||
match ret.status {
|
||||
DiscoverRequestStatus::Approved(_) => Err(create_error!(ContactSupport {
|
||||
msg: "Contact support to have your bot removed from Discover".to_string()
|
||||
})),
|
||||
DiscoverRequestStatus::Denied(_) => Err(create_error!(NoEffect)),
|
||||
DiscoverRequestStatus::Pending | DiscoverRequestStatus::UnderReview => {
|
||||
db.delete_discover_request(ret.request_type, &ret.request_id)
|
||||
.await?;
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
crates/delta/src/routes/bots/discover/mod.rs
Normal file
3
crates/delta/src/routes/bots/discover/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod discover_add_bot;
|
||||
pub mod discover_get_bot;
|
||||
pub mod discover_remove_bot;
|
||||
@@ -3,6 +3,7 @@ use rocket::Route;
|
||||
|
||||
mod create;
|
||||
mod delete;
|
||||
mod discover;
|
||||
mod edit;
|
||||
mod fetch;
|
||||
mod fetch_owned;
|
||||
@@ -18,5 +19,8 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
fetch_owned::fetch_owned_bots,
|
||||
edit::edit_bot,
|
||||
delete::delete_bot,
|
||||
discover::discover_add_bot::discover_add_bot,
|
||||
discover::discover_get_bot::discover_get_bot,
|
||||
discover::discover_remove_bot::discover_remove_bot,
|
||||
]
|
||||
}
|
||||
|
||||
41
crates/delta/src/routes/servers/discover/discover_add.rs
Normal file
41
crates/delta/src/routes/servers/discover/discover_add.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{util::reference::Reference, Database, DiscoverRequestType, User};
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
|
||||
/// # Add server to Discover
|
||||
///
|
||||
/// This puts your server into the Discover request queue.
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[put("/<server>/discover")]
|
||||
pub async fn discover_add(
|
||||
db: &State<Database>,
|
||||
server: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<EmptyResponse> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let server = server.as_server(db).await?;
|
||||
if server.owner != user.id && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Server, &server.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
db.insert_discover_request(DiscoverRequestType::Server, &server.id)
|
||||
.await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
43
crates/delta/src/routes/servers/discover/discover_get.rs
Normal file
43
crates/delta/src/routes/servers/discover/discover_get.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{util::reference::Reference, Database, DiscoverRequestType, User};
|
||||
use revolt_models::v0;
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Get Discover request status
|
||||
///
|
||||
/// Fetches the status of your Discover request.
|
||||
/// If it has been approved or denied, the reason will be provided (if applicable).
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[get("/<server>/discover")]
|
||||
pub async fn discover_get(
|
||||
db: &State<Database>,
|
||||
server: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<Json<v0::DiscoverRequest>> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let server = server.as_server(db).await?;
|
||||
if server.owner != user.id && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Server, &server.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
let ret = db
|
||||
.fetch_discover_request_by_item_id(DiscoverRequestType::Server, &server.id)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ret.into()))
|
||||
}
|
||||
55
crates/delta/src/routes/servers/discover/discover_remove.rs
Normal file
55
crates/delta/src/routes/servers/discover/discover_remove.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::reference::Reference, Database, DiscoverRequestStatus, DiscoverRequestType, User,
|
||||
};
|
||||
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
/// # Delete Discover request
|
||||
///
|
||||
/// This cannot be used if your request is no longer in the queue (ie approved or rejected).
|
||||
/// If you wish to reapply after a rejection, submit another POST.
|
||||
/// This endpoint is ONLY USEFUL in production on stoat.chat/app .
|
||||
#[openapi(tag = "Discover")]
|
||||
#[delete("/<server>/discover")]
|
||||
pub async fn discover_remove(
|
||||
db: &State<Database>,
|
||||
server: Reference<'_>,
|
||||
user: User,
|
||||
) -> Result<EmptyResponse> {
|
||||
let config = config().await;
|
||||
if !config.production {
|
||||
return Err(create_error!(NoEffect));
|
||||
}
|
||||
|
||||
let server = server.as_server(db).await?;
|
||||
if server.owner != user.id && !user.privileged {
|
||||
return Err(create_error!(NotOwner));
|
||||
}
|
||||
|
||||
if db
|
||||
.get_discover_ban(DiscoverRequestType::Server, &server.id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
let ret = db
|
||||
.fetch_discover_request_by_item_id(DiscoverRequestType::Server, &server.id)
|
||||
.await?;
|
||||
|
||||
match ret.status {
|
||||
DiscoverRequestStatus::Approved(_) => Err(create_error!(ContactSupport {
|
||||
msg: "Contact support to have your server removed from Discover".to_string()
|
||||
})),
|
||||
DiscoverRequestStatus::Denied(_) => Err(create_error!(NoEffect)),
|
||||
DiscoverRequestStatus::Pending | DiscoverRequestStatus::UnderReview => {
|
||||
db.delete_discover_request(ret.request_type, &ret.request_id)
|
||||
.await?;
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
3
crates/delta/src/routes/servers/discover/mod.rs
Normal file
3
crates/delta/src/routes/servers/discover/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod discover_add;
|
||||
pub mod discover_get;
|
||||
pub mod discover_remove;
|
||||
@@ -6,6 +6,7 @@ mod ban_create;
|
||||
mod ban_list;
|
||||
mod ban_remove;
|
||||
mod channel_create;
|
||||
mod discover;
|
||||
mod emoji_list;
|
||||
mod invites_fetch;
|
||||
mod member_edit;
|
||||
@@ -52,5 +53,8 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
emoji_list::list_emoji,
|
||||
roles_edit_positions::edit_role_ranks,
|
||||
audit_log_query::query,
|
||||
discover::discover_add::discover_add,
|
||||
discover::discover_get::discover_get,
|
||||
discover::discover_remove::discover_remove,
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user