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

feat(model, http): Add support for guild onboarding #2130

Merged
merged 30 commits into from
Jul 4, 2023

Conversation

suneettipirneni
Copy link
Member

@suneettipirneni suneettipirneni commented Feb 9, 2023

Implements guild onboarding ref: discord/discord-api-docs#5915

This adds the following structures:

  • Onboarding
  • OnboardingPrompt
  • OnboardingPromptOption
  • OnboardingPromptType

As well as supporting the http GET for retrieving guild onboarding information.

Closes #2134

@github-actions github-actions bot added c-http Affects the http crate c-http-ratelimiting Affects the http ratelimiting crate c-model Affects the model crate t-feature Addition of a new feature labels Feb 9, 2023
@zeylahellyer zeylahellyer added d-api Change related to Discord's API. d-not-deployed Discord API change that hasn't been deployed to the docs. labels Feb 10, 2023
Copy link
Member

@vilgotf vilgotf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! We should also open a tracking issue separate from this PR

twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Outdated Show resolved Hide resolved
@vilgotf
Copy link
Member

vilgotf commented Feb 11, 2023

Looks good, I'll re-review this once it lands (as there will likely be changes)

@vilgotf vilgotf self-requested a review February 11, 2023 09:41
@zeylahellyer zeylahellyer added w-do-not-merge PR is blocked or deferred w-needs-testing PR needs to be tested. labels Feb 11, 2023
zeylahellyer and others added 5 commits February 17, 2023 00:24
…2132)

Remove all of the deprecated APIs:

- `twilight_gateway::EventTypeFlags::GUILD_BANS`
- `exec` on all `twilight_http` request builders
- `twilight_http::response::StatusCode::raw`
- `twilight_model::gateway::Intents::GUILD_BANS`
- `twilight_model::guild::GuildFeature::Commerce`
- `twilight_model::guild::GuildFeature::MonetizationEnabled`
- `twilight_model::oauth::current_application_info`
- `twilight_model::user::UserFlags::CERTIFIED_MODERATOR`
The `http` depednency was exposed in `twilight-http`'s `Method`, used
when sending requests. `hyper` (the underlying HTTP crate), however,
accepts string representations of HTTP methods as well, so this switches
to using that instead.

Closes twilight-rs#1456.
Save a bit of space on gateway REST API models by reducing shard ID and
session concurrency and total integer sizes.
Remove the `twilight_model::user::UserProfile` type because it isn't
used anywhere and there doesn't appear to be a history of it being used.
This appears to have been added, likely mistakenly, in the initial model
commit years ago.
A common complaint of users is that HTTP request builder validation is too verbose. Every field of a request builder that does validation returns a `Result`. This is verbose at best, a point of contention in the middle, and a frustration at worst. It means every HTTP call has to be wrapped in order to use `?`, or errors have to be handled locally. Additionally, this is a footgun for Twilight development: if a field has validation added, then it's a breaking change. This encourages us to make every field return a Result, which is even worse for end users. The solution here is to report errors when the request builder has finalized.

We can achieve this by refactoring HTTP request builders to internally wrap the set of fields in a `Result`. Request builder field methods can simply mutate the fields if they aren't wrapped in an error, or make use of `Result::and_then` when performing validation. The builder can then simply return itself instead of wrapping itself in a `Result`.

These errors are realized by end users when calling `IntoFuture::into_future` or `TryIntoRequest::try_into_request` on request builders when they're done building the request. When a validation error occurred during request building, the resulting `ResponseFuture` will resolve to an `Error` of a new error type, `Validation`.

Use Case

People want to be able to create typed HTTP requests with ease. At the same time, these requests should be valid so users aren't sending invalid requests, unnecessarily eating into their global request ratelimit and providing slow responses for users of their application that something went wrong. People can create custom request bodies and they can do their best to make sure they've got it right, but we provide builders for them, and these builders automatically do validation on inputs. At the same time, each field input returns a Result, since something about the field can be wrong.

This gets unruly at scale: do you handle every Result in place? Do you wrap HTTP builder construction so you can `?` your problems away? Or do you take the easy way out and `.unwrap()` it all? What people go with is probably a mixture of all of these, but it's not a great experience in any case. Users already handle a `Result` as the `Output` of the `ResponseFuture`, so they can now also handle another case for validation! This wraps up validation errors with other types of errors nicely.

Technical Implementation

Request builders often store a set of fields, which can contain request body parameters or query parameters

```rust
pub struct CreateMessage<'a> {
    attachment_manager: AttachmentManager<'a>,
    channel_id: Id<ChannelMarker>,
    fields: CreateMessageFields<'a>,
    http: &'a Client,
}
```

The only change here is we wrap the fields in a `Result`:

