Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce required fields for builders #2087

Merged
merged 11 commits into from
Aug 17, 2022
2 changes: 1 addition & 1 deletion examples/e03_struct_utilities/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl EventHandler for Handler {
// In this case, you can direct message a User directly by simply
// calling a method on its instance, with the content of the
// message.
let builder = CreateMessage::default().content("Hello!");
let builder = CreateMessage::new().content("Hello!");
let dm = msg.author.dm(&context, builder).await;

if let Err(why) = dm {
Expand Down
2 changes: 1 addition & 1 deletion examples/e05_command_framework/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ async fn am_i_admin(ctx: &Context, msg: &Message, _args: Args) -> CommandResult
#[command]
async fn slow_mode(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let say_content = if let Ok(slow_mode_rate_seconds) = args.single::<u64>() {
let builder = EditChannel::default().rate_limit_per_user(slow_mode_rate_seconds);
let builder = EditChannel::new().rate_limit_per_user(slow_mode_rate_seconds);
if let Err(why) = msg.channel_id.edit(&ctx.http, builder).await {
println!("Error setting channel's slow mode rate: {:?}", why);

Expand Down
6 changes: 3 additions & 3 deletions examples/e09_create_message_builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ impl EventHandler for Handler {
// using a builder syntax.
// This example will create a message that says "Hello, World!", with an embed that has
// a title, description, an image, three fields, and a footer.
let footer = CreateEmbedFooter::default().text("This is a footer");
let embed = CreateEmbed::default()
let footer = CreateEmbedFooter::new("This is a footer");
let embed = CreateEmbed::new()
.title("This is a title")
.description("This is a description")
.image("attachment://ferris_eyes.png")
Expand All @@ -31,7 +31,7 @@ impl EventHandler for Handler {
// Add a timestamp for the current time
// This also accepts a rfc3339 Timestamp
.timestamp(Timestamp::now());
let builder = CreateMessage::default()
let builder = CreateMessage::new()
.content("Hello, World!")
.embed(embed)
.add_file("./ferris_eyes.png");
Expand Down
4 changes: 2 additions & 2 deletions examples/e13_parallel_loops/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async fn log_system_load(ctx: Arc<Context>) {

// We can use ChannelId directly to send a message to a specific channel; in this case, the
// message would be sent to the #testing channel on the discord server.
let embed = CreateEmbed::default()
let embed = CreateEmbed::new()
.title("System Resource Load")
.field("CPU Load Average", &format!("{:.2}%", cpu_load.one * 10.0), false)
.field(
Expand All @@ -92,7 +92,7 @@ async fn log_system_load(ctx: Arc<Context>) {
),
false,
);
let builder = CreateMessage::default().embed(embed);
let builder = CreateMessage::new().embed(embed);
let message = ChannelId::new(381926291785383946).send_message(&ctx, builder).await;
if let Err(why) = message {
eprintln!("Error sending message: {:?}", why);
Expand Down
55 changes: 15 additions & 40 deletions examples/e14_slash_commands/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ impl EventHandler for Handler {
_ => "not implemented :(".to_string(),
};

let data = CreateInteractionResponseData::default().content(content);
let builder = CreateInteractionResponse::default()
let data = CreateInteractionResponseData::new().content(content);
let builder = CreateInteractionResponse::new()
.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(data);
if let Err(why) = command.create_interaction_response(&ctx.http, builder).await {
Expand All @@ -74,37 +74,25 @@ impl EventHandler for Handler {
.expect("GUILD_ID must be an integer"),
);

let c1 = CreateCommand::default().name("ping").description("A ping command");
let c1 = CreateCommand::new("ping", "A ping command");

let c2 = CreateCommand::default().name("id").description("Get a user id").add_option(
CreateOption::default()
.name("id")
.description("The user to lookup")
.kind(CommandOptionType::User)
.required(true),
let c2 = CreateCommand::new("id", "Get a user id").add_option(
CreateOption::new(CommandOptionType::User, "id", "The user to lookup").required(true),
);

let c3 = CreateCommand::default()
.name("welcome")
let c3 = CreateCommand::new("welcome", "Welcome a user")
.name_localized("de", "begrüßen")
.description("Welcome a user")
.description_localized("de", "Einen Nutzer begrüßen")
.add_option(
CreateOption::default()
.name("user")
CreateOption::new(CommandOptionType::User, "user", "The user to welcome")
.name_localized("de", "nutzer")
.description("The user to welcome")
.description_localized("de", "Der zu begrüßende Nutzer")
.kind(CommandOptionType::User)
.required(true),
)
.add_option(
CreateOption::default()
.name("message")
CreateOption::new(CommandOptionType::String, "message", "The message to send")
.name_localized("de", "nachricht")
.description("The message to send")
.description_localized("de", "Die versendete Nachricht")
.kind(CommandOptionType::String)
.required(true)
.add_string_choice_localized(
"Welcome to our cool server! Ask me if you need help",
Expand All @@ -128,36 +116,23 @@ impl EventHandler for Handler {
),
);

let c4 = CreateCommand::default()
.name("numberinput")
.description("Test command for number input")
let c4 = CreateCommand::new("numberinput", "Test command for number input")
.add_option(
CreateOption::default()
.name("int")
.description("An integer from 5 to 10")
.kind(CommandOptionType::Integer)
CreateOption::new(CommandOptionType::Integer, "int", "An integer fro 5 to 10")
.min_int_value(5)
.max_int_value(10)
.required(true),
)
.add_option(
CreateOption::default()
.name("number")
.description("A float from -3.3 to 234.5")
.kind(CommandOptionType::Number)
.min_number_value(-3.3)
CreateOption::new(CommandOptionType::Number, "number", "A float from -3 to 234.5")
.min_number_value(-3.0)
.max_number_value(234.5)
.required(true),
);

let c5 = CreateCommand::default()
.name("attachmentinput")
.description("Test command for attachment input")
let c5 = CreateCommand::new("attachmentinput", "Test command for attachment input")
.add_option(
CreateOption::default()
.name("attachment")
.description("A file")
.kind(CommandOptionType::Attachment)
CreateOption::new(CommandOptionType::Attachment, "attachment", "A file")
.required(true),
);

Expand All @@ -167,7 +142,7 @@ impl EventHandler for Handler {

let guild_command = Command::create_global_application_command(
&ctx.http,
CreateCommand::default().name("wonderful_command").description("An amazing command"),
CreateCommand::new("wonderful_command", "An amazing command"),
)
.await;

Expand Down
43 changes: 21 additions & 22 deletions examples/e17_message_components/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,28 +68,27 @@ impl Animal {
}

fn menu_option(&self) -> CreateSelectMenuOption {
CreateSelectMenuOption::default()
CreateSelectMenuOption::new(
// This is what will be shown to the user
.label(format!("{} {}", self.emoji(), self))
format!("{} {}", self.emoji(), self),
// This is used to identify the selected value
.value(self.to_string().to_ascii_lowercase())
self.to_string().to_ascii_lowercase(),
)
}

fn select_menu() -> CreateSelectMenu {
CreateSelectMenu::default()
.custom_id("animal_select")
.placeholder("No animal selected")
.options(vec![
Self::Cat.menu_option(),
Self::Dog.menu_option(),
Self::Horse.menu_option(),
Self::Alpaca.menu_option(),
])
CreateSelectMenu::new("animal_select", vec![
Self::Cat.menu_option(),
Self::Dog.menu_option(),
Self::Horse.menu_option(),
Self::Alpaca.menu_option(),
])
.placeholder("No animal selected")
}

fn action_row() -> CreateActionRow {
// A select menu must be the only thing in an action row!
CreateActionRow::default().add_select_menu(Self::select_menu())
CreateActionRow::new().add_select_menu(Self::select_menu())
}
}

Expand Down Expand Up @@ -123,7 +122,7 @@ impl Sound {
}

fn button(&self) -> CreateButton {
CreateButton::default()
CreateButton::new()
.custom_id(self.to_string().to_ascii_lowercase())
.emoji(self.emoji())
.label(self.to_string())
Expand All @@ -132,7 +131,7 @@ impl Sound {

fn action_row() -> CreateActionRow {
// We can add up to 5 buttons per action row
CreateActionRow::default()
CreateActionRow::new()
.add_button(Sound::Meow.button())
.add_button(Sound::Woof.button())
.add_button(Sound::Neigh.button())
Expand Down Expand Up @@ -164,8 +163,8 @@ impl EventHandler for Handler {
}

// Ask the user for its favorite animal
let components = CreateComponents::default().add_action_row(Animal::action_row());
let builder = CreateMessage::default()
let components = CreateComponents::new().add_action_row(Animal::action_row());
let builder = CreateMessage::new()
.content("Please select your favorite animal")
.components(components);
let m = msg.channel_id.send_message(&ctx, builder).await.unwrap();
Expand All @@ -190,11 +189,11 @@ impl EventHandler for Handler {
let animal = Animal::from_str(mci.data.values.get(0).unwrap()).unwrap();

// Acknowledge the interaction and edit the message
let components = CreateComponents::default().add_action_row(Sound::action_row());
let data = CreateInteractionResponseData::default()
let components = CreateComponents::new().add_action_row(Sound::action_row());
let data = CreateInteractionResponseData::new()
.content(format!("You chose: **{}**\nNow choose a sound!", animal))
.components(components);
let builder = CreateInteractionResponse::default()
let builder = CreateInteractionResponse::new()
.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(data);
mci.create_interaction_response(&ctx, builder).await.unwrap();
Expand All @@ -209,11 +208,11 @@ impl EventHandler for Handler {
while let Some(mci) = cib.next().await {
let sound = Sound::from_str(&mci.data.custom_id).unwrap();
// Acknowledge the interaction and send a reply
let data = CreateInteractionResponseData::default()
let data = CreateInteractionResponseData::new()
.content(format!("The **{}** says __{}__", animal, sound))
// Make the message hidden for other users by setting `ephemeral(true)`.
.ephemeral(true);
let builder = CreateInteractionResponse::default()
let builder = CreateInteractionResponse::new()
// This time we don't edit the message, but reply to it.
.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(data);
Expand Down
2 changes: 1 addition & 1 deletion examples/e18_webhook/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ async fn main() {
let http = Http::new("");
let webhook = Webhook::from_url(&http, "https://discord.com/api/webhooks/133742013374206969/hello-there-oPNtRN5UY5DVmBe7m1N0HE-replace-me-Dw9LRkgq3zI7LoW3Rb-k-q").await.expect("Replace the webhook with your own");

let builder = ExecuteWebhook::default().content("hello there").username("Webhook test");
let builder = ExecuteWebhook::new().content("hello there").username("Webhook test");
webhook.execute(&http, false, builder).await.expect("Could not execute webhook.");
}
20 changes: 15 additions & 5 deletions src/builder/add_member.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ use crate::model::prelude::*;
/// A builder to add parameters when using [`GuildId::add_member`].
///
/// [`GuildId::add_member`]: crate::model::id::GuildId::add_member
#[derive(Clone, Debug, Default, Serialize)]
#[derive(Clone, Debug, Serialize)]
#[must_use]
pub struct AddMember {
#[serde(skip_serializing_if = "Option::is_none")]
access_token: Option<String>,
access_token: String,
#[serde(skip_serializing_if = "Option::is_none")]
nick: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
Expand All @@ -23,6 +22,17 @@ pub struct AddMember {
}

impl AddMember {
/// Constructs a new builder with the given access token, leaving all other fields empty.
pub fn new(access_token: String) -> Self {
Self {
access_token,
nick: None,
roles: Vec::new(),
mute: None,
deaf: None,
}
}

/// Adds a [`User`] to this guild with a valid OAuth2 access token.
///
/// Returns the created [`Member`] object, or nothing if the user is already a member of the
Expand All @@ -42,11 +52,11 @@ impl AddMember {
http.as_ref().add_guild_member(guild_id.into(), user_id.into(), &self).await
}

/// Sets the OAuth2 access token for this request.
/// Sets the OAuth2 access token for this request, replacing the current one.
///
/// Requires the access token to have the `guilds.join` scope granted.
pub fn access_token(mut self, access_token: impl Into<String>) -> Self {
self.access_token = Some(access_token.into());
self.access_token = access_token.into();
self
}

Expand Down
5 changes: 5 additions & 0 deletions src/builder/bot_auth_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ pub struct CreateBotAuthParameters {
}

impl CreateBotAuthParameters {
/// Equivalent to [`Self::default`].
pub fn new() -> Self {
Self::default()
}

/// Builds the url with the provided data.
#[must_use]
pub fn build(self) -> String {
Expand Down
21 changes: 12 additions & 9 deletions src/builder/create_allowed_mentions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,35 @@ pub enum ParseValue {
/// #
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
/// # let http = Http::new("token");
/// # let b = CreateMessage::default();
/// # let b = CreateMessage::new();
/// # let msg = ChannelId::new(7).message(&http, MessageId::new(8)).await?;
/// use serenity::builder::{CreateAllowedMentions as Am, ParseValue};
///
/// // Mention only the user 110372470472613888
/// # let m = b.clone();
/// m.allowed_mentions(Am::default().users(vec![110372470472613888]));
/// m.allowed_mentions(Am::new().users(vec![110372470472613888]));
///
/// // Mention all users and the role 182894738100322304
/// # let m = b.clone();
/// m.allowed_mentions(Am::default().parse(ParseValue::Users).roles(vec![182894738100322304]));
/// m.allowed_mentions(Am::new().parse(ParseValue::Users).roles(vec![182894738100322304]));
///
/// // Mention all roles and nothing else
/// # let m = b.clone();
/// m.allowed_mentions(Am::default().parse(ParseValue::Roles));
/// m.allowed_mentions(Am::new().parse(ParseValue::Roles));
///
/// // Mention all roles and users, but not everyone
/// # let m = b.clone();
/// m.allowed_mentions(Am::default().parse(ParseValue::Users).parse(ParseValue::Roles));
/// m.allowed_mentions(Am::new().parse(ParseValue::Users).parse(ParseValue::Roles));
///
/// // Mention everyone and the users 182891574139682816, 110372470472613888
/// # let m = b.clone();
/// m.allowed_mentions(
/// Am::default()
/// .parse(ParseValue::Everyone)
/// .users(vec![182891574139682816, 110372470472613888]),
/// Am::new().parse(ParseValue::Everyone).users(vec![182891574139682816, 110372470472613888]),
/// );
///
/// // Mention everyone and the message author.
/// # let m = b.clone();
/// m.allowed_mentions(Am::default().parse(ParseValue::Everyone).users(vec![msg.author.id]));
/// m.allowed_mentions(Am::new().parse(ParseValue::Everyone).users(vec![msg.author.id]));
/// # Ok(())
/// # }
/// ```
Expand All @@ -70,6 +68,11 @@ pub struct CreateAllowedMentions {
}

impl CreateAllowedMentions {
/// Equivalent to [`Self::default`].
pub fn new() -> Self {
Self::default()
}

/// Add a value that's allowed to be mentioned.
///
/// If passing in [`ParseValue::Users`] or [`ParseValue::Roles`], note that later calling
Expand Down
Loading