chore: refine user and bot creation methods
This commit is contained in:
24
clippy.toml
24
clippy.toml
@@ -3,19 +3,19 @@ disallowed-methods = [
|
|||||||
"revolt_database::models::bots::model::Bot::remove_field",
|
"revolt_database::models::bots::model::Bot::remove_field",
|
||||||
|
|
||||||
# Prefer to use Object::create()
|
# Prefer to use Object::create()
|
||||||
"revolt_database::models::bots::ops::AbstractBots::*",
|
|
||||||
"revolt_database::models::bots::ops::AbstractBots::insert_bot",
|
"revolt_database::models::bots::ops::AbstractBots::insert_bot",
|
||||||
"revolt_database::models::bots::ops::AbstractChannelInvites::insert_invite",
|
"revolt_database::models::channel_invites::ops::AbstractChannelInvites::insert_invite",
|
||||||
"revolt_database::models::bots::ops::AbstractChannelUnreads::acknowledge_message",
|
"revolt_database::models::channel_unreads::ops::AbstractChannelUnreads::acknowledge_message",
|
||||||
"revolt_database::models::bots::ops::AbstractChannels::insert_channel",
|
"revolt_database::models::channel_webhooks::ops::AbstractWebhooks::insert_webhook",
|
||||||
"revolt_database::models::bots::ops::AbstractEmojis::insert_emoji",
|
"revolt_database::models::channels::ops::AbstractChannels::insert_channel",
|
||||||
"revolt_database::models::bots::ops::AbstractMessages::insert_message",
|
"revolt_database::models::emojis::ops::AbstractEmojis::insert_emoji",
|
||||||
"revolt_database::models::bots::ops::AbstractRatelimitEvents::insert_ratelimit_event",
|
"revolt_database::models::files::ops::AbstractAttachments::insert_attachment",
|
||||||
"revolt_database::models::bots::ops::AbstractRatelimitEvents::insert_ratelimit_event",
|
"revolt_database::models::messages::ops::AbstractMessages::insert_message",
|
||||||
"revolt_database::models::bots::ops::AbstractServerBans::insert_ban",
|
"revolt_database::models::ratelimit_events::ops::AbstractRatelimitEvents::insert_ratelimit_event",
|
||||||
"revolt_database::models::bots::ops::AbstractServerMembers::insert_member",
|
"revolt_database::models::server_bans::ops::AbstractServerBans::insert_ban",
|
||||||
"revolt_database::models::bots::ops::AbstractServers::insert_server",
|
"revolt_database::models::server_members::ops::AbstractServerMembers::insert_member",
|
||||||
"revolt_database::models::bots::ops::AbstractUsers::insert_user",
|
"revolt_database::models::servers::ops::AbstractServers::insert_server",
|
||||||
|
"revolt_database::models::users::ops::AbstractUsers::insert_user",
|
||||||
|
|
||||||
# Prefer to use Object::update(&self)
|
# Prefer to use Object::update(&self)
|
||||||
"revolt_database::models::bots::ops::AbstractBots::update_bot",
|
"revolt_database::models::bots::ops::AbstractBots::update_bot",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use revolt_result::Result;
|
use revolt_result::Result;
|
||||||
|
use ulid::Ulid;
|
||||||
|
|
||||||
use crate::Database;
|
use crate::{BotInformation, Database, PartialUser, User};
|
||||||
|
|
||||||
auto_derived_partial!(
|
auto_derived_partial!(
|
||||||
/// Bot
|
/// Bot
|
||||||
@@ -51,6 +52,51 @@ auto_derived!(
|
|||||||
|
|
||||||
#[allow(clippy::disallowed_methods)]
|
#[allow(clippy::disallowed_methods)]
|
||||||
impl Bot {
|
impl Bot {
|
||||||
|
/// Create a new bot
|
||||||
|
pub async fn create<D>(db: &Database, username: String, owner: &User, data: D) -> Result<Bot>
|
||||||
|
where
|
||||||
|
D: Into<Option<PartialBot>>,
|
||||||
|
{
|
||||||
|
if owner.bot.is_some() {
|
||||||
|
return Err(create_error!(IsBot));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: config
|
||||||
|
let max_bot_count = 5;
|
||||||
|
if db.get_number_of_bots_by_user(&owner.id).await? >= max_bot_count {
|
||||||
|
return Err(create_error!(ReachedMaximumBots));
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = Ulid::new().to_string();
|
||||||
|
|
||||||
|
User::create(
|
||||||
|
db,
|
||||||
|
username,
|
||||||
|
Some(id.to_string()),
|
||||||
|
Some(PartialUser {
|
||||||
|
bot: Some(BotInformation {
|
||||||
|
owner: id.to_string(),
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut bot = Bot {
|
||||||
|
id,
|
||||||
|
owner: owner.id.to_string(),
|
||||||
|
token: nanoid::nanoid!(64),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(data) = data.into() {
|
||||||
|
bot.apply_options(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.insert_bot(&bot).await?;
|
||||||
|
Ok(bot)
|
||||||
|
}
|
||||||
|
|
||||||
/// Remove a field from this object
|
/// Remove a field from this object
|
||||||
pub fn remove_field(&mut self, field: &FieldsBot) {
|
pub fn remove_field(&mut self, field: &FieldsBot) {
|
||||||
match field {
|
match field {
|
||||||
@@ -96,27 +142,24 @@ mod tests {
|
|||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn crud() {
|
async fn crud() {
|
||||||
database_test!(|db| async move {
|
database_test!(|db| async move {
|
||||||
let bot_id = "bot";
|
let owner = User::create(&db, "Owner".to_string(), None, None)
|
||||||
let user_id = "user";
|
.await
|
||||||
let token = "my_token";
|
.unwrap();
|
||||||
|
|
||||||
let user = User {
|
let bot = Bot::create(
|
||||||
id: bot_id.to_string(),
|
&db,
|
||||||
username: "Bot Name".to_string(),
|
"Bot Name".to_string(),
|
||||||
|
&owner,
|
||||||
|
PartialBot {
|
||||||
|
token: Some("my token".to_string()),
|
||||||
|
interactions_url: Some("some url".to_string()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
db.insert_user(&user).await.unwrap();
|
assert!(!bot.interactions_url.is_empty());
|
||||||
|
|
||||||
let bot = Bot {
|
|
||||||
id: bot_id.to_string(),
|
|
||||||
owner: user_id.to_string(),
|
|
||||||
token: token.to_string(),
|
|
||||||
interactions_url: "some url".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
db.insert_bot(&bot).await.unwrap();
|
|
||||||
|
|
||||||
let mut updated_bot = bot.clone();
|
let mut updated_bot = bot.clone();
|
||||||
updated_bot
|
updated_bot
|
||||||
@@ -131,9 +174,9 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let fetched_bot1 = db.fetch_bot(bot_id).await.unwrap();
|
let fetched_bot1 = db.fetch_bot(&bot.id).await.unwrap();
|
||||||
let fetched_bot2 = db.fetch_bot_by_token(&fetched_bot1.token).await.unwrap();
|
let fetched_bot2 = db.fetch_bot_by_token(&fetched_bot1.token).await.unwrap();
|
||||||
let fetched_bots = db.fetch_bots_by_user(user_id).await.unwrap();
|
let fetched_bots = db.fetch_bots_by_user(&owner.id).await.unwrap();
|
||||||
|
|
||||||
assert!(!bot.public);
|
assert!(!bot.public);
|
||||||
assert!(fetched_bot1.public);
|
assert!(fetched_bot1.public);
|
||||||
@@ -143,12 +186,12 @@ mod tests {
|
|||||||
assert_eq!(updated_bot, fetched_bot1);
|
assert_eq!(updated_bot, fetched_bot1);
|
||||||
assert_eq!(fetched_bot1, fetched_bot2);
|
assert_eq!(fetched_bot1, fetched_bot2);
|
||||||
assert_eq!(fetched_bot1, fetched_bots[0]);
|
assert_eq!(fetched_bot1, fetched_bots[0]);
|
||||||
assert_eq!(1, db.get_number_of_bots_by_user(user_id).await.unwrap());
|
assert_eq!(1, db.get_number_of_bots_by_user(&owner.id).await.unwrap());
|
||||||
|
|
||||||
bot.delete(&db).await.unwrap();
|
bot.delete(&db).await.unwrap();
|
||||||
assert!(db.fetch_bot(bot_id).await.is_err());
|
assert!(db.fetch_bot(&bot.id).await.is_err());
|
||||||
assert_eq!(0, db.get_number_of_bots_by_user(user_id).await.unwrap());
|
assert_eq!(0, db.get_number_of_bots_by_user(&owner.id).await.unwrap());
|
||||||
assert_eq!(db.fetch_user(bot_id).await.unwrap().flags, Some(2))
|
assert_eq!(db.fetch_user(&bot.id).await.unwrap().flags, Some(2))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,35 @@ pub static DISCRIMINATOR_SEARCH_SPACE: Lazy<HashSet<String>> = Lazy::new(|| {
|
|||||||
set.into_iter().collect()
|
set.into_iter().collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_methods)]
|
||||||
impl User {
|
impl User {
|
||||||
|
/// Create a new user
|
||||||
|
pub async fn create<I, D>(
|
||||||
|
db: &Database,
|
||||||
|
username: String,
|
||||||
|
account_id: I,
|
||||||
|
data: D,
|
||||||
|
) -> Result<User>
|
||||||
|
where
|
||||||
|
I: Into<Option<String>>,
|
||||||
|
D: Into<Option<PartialUser>>,
|
||||||
|
{
|
||||||
|
let username = User::validate_username(username)?;
|
||||||
|
let mut user = User {
|
||||||
|
id: account_id.into().unwrap_or_else(|| Ulid::new().to_string()),
|
||||||
|
discriminator: User::find_discriminator(db, &username, None).await?,
|
||||||
|
username,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(data) = data.into() {
|
||||||
|
user.apply_options(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.insert_user(&user).await?;
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
|
||||||
/// Sanitise and validate a username can be used
|
/// Sanitise and validate a username can be used
|
||||||
pub fn validate_username(username: String) -> Result<String> {
|
pub fn validate_username(username: String) -> Result<String> {
|
||||||
// Copy the username for validation
|
// Copy the username for validation
|
||||||
@@ -207,28 +235,6 @@ impl User {
|
|||||||
event_type: crate::RatelimitEventType::DiscriminatorChange,
|
event_type: crate::RatelimitEventType::DiscriminatorChange,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
/* let rvdb: revolt_database::Database = db.clone().into();
|
|
||||||
if rvdb
|
|
||||||
.has_ratelimited(
|
|
||||||
&target_id,
|
|
||||||
RatelimitEventType::DiscriminatorChange,
|
|
||||||
Duration::from_secs(60 * 60 * 24),
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Error::from_core)?
|
|
||||||
{
|
|
||||||
return Err(Error::DiscriminatorChangeRatelimited);
|
|
||||||
}
|
|
||||||
|
|
||||||
rvdb.insert_ratelimit_event(&revolt_database::RatelimitEvent {
|
|
||||||
id: ulid::Ulid::new().to_string(),
|
|
||||||
target_id,
|
|
||||||
event_type: RatelimitEventType::DiscriminatorChange,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.map_err(Error::from_core)?; */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -605,6 +605,33 @@ impl crate::User {
|
|||||||
id: self.id,
|
id: self.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn into_self(self) -> User {
|
||||||
|
User {
|
||||||
|
username: self.username,
|
||||||
|
discriminator: self.discriminator,
|
||||||
|
display_name: self.display_name,
|
||||||
|
avatar: self.avatar.map(|file| file.into()),
|
||||||
|
relations: self
|
||||||
|
.relations
|
||||||
|
.map(|relationships| {
|
||||||
|
relationships
|
||||||
|
.into_iter()
|
||||||
|
.map(|relationship| relationship.into())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
badges: self.badges.unwrap_or_default() as u32,
|
||||||
|
status: None,
|
||||||
|
profile: None,
|
||||||
|
flags: self.flags.unwrap_or_default() as u32,
|
||||||
|
privileged: self.privileged,
|
||||||
|
bot: self.bot.map(|bot| bot.into()),
|
||||||
|
relationship: RelationshipStatus::User,
|
||||||
|
online: revolt_presence::is_online(&self.id).await,
|
||||||
|
id: self.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::RelationshipStatus> for RelationshipStatus {
|
impl From<crate::RelationshipStatus> for RelationshipStatus {
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
use nanoid::nanoid;
|
use revolt_database::{Bot, Database, User};
|
||||||
|
|
||||||
use revolt_database::{Bot, BotInformation, Database, User};
|
|
||||||
use revolt_models::v0;
|
use revolt_models::v0;
|
||||||
use revolt_result::{create_error, Result};
|
use revolt_result::{create_error, Result};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
use ulid::Ulid;
|
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
/// # Create Bot
|
/// # Create Bot
|
||||||
@@ -18,10 +15,6 @@ pub async fn create_bot(
|
|||||||
user: User,
|
user: User,
|
||||||
info: Json<v0::DataCreateBot>,
|
info: Json<v0::DataCreateBot>,
|
||||||
) -> Result<Json<v0::Bot>> {
|
) -> Result<Json<v0::Bot>> {
|
||||||
if user.bot.is_some() {
|
|
||||||
return Err(create_error!(IsBot));
|
|
||||||
}
|
|
||||||
|
|
||||||
let info = info.into_inner();
|
let info = info.into_inner();
|
||||||
info.validate().map_err(|error| {
|
info.validate().map_err(|error| {
|
||||||
create_error!(FailedValidation {
|
create_error!(FailedValidation {
|
||||||
@@ -29,32 +22,6 @@ pub async fn create_bot(
|
|||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// TODO: config
|
let bot = Bot::create(db, info.name, &user, None).await?;
|
||||||
let max_bot_count = 5;
|
|
||||||
if db.get_number_of_bots_by_user(&user.id).await? >= max_bot_count {
|
|
||||||
return Err(create_error!(ReachedMaximumBots));
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = Ulid::new().to_string();
|
|
||||||
let username = User::validate_username(info.name)?;
|
|
||||||
let bot_user = User {
|
|
||||||
id: id.clone(),
|
|
||||||
discriminator: User::find_discriminator(db, &username, None).await?,
|
|
||||||
username,
|
|
||||||
bot: Some(BotInformation {
|
|
||||||
owner: user.id.clone(),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let bot = Bot {
|
|
||||||
id,
|
|
||||||
owner: user.id,
|
|
||||||
token: nanoid!(64),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
db.insert_user(&bot_user).await?;
|
|
||||||
db.insert_bot(&bot).await?;
|
|
||||||
Ok(Json(bot.into()))
|
Ok(Json(bot.into()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::util::regex::RE_USERNAME;
|
use crate::util::regex::RE_USERNAME;
|
||||||
use revolt_quark::{
|
use revolt_database::{Database, User};
|
||||||
authifier::models::Session, models::User, Database, EmptyResponse, Error, Result,
|
use revolt_models::v0;
|
||||||
};
|
use revolt_quark::authifier::models::Session;
|
||||||
|
use revolt_result::{create_error, Result};
|
||||||
|
|
||||||
use rocket::{serde::json::Json, State};
|
use rocket::{serde::json::Json, State};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -25,22 +26,22 @@ pub async fn req(
|
|||||||
session: Session,
|
session: Session,
|
||||||
user: Option<User>,
|
user: Option<User>,
|
||||||
data: Json<DataOnboard>,
|
data: Json<DataOnboard>,
|
||||||
) -> Result<EmptyResponse> {
|
) -> Result<Json<v0::User>> {
|
||||||
if user.is_some() {
|
if user.is_some() {
|
||||||
return Err(Error::AlreadyOnboarded);
|
return Err(create_error!(AlreadyOnboarded));
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
data.validate()
|
data.validate().map_err(|error| {
|
||||||
.map_err(|error| Error::FailedValidation { error })?;
|
create_error!(FailedValidation {
|
||||||
|
error: error.to_string()
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
let username = User::validate_username(data.username)?;
|
Ok(Json(
|
||||||
let user = User {
|
User::create(db, data.username, session.user_id, None)
|
||||||
id: session.user_id,
|
.await?
|
||||||
discriminator: User::find_discriminator(db, &username, None).await?,
|
.into_self()
|
||||||
username,
|
.await,
|
||||||
..Default::default()
|
))
|
||||||
};
|
|
||||||
|
|
||||||
db.insert_user(&user).await.map(|_| EmptyResponse)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user