```diff
pub struct CreateMessage<'a> {
    attachment_manager: AttachmentManager<'a>,
    channel_id: Id<ChannelMarker>,
-    fields: CreateMessageFields<'a>,
+    fields: Result<CreateMessageFields<'a>, MessageValidationError>,
    http: &'a Client,
}
```

Methods that don't validate fields can't just mutate the fields directly, so now they only do so if the fields haven't errored:

```diff
pub fn allowed_mentions(mut self, allowed_mentions: Option<&'a AllowedMentions>) -> Self {
-    fields.allowed_mentions = Some(Nullable(allowed_mentions));
+    if let Ok(fields) = self.fields.as_mut() {
+        fields.allowed_mentions = Some(Nullable(allowed_mentions));
+    }

    self
}
```

Meanwhile, methods that *do* validate their input use `Result::and_then` so that validation can be cleanly done:

```diff
-pub fn embeds(mut self, embeds: &'a [Embed]) -> Result<Self, MessageValidationError> {
+pub fn embeds(mut self, embeds: &'a [Embed]) -> Self {
-    validate_embeds(embeds)?;
-
-    self.fields.embeds = Some(embeds);
+    self.fields = self.fields.and_then(|mut fields| {
+        validate_embeds(embeds)?;
+        fields.embeds = Some(embeds);
+
+        Ok(fields)
+    });

-    Ok(self)
+    self
}
```

Audit log reasons have been similarly changed:

```diff
pub trait AuditLogReason<'a>: private::Sealed {
-    fn reason(self, reason: &'a str) -> Result<Self, ValidationError>
+    fn reason(self, reason: &'a str) -> Self
    where
        Self: Sized;
}
```

```diff
impl<'a> AuditLogReason<'a> for DeleteMessage<'a> {
-    fn reason(mut self, reason: &'a str) -> Self {
-        validate_audit_reason(reason)?;
-
-        self.reason = Some(reason);
+    fn reason(mut self, reason: &'a str) -> Self {
+        self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));

        self
    }
}
```

This is the heart of the changes made. Nothing Earth-shattering, it just had to be done.. for every. Request. We have. Along with removing now-extraneous `?`s on method calls in examples. So the diff is large.

Example

Before:

```rust
let response = client.create_message(channel_id)
  .content("test")?
  .embeds(&embeds)?
  .tts(true)
  .await?;
```

After:

```rust
let response = client.create_message(channel_id)
  .content("test")
  .embeds(&embeds)
  .tts(true)
  .await?;
```

Closes issue twilight-rs#1187.
@vilgotf
Copy link
Member

vilgotf commented Apr 24, 2023

Feature is live, could this be updated?

@suneettipirneni
Copy link
Member Author

Feature is live, could this be updated?

Yeah, I'll try to finish it out this weekend.

@suneettipirneni suneettipirneni self-assigned this Apr 25, 2023
@github-actions github-actions bot added c-cache Affects the cache crate c-mention Affects the mention crate labels Apr 25, 2023
@github-actions github-actions bot added c-gateway Affects the gateway crate c-gateway-queue Affects the gateway queue crate c-lavalink Affects the lavalink crate labels Apr 25, 2023
…into feat/guild-onboarding"

This reverts commit a0e7ec0, reversing
changes made to bebaeb5.
…into feat/guild-onboarding"

This reverts commit d237656, reversing
changes made to 9df0721.
@github-actions github-actions bot removed c-gateway-queue Affects the gateway queue crate c-book Affects the book c-gateway Affects the gateway crate c-lavalink Affects the lavalink crate labels Apr 25, 2023
@github-actions github-actions bot removed the c-cache Affects the cache crate label Apr 25, 2023
@suneettipirneni suneettipirneni removed c-all Affects all crates or the project as a whole w-needs-testing PR needs to be tested. w-do-not-merge PR is blocked or deferred labels Apr 25, 2023
twilight-model/src/guild/onboarding/option.rs Show resolved Hide resolved
twilight-model/src/guild/onboarding/prompt_type.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/prompt_type.rs Outdated Show resolved Hide resolved
Copy link
Member

@vilgotf vilgotf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review.

twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/mod.rs Outdated Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Show resolved Hide resolved
twilight-model/src/guild/onboarding/option.rs Show resolved Hide resolved
twilight-model/src/guild/onboarding/prompt.rs Show resolved Hide resolved
Copy link
Contributor

@HTGAzureX1212 HTGAzureX1212 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Thank you for working on this!

@vilgotf vilgotf merged commit 36f8377 into twilight-rs:main Jul 4, 2023
@suneettipirneni suneettipirneni deleted the feat/guild-onboarding branch July 4, 2023 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c-http Affects the http crate c-http-ratelimiting Affects the http ratelimiting crate c-model Affects the model crate d-api Change related to Discord's API. t-feature Addition of a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support guild onboarding
6 participants