diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4bec79acad..d59cf77c60 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,9 +37,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore dependencies run: | dotnet restore --no-cache -f -v minimal DisCatSharp.sln @@ -62,9 +62,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore Packages run: dotnet restore --no-cache -f -v minimal DisCatSharp.sln - name: Build library diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6eb11e520a..7386673a2b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,9 +43,9 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore dependencies run: dotnet restore --no-cache -f -v minimal DisCatSharp.sln - name: Build diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index a18923d721..44228828bd 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -22,9 +22,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.403 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Git fetch unshallow run: git fetch --unshallow - name: Install DocFX diff --git a/.github/workflows/documentation_test.yml b/.github/workflows/documentation_test.yml index 3c2172b0d2..3e12085da5 100644 --- a/.github/workflows/documentation_test.yml +++ b/.github/workflows/documentation_test.yml @@ -23,9 +23,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.403 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Install DocFX run: dotnet tool update -g docfx continue-on-error: true diff --git a/.github/workflows/internal-release.yml b/.github/workflows/internal-release.yml index d36b1186c0..7a1175781f 100644 --- a/.github/workflows/internal-release.yml +++ b/.github/workflows/internal-release.yml @@ -25,9 +25,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore dependencies run: | dotnet restore --no-cache -f -v minimal DisCatSharp.sln diff --git a/.github/workflows/public-dev-release.yml b/.github/workflows/public-dev-release.yml index a9b7e6945b..47070d1b09 100644 --- a/.github/workflows/public-dev-release.yml +++ b/.github/workflows/public-dev-release.yml @@ -39,9 +39,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore dependencies run: dotnet restore --no-cache -f -v minimal DisCatSharp.sln - name: Set outputs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d53bd91e2d..03e48480f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,9 +55,9 @@ jobs: uses: actions/setup-dotnet@v4.0.1 with: dotnet-version: | - 9.0.100-preview.6.24328.19 - 8.0.301 - 7.0.404 + 9.0.100-preview.7.24407.12 + 8.x + 7.x - name: Restore dependencies (DisCatSharp) if: ${{ github.event.inputs.packages_to_release == 'DisCatSharp' }} run: dotnet restore --no-cache -f -v minimal DisCatSharp.sln diff --git a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs index 1098980b4f..0280162fc3 100644 --- a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs +++ b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs @@ -120,8 +120,8 @@ internal BaseContext(DisCatSharpCommandType type) /// The type of the response. /// The data to be sent, if any. /// - public Task CreateResponseAsync(InteractionResponseType type, DiscordInteractionResponseBuilder builder = null) - => this.Interaction.CreateResponseAsync(type, builder); + public async Task CreateResponseAsync(InteractionResponseType type, DiscordInteractionResponseBuilder? builder = null) + => await this.Interaction.CreateResponseAsync(type, builder); /// /// Creates a modal response to this interaction. diff --git a/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs b/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs index 8b3083990e..01f61db635 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using ConcurrentCollections; @@ -105,17 +106,16 @@ private async Task Handle(DiscordClient _, ComponentInteractionCreateEventArgs a else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); - foreach (var creq in this._collectRequests) - if (creq.Message == args.Message && creq.IsMatch(args)) - { - await args.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate).ConfigureAwait(false); + foreach (var creq in this._collectRequests.Where(creq => creq.Message == args.Message && creq.IsMatch(args))) + { + await args.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate).ConfigureAwait(false); - if (creq.IsMatch(args)) - creq.Collected.Add(args); + if (creq.IsMatch(args)) + creq.Collected.Add(args); - else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) - await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); - } + else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) + await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); + } } /// diff --git a/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs b/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs index df0668ddf2..7f309432e5 100644 --- a/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs +++ b/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs @@ -63,8 +63,7 @@ public static async Task CreatePaginatedModalResponseAsy if (previousInteraction.Type is InteractionType.Ping or InteractionType.ModalSubmit) { - await previousInteraction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, b.OpenMessage.AddComponents(b.OpenButton)).ConfigureAwait(false); - var originalResponse = await previousInteraction.GetOriginalResponseAsync().ConfigureAwait(false); + var originalResponse = await previousInteraction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, b.OpenMessage.AddComponents(b.OpenButton)).ConfigureAwait(false); var modalOpen = await interactivity.WaitForButtonAsync(originalResponse, new List { b.OpenButton diff --git a/DisCatSharp.Interactivity/InteractivityExtension.cs b/DisCatSharp.Interactivity/InteractivityExtension.cs index 259d76d17d..e838dc7470 100644 --- a/DisCatSharp.Interactivity/InteractivityExtension.cs +++ b/DisCatSharp.Interactivity/InteractivityExtension.cs @@ -822,8 +822,7 @@ public async Task SendPaginatedResponseAsync(DiscordInteraction interaction, boo .AddComponents(bts.ButtonArray); if (ephemeral) builder = builder.AsEphemeral(); - await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder).ConfigureAwait(false); - message = await interaction.GetOriginalResponseAsync().ConfigureAwait(false); + message = await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder).ConfigureAwait(false); } var req = new InteractionPaginationRequest(interaction, message, user, bhv, del, bts, pages, token); diff --git a/DisCatSharp.Tests/DisCatSharp.ApplicationCommands.Tests/DisCatSharp.ApplicationCommands.Tests.csproj b/DisCatSharp.Tests/DisCatSharp.ApplicationCommands.Tests/DisCatSharp.ApplicationCommands.Tests.csproj index c034f4925a..8d738b871f 100644 --- a/DisCatSharp.Tests/DisCatSharp.ApplicationCommands.Tests/DisCatSharp.ApplicationCommands.Tests.csproj +++ b/DisCatSharp.Tests/DisCatSharp.ApplicationCommands.Tests/DisCatSharp.ApplicationCommands.Tests.csproj @@ -4,7 +4,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DisCatSharp.Tests/DisCatSharp.Configuration.Tests/DisCatSharp.Configuration.Tests.csproj b/DisCatSharp.Tests/DisCatSharp.Configuration.Tests/DisCatSharp.Configuration.Tests.csproj index fd2282ae61..ca0367f620 100644 --- a/DisCatSharp.Tests/DisCatSharp.Configuration.Tests/DisCatSharp.Configuration.Tests.csproj +++ b/DisCatSharp.Tests/DisCatSharp.Configuration.Tests/DisCatSharp.Configuration.Tests.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DisCatSharp.Tests/DisCatSharp.EventHandlers.Tests/DisCatSharp.EventHandlers.Tests.csproj b/DisCatSharp.Tests/DisCatSharp.EventHandlers.Tests/DisCatSharp.EventHandlers.Tests.csproj index 0190fcad76..40fdac0fb4 100644 --- a/DisCatSharp.Tests/DisCatSharp.EventHandlers.Tests/DisCatSharp.EventHandlers.Tests.csproj +++ b/DisCatSharp.Tests/DisCatSharp.EventHandlers.Tests/DisCatSharp.EventHandlers.Tests.csproj @@ -4,7 +4,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DisCatSharp.Tests/DisCatSharp.Hosting.Tests/DisCatSharp.Hosting.Tests.csproj b/DisCatSharp.Tests/DisCatSharp.Hosting.Tests/DisCatSharp.Hosting.Tests.csproj index 9291635c96..5b60eb3ce8 100644 --- a/DisCatSharp.Tests/DisCatSharp.Hosting.Tests/DisCatSharp.Hosting.Tests.csproj +++ b/DisCatSharp.Tests/DisCatSharp.Hosting.Tests/DisCatSharp.Hosting.Tests.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DisCatSharp.Tests/SafetyTests/DisCatSharp.SafetyTests.csproj b/DisCatSharp.Tests/SafetyTests/DisCatSharp.SafetyTests.csproj index de32674e19..04bc9b2593 100644 --- a/DisCatSharp.Tests/SafetyTests/DisCatSharp.SafetyTests.csproj +++ b/DisCatSharp.Tests/SafetyTests/DisCatSharp.SafetyTests.csproj @@ -5,9 +5,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer.Package/DisCatSharp.Analyzer.Package.csproj b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer.Package/DisCatSharp.Analyzer.Package.csproj index c094429656..41ddece74a 100644 --- a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer.Package/DisCatSharp.Analyzer.Package.csproj +++ b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer.Package/DisCatSharp.Analyzer.Package.csproj @@ -9,8 +9,8 @@ DisCatSharp.Analyzer.Roselyn - 6.2.4 - 6.2.4 + 6.2.5 + 6.2.5 AITSYS false DisCatSharp Analyzer @@ -71,7 +71,7 @@ - + diff --git a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj index 8f9d869544..651257aab2 100644 --- a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj +++ b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/DisCatSharp.Analyzer.csproj @@ -41,7 +41,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/DisCatSharp/Clients/BaseDiscordClient.cs b/DisCatSharp/Clients/BaseDiscordClient.cs index 993bf87b84..b13154a57b 100644 --- a/DisCatSharp/Clients/BaseDiscordClient.cs +++ b/DisCatSharp/Clients/BaseDiscordClient.cs @@ -414,6 +414,7 @@ public async Task GetCurrentApplicationAsync() app.CoverImageHash = tapp.CoverImageHash.ValueOrDefault(); app.Guild = tapp.Guild.ValueOrDefault(); app.ApproximateGuildCount = tapp.ApproximateGuildCount.ValueOrDefault(); + app.ApproximateUserInstallCount = tapp.ApproximateUserInstallCount.ValueOrDefault(); app.RequiresCodeGrant = tapp.BotRequiresCodeGrant.ValueOrDefault(); app.IsPublic = tapp.IsPublicBot.ValueOrDefault(); app.RedirectUris = tapp.RedirectUris.ValueOrDefault(); diff --git a/DisCatSharp/Clients/DiscordClient.cs b/DisCatSharp/Clients/DiscordClient.cs index f9158f983f..2a06e64f08 100644 --- a/DisCatSharp/Clients/DiscordClient.cs +++ b/DisCatSharp/Clients/DiscordClient.cs @@ -1054,6 +1054,16 @@ public bool TryGetSticker(ulong id, [NotNullWhen(true)] out DiscordSticker? stic } } + /// + /// Gets a sticker pack. + /// + /// The sticker pack's id. + /// The sticker pack. + /// Thrown when an invalid parameter was provided. + /// Thrown when Discord is unable to process the request. + public Task GetStickerPackAsync(ulong id) + => this.ApiClient.GetStickerPackAsync(id); + /// /// Gets all nitro sticker packs. /// diff --git a/DisCatSharp/DisCatSharp.csproj b/DisCatSharp/DisCatSharp.csproj index c5cbbed4a1..1f6ad8a76b 100644 --- a/DisCatSharp/DisCatSharp.csproj +++ b/DisCatSharp/DisCatSharp.csproj @@ -40,8 +40,8 @@ - - + + diff --git a/DisCatSharp/Entities/Application/DiscordApplication.cs b/DisCatSharp/Entities/Application/DiscordApplication.cs index 1e7a66f03d..fc9871052b 100644 --- a/DisCatSharp/Entities/Application/DiscordApplication.cs +++ b/DisCatSharp/Entities/Application/DiscordApplication.cs @@ -162,6 +162,11 @@ public override string CoverImageUrl /// public int? ApproximateGuildCount { get; internal set; } + /// + /// Gets the approximate user install count + /// + public int? ApproximateUserInstallCount { get; internal set; } + /// /// Gets the interactions endpoint url. /// diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.cs b/DisCatSharp/Entities/Guild/DiscordGuild.cs index aa2e609908..80353b873b 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuild.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuild.cs @@ -447,6 +447,13 @@ public DiscordMember CurrentMember [JsonIgnore] private readonly Lazy _currentMemberLazy; + /// + /// Gets the current guild member's voice state. + /// + /// + public async Task GetCurrentMemberVoiceStateAsync() + => await this.Discord.ApiClient.GetCurrentUserVoiceStateAsync(this.Id); + /// /// Gets the @everyone role for this guild. /// diff --git a/DisCatSharp/Entities/Guild/DiscordMember.cs b/DisCatSharp/Entities/Guild/DiscordMember.cs index 1705c543e3..6b55266aa5 100644 --- a/DisCatSharp/Entities/Guild/DiscordMember.cs +++ b/DisCatSharp/Entities/Guild/DiscordMember.cs @@ -694,6 +694,13 @@ public Task RemoveAsync(string? reason = null) public Task PlaceInAsync(DiscordChannel channel) => channel.PlaceMemberAsync(this); + /// + /// Gets the member's voice state. + /// + /// + public async Task GetVoiceStateAsync() + => await this.Discord.ApiClient.GetUserVoiceStateAsync(this.Guild.Id, this.Id); + /// /// Updates the member's suppress state in a stage channel. /// diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 3a93c739c6..0c6bf32e85 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -377,6 +377,7 @@ internal void Validate() { if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && !this.Embeds.Any() && !this.Components.Any() && this.Poll is null) throw new ArgumentException("You must specify content, an embed, a component, a poll, or at least one file."); + this.Poll?.Validate(); } } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteraction.cs b/DisCatSharp/Entities/Interaction/DiscordInteraction.cs index 3d6449a175..da1603fc19 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteraction.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteraction.cs @@ -145,8 +145,8 @@ public DiscordChannel Channel /// /// The type of the response. /// The data, if any, to send. - public Task CreateResponseAsync(InteractionResponseType type, DiscordInteractionResponseBuilder builder = null) - => this.Discord.ApiClient.CreateInteractionResponseAsync(this.Id, this.Token, type, builder); + public async Task CreateResponseAsync(InteractionResponseType type, DiscordInteractionResponseBuilder? builder = null) + => await this.Discord.ApiClient.CreateInteractionResponseAsync(this.Id, this.Token, type, builder); /// /// Creates a modal response to this interaction. diff --git a/DisCatSharp/Entities/Message/DiscordAttachment.cs b/DisCatSharp/Entities/Message/DiscordAttachment.cs index c2695f1a73..7988fcd282 100644 --- a/DisCatSharp/Entities/Message/DiscordAttachment.cs +++ b/DisCatSharp/Entities/Message/DiscordAttachment.cs @@ -15,6 +15,12 @@ public class DiscordAttachment : NullableSnowflakeObject [JsonProperty("filename", NullValueHandling = NullValueHandling.Ignore)] public string Filename { get; internal set; } + /// + /// Gets the title of the file. + /// + [JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)] + public string? Title { get; set; } + /// /// Gets the description of the file. /// diff --git a/DisCatSharp/Entities/Message/Polls/DiscordPollBuilder.cs b/DisCatSharp/Entities/Message/Polls/DiscordPollBuilder.cs index 439b41170d..d66d810f94 100644 --- a/DisCatSharp/Entities/Message/Polls/DiscordPollBuilder.cs +++ b/DisCatSharp/Entities/Message/Polls/DiscordPollBuilder.cs @@ -42,7 +42,7 @@ public string Question public PollLayoutType LayoutType { get; internal set; } = PollLayoutType.Default; /// - /// Gets or sets the number of hours the poll should be open for, up to 7 days. + /// Gets or sets the number of hours the poll should be open for, up to 32 days. /// Defaults to 24 hours. /// public int Duration { get; set; } = 24; @@ -127,6 +127,7 @@ public DiscordPollBuilder AddAnswers(IEnumerable answers) { if (answer.PollMedia.Text.Length > 55) throw new ArgumentException($"Answers text cannot exceed 55 characters. Thrown in answer {answerId}"); + answerId++; } @@ -173,7 +174,7 @@ internal void Validate() throw new ArgumentException("You must specify a question."); if (this.Duration > 168) - throw new ArgumentException("Polls can only be open for up to 7 days or 168 hours."); + throw new ArgumentException("Polls can only be open for up to 32 days or 768 hours."); } /// diff --git a/DisCatSharp/Entities/Sticker/DiscordStickerPack.cs b/DisCatSharp/Entities/Sticker/DiscordStickerPack.cs index 8ed9f6e8f9..062538d238 100644 --- a/DisCatSharp/Entities/Sticker/DiscordStickerPack.cs +++ b/DisCatSharp/Entities/Sticker/DiscordStickerPack.cs @@ -51,6 +51,12 @@ public sealed class DiscordStickerPack : SnowflakeObject [JsonProperty("banner_asset_id")] public ulong BannerAssetId { get; internal set; } + /// + /// Gets the descriptions of this pack. + /// + [JsonProperty("description")] + public string Description { get; internal set; } + /// /// Gets the pack's banner url. /// diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 1170096c5a..caab36aa23 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -520,14 +520,12 @@ internal void Validate(bool isModify = false, bool isFollowup = false, bool isIn if (this.AvatarUrl.HasValue) throw new ArgumentException("You cannot change the avatar of an interaction response."); - - if (this.Poll is not null) - throw new InvalidOperationException("You cannnot edit a poll."); } else { if (this.Files?.Count == 0 && string.IsNullOrEmpty(this.Content) && !this.Embeds.Any() && !this.Components.Any() && this.Poll is null) throw new ArgumentException("You must specify content, an embed, a component, a poll, or at least one file."); + this.Poll?.Validate(); } } diff --git a/DisCatSharp/Net/Abstractions/Transport/TransportApplication.cs b/DisCatSharp/Net/Abstractions/Transport/TransportApplication.cs index 1048acebc9..42ae6b1f5d 100644 --- a/DisCatSharp/Net/Abstractions/Transport/TransportApplication.cs +++ b/DisCatSharp/Net/Abstractions/Transport/TransportApplication.cs @@ -169,9 +169,18 @@ internal sealed class TransportApplication : ObservableApiObject [JsonProperty("tags", NullValueHandling = NullValueHandling.Include)] public List? Tags { get; set; } + /// + /// Gets or sets the approximate guild count. + /// [JsonProperty("approximate_guild_count", NullValueHandling = NullValueHandling.Ignore)] public Optional ApproximateGuildCount { get; set; } + /// + /// Gets or sets the approximate user install count. + /// + [JsonProperty("approximate_user_install_count", NullValueHandling = NullValueHandling.Ignore)] + public Optional ApproximateUserInstallCount { get; set; } + /// /// Gets or sets the interactions endpoint url. /// diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index e003cd49b4..9f8e58ad7f 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -12,6 +12,7 @@ using DisCatSharp.Entities; using DisCatSharp.Entities.OAuth2; using DisCatSharp.Enums; +using DisCatSharp.Exceptions; using DisCatSharp.Net.Abstractions; using DisCatSharp.Net.Abstractions.Rest; using DisCatSharp.Net.Serialization; @@ -374,7 +375,7 @@ internal async Task GetGuildAsync(ulong guildId, bool? withCounts) { var urlParams = new Dictionary(); if (withCounts.HasValue) - urlParams["with_counts"] = withCounts?.ToString(); + urlParams["with_counts"] = withCounts.Value.ToString(); var route = $"{Endpoints.GUILDS}/:guild_id"; var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new @@ -1131,7 +1132,7 @@ internal async Task CreateGuildBulkBanAsync(ulong guildI var pld = new RestGuildBulkBanPayload() { UserIds = userIds.ToList(), - DeleteMessageSeconds = deleteMessageSeconds, + DeleteMessageSeconds = deleteMessageSeconds }; var headers = Utilities.GetBaseHeaders(); @@ -1762,6 +1763,30 @@ internal async Task ModifyGuildWelcomeScreenAsync(ulo return ret; } + /// + /// Gets the current user's voice state async. + /// + /// The guild_id. + internal async Task GetCurrentUserVoiceStateAsync(ulong guildId) + { + var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.VOICE_STATES}{Endpoints.ME}"; + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId + }, out var path); + + var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); + try + { + var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); + return DiscordJson.DeserializeObject(res.Response, this.Discord); + } + catch (NotFoundException) + { + return null; + } + } + /// /// Updates the current user voice state async. /// @@ -1788,6 +1813,32 @@ internal async Task UpdateCurrentUserVoiceStateAsync(ulong guildId, ulong channe await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); } + /// + /// Gets the user's voice state async. + /// + /// The guild_id. + /// The user_id. + internal async Task GetUserVoiceStateAsync(ulong guildId, ulong userId) + { + var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.VOICE_STATES}/:user_id"; + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId, + user_id = userId + }, out var path); + + var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); + try + { + var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); + return DiscordJson.DeserializeObject(res.Response, this.Discord); + } + catch (NotFoundException) + { + return null; + } + } + /// /// Updates the user voice state async. /// @@ -5988,7 +6039,7 @@ internal async Task> GetApplicationEmojis var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.EMOJIS}"; var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { - application_id = applicationId, + application_id = applicationId }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); @@ -6043,7 +6094,7 @@ internal async Task CreateApplicationEmojiAsync(ulong a var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.EMOJIS}"; var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { - application_id = applicationId, + application_id = applicationId }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); @@ -6132,6 +6183,24 @@ internal async Task GetStickerAsync(ulong stickerId) return ret; } + /// + /// Gets the sticker pack. + /// + /// The sticker pack's id. + internal async Task GetStickerPackAsync(ulong id) + { + var route = $"{Endpoints.STICKERPACKS}/:pack_id"; + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + pack_id = id + }, out var path); + + var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); + var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); + + return DiscordJson.DeserializeObject(res.Response, this.Discord); + } + /// /// Gets the sticker packs. /// @@ -6699,7 +6768,7 @@ internal async Task DeleteGuildApplicationCommandAsync(ulong applicationId, ulon /// The interaction token. /// The type. /// The builder. - internal async Task CreateInteractionResponseAsync(ulong interactionId, string interactionToken, InteractionResponseType type, DiscordInteractionResponseBuilder builder) + internal async Task CreateInteractionResponseAsync(ulong interactionId, string interactionToken, InteractionResponseType type, DiscordInteractionResponseBuilder? builder) { if (builder?.Embeds != null) foreach (var embed in builder.Embeds) @@ -6790,6 +6859,9 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i if (!string.IsNullOrEmpty(builder.Content) || builder.Embeds?.Count > 0 || builder.IsTts == true || builder.Mentions != null || builder.Files?.Count > 0 || builder.Components?.Count > 0) values["payload_json"] = DiscordJson.SerializeObject(pld); + var headers = Utilities.GetBaseHeaders(); + headers["with_response"] = "true"; + var route = $"{Endpoints.INTERACTIONS}/:interaction_id/:interaction_token{Endpoints.CALLBACK}"; var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { @@ -6797,16 +6869,27 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i interaction_token = interactionToken }, out var path); + RestResponse response; + var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "false").Build(); if (builder != null && values.Count is not 0) { - await this.DoMultipartAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, values: values, files: builder.Files).ConfigureAwait(false); + response = await this.DoMultipartAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, values: values, files: builder.Files).ConfigureAwait(false); foreach (var file in builder.Files.Where(x => x.ResetPositionTo.HasValue)) file.Stream.Position = file.ResetPositionTo.Value; } else - await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); + response = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); + + try + { + return DiscordJson.DeserializeObject(response.Response, this.Discord); + } + catch + { + return null!; + } } /// @@ -7621,5 +7704,4 @@ internal async Task RevokeOAuth2TokenAsync(string token, string type) } #endregion - }