revolt_database/models/channel_invites/
model.rs

1use revolt_result::{create_error, Result};
2
3use crate::{Channel, Database, User};
4
5static ALPHABET: [char; 54] = [
6    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
7    'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
8    'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z',
9];
10
11auto_derived!(
12    /// Invite
13    #[serde(tag = "type")]
14    pub enum Invite {
15        /// Invite to a specific server channel
16        Server {
17            /// Invite code
18            #[serde(rename = "_id")]
19            code: String,
20            /// Id of the server this invite points to
21            server: String,
22            /// Id of user who created this invite
23            creator: String,
24            /// Id of the server channel this invite points to
25            channel: String,
26        },
27        /// Invite to a group channel
28        Group {
29            /// Invite code
30            #[serde(rename = "_id")]
31            code: String,
32            /// Id of user who created this invite
33            creator: String,
34            /// Id of the group channel this invite points to
35            channel: String,
36        }, /* User {
37               code: String,
38               user: String
39           } */
40    }
41);
42
43#[allow(clippy::disallowed_methods)]
44impl Invite {
45    /// Get the invite code for this invite
46    pub fn code(&'_ self) -> &'_ str {
47        match self {
48            Invite::Server { code, .. } | Invite::Group { code, .. } => code,
49        }
50    }
51
52    /// Get the ID of the user who created this invite
53    pub fn creator(&'_ self) -> &'_ str {
54        match self {
55            Invite::Server { creator, .. } | Invite::Group { creator, .. } => creator,
56        }
57    }
58
59    /// Create a new invite from given information
60    pub async fn create_channel_invite(
61        db: &Database,
62        creator: &User,
63        channel: &Channel,
64    ) -> Result<Invite> {
65        let code = nanoid::nanoid!(8, &ALPHABET);
66        let invite = match &channel {
67            Channel::Group { id, .. } => Ok(Invite::Group {
68                code,
69                creator: creator.id.clone(),
70                channel: id.clone(),
71            }),
72            Channel::TextChannel { id, server, .. } => {
73                Ok(Invite::Server {
74                    code,
75                    creator: creator.id.clone(),
76                    server: server.clone(),
77                    channel: id.clone(),
78                })
79            }
80            _ => Err(create_error!(InvalidOperation)),
81        }?;
82
83        db.insert_invite(&invite).await?;
84        Ok(invite)
85    }
86
87    /// Resolve an invite by its ID or by a public server ID
88    pub async fn find(db: &Database, code: &str) -> Result<Invite> {
89        if let Ok(invite) = db.fetch_invite(code).await {
90            return Ok(invite);
91        } else if let Ok(server) = db.fetch_server(code).await {
92            if server.discoverable {
93                if let Some(channel) = server.channels.into_iter().next() {
94                    return Ok(Invite::Server {
95                        code: code.to_string(),
96                        server: server.id,
97                        creator: server.owner,
98                        channel,
99                    });
100                }
101            }
102        }
103
104        Err(create_error!(NotFound))
105    }
106}