mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 13:36:59 +00:00
@@ -2,13 +2,17 @@ use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use futures::lock::Mutex;
|
||||
|
||||
use crate::{Bot, Channel, File, Member, MemberCompositeKey, Server, User, UserSettings, Webhook};
|
||||
use crate::{
|
||||
Bot, Channel, File, Invite, Member, MemberCompositeKey, Server, User, UserSettings, Webhook,
|
||||
};
|
||||
|
||||
database_derived!(
|
||||
/// Reference implementation
|
||||
#[derive(Default)]
|
||||
pub struct ReferenceDb {
|
||||
pub bots: Arc<Mutex<HashMap<String, Bot>>>,
|
||||
pub channels: Arc<Mutex<HashMap<String, Channel>>>,
|
||||
pub channel_invites: Arc<Mutex<HashMap<String, Invite>>>,
|
||||
pub channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
||||
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
||||
pub users: Arc<Mutex<HashMap<String, User>>>,
|
||||
@@ -20,8 +24,6 @@ database_derived!(
|
||||
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub emoji: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub messages: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub channels: Arc<Mutex<HashMap<String, Channel>>>,
|
||||
pub channel_invites: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub channel_unreads: Arc<Mutex<HashMap<String, ()>>>,
|
||||
}
|
||||
);
|
||||
|
||||
5
crates/core/database/src/models/channel_invites/mod.rs
Normal file
5
crates/core/database/src/models/channel_invites/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod model;
|
||||
mod ops;
|
||||
|
||||
pub use model::*;
|
||||
pub use ops::*;
|
||||
101
crates/core/database/src/models/channel_invites/model.rs
Normal file
101
crates/core/database/src/models/channel_invites/model.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use revolt_result::{create_error, Result};
|
||||
|
||||
use crate::Database;
|
||||
|
||||
/* static ALPHABET: [char; 54] = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
|
||||
'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z',
|
||||
]; */
|
||||
|
||||
auto_derived!(
|
||||
/// Invite
|
||||
pub enum Invite {
|
||||
/// Invite to a specific server channel
|
||||
Server {
|
||||
/// Invite code
|
||||
#[serde(rename = "_id")]
|
||||
code: String,
|
||||
/// Id of the server this invite points to
|
||||
server: String,
|
||||
/// Id of user who created this invite
|
||||
creator: String,
|
||||
/// Id of the server channel this invite points to
|
||||
channel: String,
|
||||
},
|
||||
/// Invite to a group channel
|
||||
Group {
|
||||
/// Invite code
|
||||
#[serde(rename = "_id")]
|
||||
code: String,
|
||||
/// Id of user who created this invite
|
||||
creator: String,
|
||||
/// Id of the group channel this invite points to
|
||||
channel: String,
|
||||
}, /* User {
|
||||
code: String,
|
||||
user: String
|
||||
} */
|
||||
}
|
||||
);
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
impl Invite {
|
||||
/// Get the invite code for this invite
|
||||
pub fn code(&'_ self) -> &'_ str {
|
||||
match self {
|
||||
Invite::Server { code, .. } | Invite::Group { code, .. } => code,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the ID of the user who created this invite
|
||||
pub fn creator(&'_ self) -> &'_ str {
|
||||
match self {
|
||||
Invite::Server { creator, .. } | Invite::Group { creator, .. } => creator,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new invite from given information
|
||||
/*pub async fn create_channel_invite(db: &Database, creator_id: String, target: &Channel) -> Result<Invite> {
|
||||
let code = nanoid::nanoid!(8, &ALPHABET);
|
||||
let invite = match &target {
|
||||
Channel::Group { id, .. } => Ok(Invite::Group {
|
||||
code,
|
||||
creator: creator.id.clone(),
|
||||
channel: id.clone(),
|
||||
}),
|
||||
Channel::TextChannel { id, server, .. } | Channel::VoiceChannel { id, server, .. } => {
|
||||
Ok(Invite::Server {
|
||||
code,
|
||||
creator: creator.id.clone(),
|
||||
server: server.clone(),
|
||||
channel: id.clone(),
|
||||
})
|
||||
}
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}?;
|
||||
|
||||
db.insert_invite(&invite).await?;
|
||||
Ok(invite)
|
||||
}*/
|
||||
|
||||
/// Resolve an invite by its ID or by a public server ID
|
||||
pub async fn find(db: &Database, code: &str) -> Result<Invite> {
|
||||
if let Ok(invite) = db.fetch_invite(code).await {
|
||||
return Ok(invite);
|
||||
} else if let Ok(server) = db.fetch_server(code).await {
|
||||
if server.discoverable {
|
||||
if let Some(channel) = server.channels.into_iter().next() {
|
||||
return Ok(Invite::Server {
|
||||
code: code.to_string(),
|
||||
server: server.id,
|
||||
creator: server.owner,
|
||||
channel,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
21
crates/core/database/src/models/channel_invites/ops.rs
Normal file
21
crates/core/database/src/models/channel_invites/ops.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Invite;
|
||||
|
||||
mod mongodb;
|
||||
mod reference;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AbstractChannelInvites: Sync + Send {
|
||||
/// Insert a new invite into the database
|
||||
async fn insert_invite(&self, invite: &Invite) -> Result<()>;
|
||||
|
||||
/// Fetch an invite by its id
|
||||
async fn fetch_invite(&self, code: &str) -> Result<Invite>;
|
||||
|
||||
/// Fetch all invites for a server
|
||||
async fn fetch_invites_for_server(&self, server_id: &str) -> Result<Vec<Invite>>;
|
||||
|
||||
/// Delete an invite by its id
|
||||
async fn delete_invite(&self, code: &str) -> Result<()>;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use futures::StreamExt;
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Invite;
|
||||
use crate::MongoDb;
|
||||
|
||||
use super::AbstractChannelInvites;
|
||||
|
||||
static COL: &str = "channel_invites";
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractChannelInvites for MongoDb {
|
||||
/// Insert a new invite into the database
|
||||
async fn insert_invite(&self, invite: &Invite) -> Result<()> {
|
||||
query!(self, insert_one, COL, &invite).map(|_| ())
|
||||
}
|
||||
|
||||
/// Fetch an invite by the code
|
||||
async fn fetch_invite(&self, code: &str) -> Result<Invite> {
|
||||
query!(self, find_one_by_id, COL, code)?.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Fetch all invites for a server
|
||||
async fn fetch_invites_for_server(&self, server_id: &str) -> Result<Vec<Invite>> {
|
||||
Ok(self
|
||||
.col::<Invite>(COL)
|
||||
.find(
|
||||
doc! {
|
||||
"server": server_id,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| create_database_error!("find", COL))?
|
||||
.filter_map(|s| async {
|
||||
if cfg!(debug_assertions) {
|
||||
Some(s.unwrap())
|
||||
} else {
|
||||
s.ok()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await)
|
||||
}
|
||||
|
||||
/// Delete an invite by its code
|
||||
async fn delete_invite(&self, code: &str) -> Result<()> {
|
||||
query!(self, delete_one_by_id, COL, code).map(|_| ())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Invite;
|
||||
use crate::ReferenceDb;
|
||||
|
||||
use super::AbstractChannelInvites;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractChannelInvites for ReferenceDb {
|
||||
/// Insert a new invite into the database
|
||||
async fn insert_invite(&self, invite: &Invite) -> Result<()> {
|
||||
let mut invites = self.channel_invites.lock().await;
|
||||
if invites.contains_key(invite.code()) {
|
||||
Err(create_database_error!("insert", "invite"))
|
||||
} else {
|
||||
invites.insert(invite.code().to_string(), invite.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch an invite by the code
|
||||
async fn fetch_invite(&self, code: &str) -> Result<Invite> {
|
||||
let invites = self.channel_invites.lock().await;
|
||||
invites
|
||||
.get(code)
|
||||
.cloned()
|
||||
.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Fetch all invites for a server
|
||||
async fn fetch_invites_for_server(&self, server_id: &str) -> Result<Vec<Invite>> {
|
||||
let invites = self.channel_invites.lock().await;
|
||||
Ok(invites
|
||||
.values()
|
||||
.filter(|invite| match invite {
|
||||
Invite::Server { server, .. } => server == server_id,
|
||||
_ => false,
|
||||
})
|
||||
.cloned()
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Delete an invite by its code
|
||||
async fn delete_invite(&self, code: &str) -> Result<()> {
|
||||
let mut invites = self.channel_invites.lock().await;
|
||||
if invites.remove(code).is_some() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod admin_migrations;
|
||||
mod bots;
|
||||
mod channel_invites;
|
||||
mod channel_webhooks;
|
||||
mod channels;
|
||||
mod files;
|
||||
@@ -11,6 +12,7 @@ mod users;
|
||||
|
||||
pub use admin_migrations::*;
|
||||
pub use bots::*;
|
||||
pub use channel_invites::*;
|
||||
pub use channel_webhooks::*;
|
||||
pub use channels::*;
|
||||
pub use files::*;
|
||||
@@ -28,6 +30,7 @@ pub trait AbstractDatabase:
|
||||
+ admin_migrations::AbstractMigrations
|
||||
+ bots::AbstractBots
|
||||
+ channels::AbstractChannels
|
||||
+ channel_invites::AbstractChannelInvites
|
||||
+ channel_webhooks::AbstractWebhooks
|
||||
+ files::AbstractAttachments
|
||||
+ ratelimit_events::AbstractRatelimitEvents
|
||||
|
||||
@@ -34,6 +34,33 @@ impl From<crate::Bot> for Bot {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Invite> for Invite {
|
||||
fn from(value: crate::Invite) -> Self {
|
||||
match value {
|
||||
crate::Invite::Group {
|
||||
code,
|
||||
creator,
|
||||
channel,
|
||||
} => Invite::Group {
|
||||
code,
|
||||
creator,
|
||||
channel,
|
||||
},
|
||||
crate::Invite::Server {
|
||||
code,
|
||||
server,
|
||||
creator,
|
||||
channel,
|
||||
} => Invite::Server {
|
||||
code,
|
||||
server,
|
||||
creator,
|
||||
channel,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Webhook> for Webhook {
|
||||
fn from(value: crate::Webhook) -> Self {
|
||||
Webhook {
|
||||
|
||||
27
crates/core/models/src/v0/channel_invites.rs
Normal file
27
crates/core/models/src/v0/channel_invites.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
auto_derived!(
|
||||
/// Invite
|
||||
pub enum Invite {
|
||||
/// Invite to a specific server channel
|
||||
Server {
|
||||
/// Invite code
|
||||
#[cfg_attr(feature = "serde", serde(rename = "_id"))]
|
||||
code: String,
|
||||
/// Id of the server this invite points to
|
||||
server: String,
|
||||
/// Id of user who created this invite
|
||||
creator: String,
|
||||
/// Id of the server channel this invite points to
|
||||
channel: String,
|
||||
},
|
||||
/// Invite to a group channel
|
||||
Group {
|
||||
/// Invite code
|
||||
#[cfg_attr(feature = "serde", serde(rename = "_id"))]
|
||||
code: String,
|
||||
/// Id of user who created this invite
|
||||
creator: String,
|
||||
/// Id of the group channel this invite points to
|
||||
channel: String,
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -1,4 +1,5 @@
|
||||
mod bots;
|
||||
mod channel_invites;
|
||||
mod channel_webhooks;
|
||||
mod channels;
|
||||
mod files;
|
||||
@@ -7,6 +8,7 @@ mod servers;
|
||||
mod users;
|
||||
|
||||
pub use bots::*;
|
||||
pub use channel_invites::*;
|
||||
pub use channel_webhooks::*;
|
||||
pub use channels::*;
|
||||
pub use files::*;
|
||||
|
||||
Reference in New Issue
Block a user