forked from jmug/stoatchat
@@ -2,13 +2,17 @@ use std::{collections::HashMap, sync::Arc};
|
|||||||
|
|
||||||
use futures::lock::Mutex;
|
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!(
|
database_derived!(
|
||||||
/// Reference implementation
|
/// Reference implementation
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ReferenceDb {
|
pub struct ReferenceDb {
|
||||||
pub bots: Arc<Mutex<HashMap<String, Bot>>>,
|
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 channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
||||||
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
||||||
pub users: Arc<Mutex<HashMap<String, User>>>,
|
pub users: Arc<Mutex<HashMap<String, User>>>,
|
||||||
@@ -20,8 +24,6 @@ database_derived!(
|
|||||||
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
pub emoji: Arc<Mutex<HashMap<String, ()>>>,
|
pub emoji: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
pub messages: 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, ()>>>,
|
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 admin_migrations;
|
||||||
mod bots;
|
mod bots;
|
||||||
|
mod channel_invites;
|
||||||
mod channel_webhooks;
|
mod channel_webhooks;
|
||||||
mod channels;
|
mod channels;
|
||||||
mod files;
|
mod files;
|
||||||
@@ -11,6 +12,7 @@ mod users;
|
|||||||
|
|
||||||
pub use admin_migrations::*;
|
pub use admin_migrations::*;
|
||||||
pub use bots::*;
|
pub use bots::*;
|
||||||
|
pub use channel_invites::*;
|
||||||
pub use channel_webhooks::*;
|
pub use channel_webhooks::*;
|
||||||
pub use channels::*;
|
pub use channels::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
@@ -28,6 +30,7 @@ pub trait AbstractDatabase:
|
|||||||
+ admin_migrations::AbstractMigrations
|
+ admin_migrations::AbstractMigrations
|
||||||
+ bots::AbstractBots
|
+ bots::AbstractBots
|
||||||
+ channels::AbstractChannels
|
+ channels::AbstractChannels
|
||||||
|
+ channel_invites::AbstractChannelInvites
|
||||||
+ channel_webhooks::AbstractWebhooks
|
+ channel_webhooks::AbstractWebhooks
|
||||||
+ files::AbstractAttachments
|
+ files::AbstractAttachments
|
||||||
+ ratelimit_events::AbstractRatelimitEvents
|
+ 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 {
|
impl From<crate::Webhook> for Webhook {
|
||||||
fn from(value: crate::Webhook) -> Self {
|
fn from(value: crate::Webhook) -> Self {
|
||||||
Webhook {
|
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 bots;
|
||||||
|
mod channel_invites;
|
||||||
mod channel_webhooks;
|
mod channel_webhooks;
|
||||||
mod channels;
|
mod channels;
|
||||||
mod files;
|
mod files;
|
||||||
@@ -7,6 +8,7 @@ mod servers;
|
|||||||
mod users;
|
mod users;
|
||||||
|
|
||||||
pub use bots::*;
|
pub use bots::*;
|
||||||
|
pub use channel_invites::*;
|
||||||
pub use channel_webhooks::*;
|
pub use channel_webhooks::*;
|
||||||
pub use channels::*;
|
pub use channels::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user