From 1695c1d0def349238cfacaf8597b6840a949878f Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 00:40:23 -0500 Subject: [PATCH 01/32] feat(api): Add integration type to applications --- .../ApplicationIntegrationType.cs | 39 +++++++++++++++++++ .../API/Rest/IDiscordRestApplicationAPI.cs | 2 + .../Applications/DiscordRestApplicationAPI.cs | 2 + .../DiscordRestApplicationAPITests.cs | 19 ++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs new file mode 100644 index 0000000000..ae72e3bd5a --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs @@ -0,0 +1,39 @@ +// +// ApplicationIntegrationType.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents valid locations for users to install application integrations. +/// +public enum ApplicationIntegrationType +{ + /// + /// Specifies that the integration can be installed on a guild. + /// + GuildInstallable, + + /// + /// Specifies that the integration can be installed on a user. + /// + UserInstallable +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs index a3b097bd2b..c8c773b023 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs @@ -394,6 +394,7 @@ Task>> UpdateApplicatio /// The new cover image. /// The new interactions endpoint URL. /// The new tags. + /// The new integration types. /// The cancellation token for this operation. /// The updated application. Task> EditCurrentApplicationAsync @@ -407,6 +408,7 @@ Task> EditCurrentApplicationAsync Optional coverImage = default, Optional interactionsEndpointUrl = default, Optional> tags = default, + Optional> integrationTypes = default, CancellationToken ct = default ); } diff --git a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs index 783423d158..8daab0e12f 100644 --- a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs @@ -667,6 +667,7 @@ public async Task> EditCurrentApplicationAsync Optional coverImage = default, Optional interactionsEndpointUrl = default, Optional> tags = default, + Optional> integrationTypes = default, CancellationToken ct = default ) { @@ -709,6 +710,7 @@ public async Task> EditCurrentApplicationAsync json.Write("cover_image", base64EncodedCover, this.JsonOptions); json.Write("interactions_endpoint_url", interactionsEndpointUrl, this.JsonOptions); json.Write("tags", tags, this.JsonOptions); + json.Write("integration_types", integrationTypes, this.JsonOptions); } ); diff --git a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs index 7e4cc05eee..e77b62276e 100644 --- a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs +++ b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs @@ -2495,6 +2495,12 @@ public async Task PerformsRequestCorrectly() var interactionsEndpointUrl = new Uri("https://example.org/interact"); var tags = new[] { "ooga", "booga" }; + var integrationTypes = new[] + { + ApplicationIntegrationType.UserInstallable, + ApplicationIntegrationType.GuildInstallable + }; + var api = CreateAPI ( b => b @@ -2534,6 +2540,16 @@ public async Task PerformsRequestCorrectly() .WithElement(1, e => e.Is("booga")) ) ) + .WithProperty + ( + "integration_types", + p => p.IsArray + ( + a => a + .WithElement(0, e => e.Is((int)ApplicationIntegrationType.UserInstallable)) + .WithElement(1, e => e.Is((int)ApplicationIntegrationType.GuildInstallable)) + ) + ) ) ) .Respond("application/json", SampleRepository.Samples[typeof(IApplication)]) @@ -2549,7 +2565,8 @@ public async Task PerformsRequestCorrectly() icon, cover, interactionsEndpointUrl, - tags + tags, + integrationTypes ); ResultAssert.Successful(result); From deef93ec35d03398c70cb39e4af42ba32c5c6964 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:18:29 -0500 Subject: [PATCH 02/32] feat(api): Add contexts --- .../ApplicationCommandContextType.cs | 44 +++++++++++++++++ .../IApplicationCommand.cs | 10 ++++ .../Interactions/IInteractionCallbackHint.cs | 47 +++++++++++++++++++ .../InteractionCallbackEphemerality.cs | 39 +++++++++++++++ .../ApplicationCommands/ApplicationCommand.cs | 4 +- .../Interactions/InteractionCallbackHint.cs | 36 ++++++++++++++ 6 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs new file mode 100644 index 0000000000..2d9904ae3f --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs @@ -0,0 +1,44 @@ +// +// ApplicationCommandContextType.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents valid contexts for application commands to be executed. +/// +public enum ApplicationCommandContextType +{ + /// + /// Specifies that the command can be invoked in a guild. + /// + Guild, + + /// + /// Specifies that the command can be invoked in the corresponding bot's DM. + /// + BotDM, + + /// + /// Specifies that the command can be invoked in a DM (Private Channel). + /// + PrivateChannel +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs index 61fbeb55d0..8e96ba16f2 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs @@ -114,4 +114,14 @@ public interface IApplicationCommand /// Gets a value indicating whether this command is age-restricted. /// Optional IsNsfw { get; } + + /// + /// Gets a value indicating the contexts in which this command can be installed. + /// + Optional> AllowedIntegrationTypes { get; } + + /// + /// Gets a value indicating the contexts in which this command can be invoked. + /// + Optional> AllowedContextTypes { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs new file mode 100644 index 0000000000..8c4edfded1 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs @@ -0,0 +1,47 @@ +// +// IInteractionCallbackHint.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents a hint to Discord about how to handle an interaction callback. +/// +public interface IInteractionCallbackHint +{ + /// + /// Gets a value specifying the allowed callback types. + /// + IReadOnlyList AllowedCallbackTypes { get; } + + /// + /// Gets a value specifying the ephemeral nature of the callback, if required. + /// + Optional Ephemerality { get; } + + /// + /// Gets a value specifying the required permissions for the callback, if required. + /// + Optional RequiredPermissions { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs new file mode 100644 index 0000000000..c565999497 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs @@ -0,0 +1,39 @@ +// +// InteractionCallbackEphemerality.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents the ephemeral-ness of a command. +/// +public enum InteractionCallbackEphemerality +{ + /// + /// Represents that an ephemeral response is optional. + /// + Optional, + + /// + /// Represents that am ephemeral response is required. + /// + Required +} diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs index fd7a81b558..8af074ae41 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs @@ -47,5 +47,7 @@ public record ApplicationCommand Optional DescriptionLocalized = default, IDiscordPermissionSet? DefaultMemberPermissions = default, Optional DMPermission = default, - Optional IsNsfw = default + Optional IsNsfw = default, + Optional> AllowedIntegrationTypes = default, + Optional> AllowedContextTypes = default ) : IApplicationCommand; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs new file mode 100644 index 0000000000..1e730655b2 --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs @@ -0,0 +1,36 @@ +// +// InteractionCallbackHint.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Objects; + +/// +public record InteractionCallbackHint +( + IReadOnlyList AllowedCallbackTypes, + Optional Ephemerality, + Optional RequiredPermissions +) +: IInteractionCallbackHint; From 81544f7a09fd1255ed1eefad92967c0a2a85f472 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:35:55 -0500 Subject: [PATCH 03/32] feat(commands): Add new hint attributes --- .../Attributes/AllowedContextsAttribute.cs | 42 ++++++++++++ .../InteractionCallbackHintAttribute.cs | 64 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs create mode 100644 Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs diff --git a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs new file mode 100644 index 0000000000..4b1629da36 --- /dev/null +++ b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs @@ -0,0 +1,42 @@ +// +// AllowedContextsAttribute.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Remora.Discord.API.Abstractions.Objects; + +namespace Remora.Discord.Commands.Attributes; + +/// +/// Defines the contexts in which a command can be invoked. +/// +/// The contexts the command can be invoked. +[PublicAPI] +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class AllowedContextsAttribute(IReadOnlyList allowedContexts) : Attribute +{ + /// + /// Gets a value specifying the allowed contexts. + /// + public IReadOnlyList AllowedContexts { get; } = allowedContexts; +} diff --git a/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs b/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs new file mode 100644 index 0000000000..711234091f --- /dev/null +++ b/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs @@ -0,0 +1,64 @@ +// +// InteractionCallbackHintAttribute.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Discord.API.Objects; +using Remora.Rest.Core; + +namespace Remora.Discord.Commands.Attributes; + +/// +/// Represents a hint to Discord for how to handle an interaction callback. +/// +/// The allowed callback types. +/// Represents a hint as to whether the command can/will respond ephemerally. +/// If specifies a type that creates or updates a message, the required permissions. +[PublicAPI] +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class InteractionCallbackHintAttribute +( + IReadOnlyList allowedCallbackTypes, + InteractionCallbackEphemerality? ephemerality = default, + IReadOnlyList? requiredPermissions = default +) : Attribute +{ + /// + /// Gets a value specifying the allowed callback types. + /// + public IReadOnlyList AllowedCallbackTypes { get; } = allowedCallbackTypes; + + /// + /// Gets a value specifying the ephemeral nature of the callback, if required. + /// + public Optional Ephemerality { get; } = ephemerality.AsOptional(); + + /// + /// Gets a value specifying the required permissions for the callback, if required. + /// + public Optional RequiredPermissions { get; } = requiredPermissions + .AsOptional() + .Map(t => (IDiscordPermissionSet)new DiscordPermissionSet(t.ToArray())); +} From bcad4cbaf32e2ed01a2636ce2e8f3040e933c6f8 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:46:26 -0500 Subject: [PATCH 04/32] fix(api): Set property names in converter --- .../Extensions/ServiceCollectionExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index 61b65e5267..76425da4ee 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1052,7 +1052,9 @@ private static JsonSerializerOptions AddInteractionObjectConverters(this JsonSer options.AddDataObjectConverter(); options.AddDataObjectConverter() - .WithPropertyName(d => d.IsNsfw, "nsfw"); + .WithPropertyName(d => d.IsNsfw, "nsfw") + .WithPropertyName(d => d.AllowedContextTypes, "contexts") + .WithPropertyName(d => d.AllowedIntegrationTypes, "integration_types"); options.AddDataObjectConverter() .WithPropertyName(o => o.IsDefault, "default") From 3a1f9c1b2c688bb184edc817f1321bc6f7d228d8 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 02:10:59 -0500 Subject: [PATCH 05/32] feat(api): Add AuthorizingIntegrationOwners --- .../API/Objects/Interactions/IInteraction.cs | 5 +++++ .../API/Objects/Interactions/Interaction.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs index ef3ce30c89..92c56209af 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs @@ -122,4 +122,9 @@ public interface IInteraction /// Gets, for monetized apps, any entitlements for the invoking user. /// IReadOnlyList Entitlements { get; } + + /// + /// Gets the authorizing integration owners, that is, the entity that has the integration installed. + /// + Optional> AuthorizingIntegrationOwners { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs index 6aabaa483b..3ad4be5faa 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs @@ -49,5 +49,6 @@ public record Interaction Optional AppPermissions, Optional Locale, Optional GuildLocale, - IReadOnlyList Entitlements + IReadOnlyList Entitlements, + Optional> AuthorizingIntegrationOwners ) : IInteraction; From 43840e5f2dc6f334c1b03f046e5d504ead177f02 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 02:13:46 -0500 Subject: [PATCH 06/32] fix(api): Add property mappings to bulk data as well --- .../ApplicationCommands/IBulkApplicationCommandData.cs | 6 ++++++ .../ApplicationCommands/BulkApplicationCommandData.cs | 4 +++- .../Extensions/ServiceCollectionExtensions.cs | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs index 8fe59b2d65..39767a00c7 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs @@ -61,4 +61,10 @@ public interface IBulkApplicationCommandData /// Optional IsNsfw { get; } + + /// + Optional> AllowedIntegrationTypes { get; } + + /// + Optional> AllowedContextTypes { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs index 9c19c5c6f0..79a209389e 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs @@ -40,5 +40,7 @@ public record BulkApplicationCommandData Optional?> DescriptionLocalizations = default, IDiscordPermissionSet? DefaultMemberPermissions = default, Optional DMPermission = default, - Optional IsNsfw = default + Optional IsNsfw = default, + Optional> AllowedIntegrationTypes = default, + Optional> AllowedContextTypes = default ) : IBulkApplicationCommandData; diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index 76425da4ee..d0851d9223 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1064,7 +1064,9 @@ private static JsonSerializerOptions AddInteractionObjectConverters(this JsonSer options.AddDataObjectConverter(); options.AddDataObjectConverter(); options.AddDataObjectConverter() - .WithPropertyName(d => d.IsNsfw, "nsfw"); + .WithPropertyName(d => d.IsNsfw, "nsfw") + .WithPropertyName(d => d.AllowedContextTypes, "contexts") + .WithPropertyName(d => d.AllowedIntegrationTypes, "integration_types"); options.AddDataObjectConverter < From da1dade3830f93dfbee5cd908fc392d78f234d37 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 02:19:12 -0500 Subject: [PATCH 07/32] fix(api): Add missing parameter to InteractionCreate --- .../API/Gateway/Events/Interactions/InteractionCreate.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs b/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs index 5f86584432..5f9f0015f6 100644 --- a/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs +++ b/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs @@ -50,5 +50,6 @@ public record InteractionCreate Optional AppPermissions, Optional Locale, Optional GuildLocale, - IReadOnlyList Entitlements + IReadOnlyList Entitlements, + Optional> AuthorizingIntegrationOwners ) : IInteractionCreate; From aefd709095d2d16a2100ac91c9dab665e7606730 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 03:46:17 -0500 Subject: [PATCH 08/32] feat(api): Add interaction callback hints This may be non-functional at time of commit! --- .../Interactions/ApplicationCommands/IApplicationCommand.cs | 5 +++++ .../ApplicationCommands/IBulkApplicationCommandData.cs | 3 +++ .../ApplicationCommands/BulkApplicationCommandData.cs | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs index 8e96ba16f2..a72ef24fb8 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs @@ -124,4 +124,9 @@ public interface IApplicationCommand /// Gets a value indicating the contexts in which this command can be invoked. /// Optional> AllowedContextTypes { get; } + + /// + /// Gets a value indicating the callback hint for this command. + /// + Optional InteractionCallbackHint { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs index 39767a00c7..399eee8764 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs @@ -67,4 +67,7 @@ public interface IBulkApplicationCommandData /// Optional> AllowedContextTypes { get; } + + /// + Optional InteractionCallbackHint { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs index 79a209389e..0dc1a45750 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs @@ -42,5 +42,6 @@ public record BulkApplicationCommandData Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> AllowedContextTypes = default, + Optional InteractionCallbackHint = default ) : IBulkApplicationCommandData; From 7a9df56525e61559a0525c44297d0ad7fc82f4e7 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 03:46:29 -0500 Subject: [PATCH 09/32] feat(commands): Add missing install context attribute --- .../DiscordInstallContextAttribute.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs diff --git a/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs b/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs new file mode 100644 index 0000000000..815719755f --- /dev/null +++ b/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs @@ -0,0 +1,39 @@ +// +// DiscordInstallContextAttribute.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System; +using System.Collections.Generic; +using Remora.Discord.API.Abstractions.Objects; + +namespace Remora.Discord.Commands.Attributes; + +/// +/// Specifies that the command is valid to install in the given contexts. +/// +/// The contexts that the command can be installed into. +public class DiscordInstallContextAttribute(params ApplicationIntegrationType[] installTypes) : Attribute +{ + /// + /// Gets a value specifying the contexts that the command can be installed into. + /// + public IReadOnlyList InstallTypes { get; } = installTypes; +} From 4be9310d2201160925e527bffcffcb7af8c4b78e Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 03:49:21 -0500 Subject: [PATCH 10/32] feat(commands): Add support for user commands N.B: It is important to note that Remora allows: - Automatic framework responses - Those responses to be made ephemeral Because of this, it brings into question whether there should be validation on the account that a command may be marked as ephemeral, (or worse, may be marked as NON-ephemeral) when the callback hint would indicate that the opposite is true. This behavior- or lack thereof- is technically spawned from developer error, despite being the framework's decision on how to handle commands. --- .../Extensions/CommandTreeExtensions.cs | 131 +++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index 313a176224..4cff1253f8 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -199,7 +199,7 @@ public static IReadOnlyList CreateApplicationComman } // Translate from options to bulk data - var (commandType, directMessagePermission, defaultMemberPermissions, isNsfw) = GetNodeMetadata(node); + var (commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedInstalls, allowedContexts, callbackHint) = GetNodeMetadata(node); var localizedNames = localizationProvider.GetStrings(option.Name); var localizedDescriptions = localizationProvider.GetStrings(option.Description); @@ -217,7 +217,10 @@ public static IReadOnlyList CreateApplicationComman localizedDescriptions.Count > 0 ? new(localizedDescriptions) : default, defaultMemberPermissions, directMessagePermission, - isNsfw + isNsfw, + allowedInstalls, + allowedContexts, + callbackHint ) ); } @@ -241,6 +244,9 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) Optional directMessagePermission = default; IDiscordPermissionSet? defaultMemberPermissions = default; Optional isNsfw = default; + Optional> allowedIntegrationTypes = default; + Optional> allowedContextTypes = default; + Optional interactionCallbackHint = default; switch (node) { @@ -321,6 +327,85 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) isNsfw = nsfwAttribute.IsNsfw; } + var contextsAttributes = groupNode.GroupTypes.Select + ( + t => t.GetCustomAttribute() + ); + + var contexts = contextsAttributes + .Where(attribute => attribute is not null) + .ToArray(); + + if (contexts.Length > 1) + { + throw new InvalidNodeException + ( + $"In a set of groups with the same name, only one may be marked with a context attribute, but " + + $"{contexts.Length} were found.", + node + ); + } + + var context = contexts.SingleOrDefault(); + + if (context is not null) + { + allowedContextTypes = context.AllowedContexts.AsOptional(); + } + + var integrationAttributes = groupNode.GroupTypes.Select + ( + t => t.GetCustomAttribute() + ); + + var integrations = integrationAttributes + .Where(attribute => attribute is not null) + .ToArray(); + + if (integrations.Length > 1) + { + throw new InvalidNodeException + ( + $"In a set of groups with the same name, only one may be marked with an integration attribute, but " + + $"{integrations.Length} were found.", + node + ); + } + + var integrationsAttributes = groupNode.GroupTypes.Select + ( + t => t.GetCustomAttribute() + ); + + var callbackHintAttributes = groupNode.GroupTypes.Select + ( + t => t.GetCustomAttribute() + ); + + var callbackHints = callbackHintAttributes + .Where(attribute => attribute is not null) + .ToArray(); + + if (callbackHints.Length > 1) + { + throw new InvalidNodeException + ( + $"In a set of groups with the same name, only one may be marked with an callback hint attribute, but " + + $"{callbackHints.Length} were found.", + node + ); + } + + if (callbackHints.SingleOrDefault() is { } hintData) + { + interactionCallbackHint = new InteractionCallbackHint + ( + hintData.AllowedCallbackTypes, + hintData.Ephemerality, + hintData.RequiredPermissions + ); + } + break; } case CommandNode commandNode: @@ -358,11 +443,43 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) isNsfw = nsfwAttribute.IsNsfw; } + var contextsAttribute = + commandNode.GroupType.GetCustomAttribute() ?? + commandNode.CommandMethod.GetCustomAttribute(); + + if (contextsAttribute is not null) + { + allowedContextTypes = contextsAttribute.AllowedContexts.AsOptional(); + } + + var integrationAttribute = + commandNode.GroupType.GetCustomAttribute() ?? + commandNode.CommandMethod.GetCustomAttribute(); + + if (integrationAttribute is not null) + { + allowedIntegrationTypes = integrationAttribute.InstallTypes.AsOptional(); + } + + var callbackHintAttribute = + commandNode.GroupType.GetCustomAttribute() ?? + commandNode.CommandMethod.GetCustomAttribute(); + + if (callbackHintAttribute is not null) + { + interactionCallbackHint = new InteractionCallbackHint + ( + callbackHintAttribute.AllowedCallbackTypes, + callbackHintAttribute.Ephemerality, + callbackHintAttribute.RequiredPermissions + ); + } + break; } } - return new(commandType, directMessagePermission, defaultMemberPermissions, isNsfw); + return new(commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedIntegrationTypes, allowedContextTypes, interactionCallbackHint); } private static IApplicationCommandOption? TranslateCommandNode @@ -1043,11 +1160,17 @@ Optional MaxLength /// The DM permission requested for the node. /// The default member permission requested for the node. /// The age restriction requested for the node. + /// The integration types allowed for the node. + /// The context types allowed for the node. + /// The interaction callback hint for the node. private sealed record TopLevelMetadata ( Optional CommandType, Optional DirectMessagePermission, IDiscordPermissionSet? DefaultMemberPermission, - Optional IsNsfw + Optional IsNsfw, + Optional> AllowedIntegrationTypes, + Optional> AllowedContextTypes, + Optional InteractionCallbackHint ); } From 67184273b4b1cba22751a3e7ff1e2c8f8fdd800c Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 04:14:16 -0500 Subject: [PATCH 11/32] refactor(api)!: Make allowed contexts be `params` BREAKING-CHANGE: This changes the constructor of the `AllowedContextsAttribute` to take a `params ApplicationCommandContextType[]` instead of an `IReadOnlyList` --- .../Attributes/AllowedContextsAttribute.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs index 4b1629da36..9b84a4fc8d 100644 --- a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs +++ b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; @@ -33,10 +34,10 @@ namespace Remora.Discord.Commands.Attributes; /// The contexts the command can be invoked. [PublicAPI] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -public class AllowedContextsAttribute(IReadOnlyList allowedContexts) : Attribute +public class AllowedContextsAttribute(params ApplicationCommandContextType[] allowedContexts) : Attribute { /// /// Gets a value specifying the allowed contexts. /// - public IReadOnlyList AllowedContexts { get; } = allowedContexts; + public IReadOnlyList AllowedContexts { get; } = allowedContexts.ToArray(); } From d1fe3d87ad858b2fbed12f85fea5e970f3d77895 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Thu, 30 Nov 2023 04:39:51 -0500 Subject: [PATCH 12/32] fix(api): Add missing interaction property --- .../Interactions/ApplicationCommands/ApplicationCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs index 8af074ae41..95c474df4b 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs @@ -49,5 +49,6 @@ public record ApplicationCommand Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> AllowedContextTypes = default, + Optional InteractionCallbackHint = default ) : IApplicationCommand; From a5d9e3be602978fe8ab6efcb45bc3eb4aa105cd4 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:13:23 -0400 Subject: [PATCH 13/32] feat: Implement integration type configurations --- .../API/Objects/Applications/IApplication.cs | 8 ++++ ...ApplicationIntegrationTypeConfiguration.cs | 34 ++++++++++++++ .../IApplicationOAuth2InstallParams.cs | 44 +++++++++++++++++++ .../Applications/IPartialApplication.cs | 3 ++ .../API/Objects/Applications/Application.cs | 1 + .../Applications/PartialApplication.cs | 3 +- 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs index a6a26b7ef9..317ba0644f 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs @@ -165,6 +165,11 @@ public interface IApplication : IPartialApplication /// new Optional CustomInstallUrl { get; } + /// + /// Gets the application's integration type configurations. + /// + new IReadOnlyDictionary> IntegrationTypeConfigurations { get; } + /// Optional IPartialApplication.ID => this.ID; @@ -242,4 +247,7 @@ public interface IApplication : IPartialApplication /// Optional IPartialApplication.CustomInstallUrl => this.CustomInstallUrl; + + /// + Optional>> IPartialApplication.IntegrationTypeConfigurations => new(this.IntegrationTypeConfigurations); } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs new file mode 100644 index 0000000000..a287a2c772 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs @@ -0,0 +1,34 @@ +// +// IApplicationIntegrationTypeConfiguration.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// The integration type configuration for an application. +/// +public interface IApplicationIntegrationTypeConfiguration +{ + /// + /// Gets the OAuth2 install parameters for the integration type. + /// + public IApplicationOAuth2InstallParams OAuth2InstallParams { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs new file mode 100644 index 0000000000..99a4a72bbf --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs @@ -0,0 +1,44 @@ +// +// IApplicationOAuth2InstallParams.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents the OAuth2 install parameters for an application. +/// +public interface IApplicationOAuth2InstallParams +{ + /// + /// Gets the permissions required for the application. + /// + /// + /// Only applicable if includes `bot`. + /// + IDiscordPermissionSet Permissions { get; } + + /// + /// Gets the list of OAuth2 scopes required for the application. + /// + IReadOnlyList Scopes { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs index f76a9d52f9..d9e7807cda 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs @@ -110,4 +110,7 @@ public interface IPartialApplication /// Optional CustomInstallUrl { get; } + + /// + Optional>> IntegrationTypeConfigurations { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs index cb27e7571e..fbd9c2ebf7 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs @@ -47,6 +47,7 @@ public record Application Optional Owner, string VerifyKey, ITeam? Team, + IReadOnlyDictionary> IntegrationTypeConfigurations, Optional GuildID = default, Optional Guild = default, Optional PrimarySKUID = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs index 4a1550ad49..080ef5bc5a 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs @@ -59,5 +59,6 @@ public record PartialApplication Optional RoleConnectionsVerificationUrl = default, Optional> Tags = default, Optional InstallParams = default, - Optional CustomInstallUrl = default + Optional CustomInstallUrl = default, + Optional>> IntegrationTypeConfigurations = default ) : IPartialApplication; From 35745b746799d88ae7a28c459805318c23d158b4 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:17:16 -0400 Subject: [PATCH 14/32] refactor: Remove interaction callback hints --- .../IBulkApplicationCommandData.cs | 3 -- .../Interactions/IInteractionCallbackHint.cs | 47 ------------------- .../BulkApplicationCommandData.cs | 3 +- .../Interactions/InteractionCallbackHint.cs | 36 -------------- .../Extensions/CommandTreeExtensions.cs | 32 ++----------- 5 files changed, 5 insertions(+), 116 deletions(-) delete mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs delete mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs index 399eee8764..39767a00c7 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs @@ -67,7 +67,4 @@ public interface IBulkApplicationCommandData /// Optional> AllowedContextTypes { get; } - - /// - Optional InteractionCallbackHint { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs deleted file mode 100644 index 8c4edfded1..0000000000 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteractionCallbackHint.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// IInteractionCallbackHint.cs -// -// Author: -// Jarl Gullberg -// -// Copyright (c) Jarl Gullberg -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// - -using System.Collections.Generic; -using Remora.Rest.Core; - -namespace Remora.Discord.API.Abstractions.Objects; - -/// -/// Represents a hint to Discord about how to handle an interaction callback. -/// -public interface IInteractionCallbackHint -{ - /// - /// Gets a value specifying the allowed callback types. - /// - IReadOnlyList AllowedCallbackTypes { get; } - - /// - /// Gets a value specifying the ephemeral nature of the callback, if required. - /// - Optional Ephemerality { get; } - - /// - /// Gets a value specifying the required permissions for the callback, if required. - /// - Optional RequiredPermissions { get; } -} diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs index 0dc1a45750..79a209389e 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs @@ -42,6 +42,5 @@ public record BulkApplicationCommandData Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default, - Optional InteractionCallbackHint = default + Optional> AllowedContextTypes = default ) : IBulkApplicationCommandData; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs deleted file mode 100644 index 1e730655b2..0000000000 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/InteractionCallbackHint.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// InteractionCallbackHint.cs -// -// Author: -// Jarl Gullberg -// -// Copyright (c) Jarl Gullberg -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// - -using System.Collections.Generic; -using Remora.Discord.API.Abstractions.Objects; -using Remora.Rest.Core; - -namespace Remora.Discord.API.Objects; - -/// -public record InteractionCallbackHint -( - IReadOnlyList AllowedCallbackTypes, - Optional Ephemerality, - Optional RequiredPermissions -) -: IInteractionCallbackHint; diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index 4cff1253f8..b9573443a5 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -199,7 +199,7 @@ public static IReadOnlyList CreateApplicationComman } // Translate from options to bulk data - var (commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedInstalls, allowedContexts, callbackHint) = GetNodeMetadata(node); + var (commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedInstalls, allowedContexts) = GetNodeMetadata(node); var localizedNames = localizationProvider.GetStrings(option.Name); var localizedDescriptions = localizationProvider.GetStrings(option.Description); @@ -219,8 +219,7 @@ public static IReadOnlyList CreateApplicationComman directMessagePermission, isNsfw, allowedInstalls, - allowedContexts, - callbackHint + allowedContexts ) ); } @@ -246,7 +245,6 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) Optional isNsfw = default; Optional> allowedIntegrationTypes = default; Optional> allowedContextTypes = default; - Optional interactionCallbackHint = default; switch (node) { @@ -396,16 +394,6 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) ); } - if (callbackHints.SingleOrDefault() is { } hintData) - { - interactionCallbackHint = new InteractionCallbackHint - ( - hintData.AllowedCallbackTypes, - hintData.Ephemerality, - hintData.RequiredPermissions - ); - } - break; } case CommandNode commandNode: @@ -465,21 +453,11 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) commandNode.GroupType.GetCustomAttribute() ?? commandNode.CommandMethod.GetCustomAttribute(); - if (callbackHintAttribute is not null) - { - interactionCallbackHint = new InteractionCallbackHint - ( - callbackHintAttribute.AllowedCallbackTypes, - callbackHintAttribute.Ephemerality, - callbackHintAttribute.RequiredPermissions - ); - } - break; } } - return new(commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedIntegrationTypes, allowedContextTypes, interactionCallbackHint); + return new(commandType, directMessagePermission, defaultMemberPermissions, isNsfw, allowedIntegrationTypes, allowedContextTypes); } private static IApplicationCommandOption? TranslateCommandNode @@ -1162,7 +1140,6 @@ Optional MaxLength /// The age restriction requested for the node. /// The integration types allowed for the node. /// The context types allowed for the node. - /// The interaction callback hint for the node. private sealed record TopLevelMetadata ( Optional CommandType, @@ -1170,7 +1147,6 @@ private sealed record TopLevelMetadata IDiscordPermissionSet? DefaultMemberPermission, Optional IsNsfw, Optional> AllowedIntegrationTypes, - Optional> AllowedContextTypes, - Optional InteractionCallbackHint + Optional> AllowedContextTypes ); } From 21e27a0f2e9adaf6dd3ad259b22f8e1cb1e42e8e Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:17:16 -0400 Subject: [PATCH 15/32] refactor: Remove interaction callback hints --- .../Interactions/ApplicationCommands/IApplicationCommand.cs | 5 ----- .../Interactions/ApplicationCommands/ApplicationCommand.cs | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs index a72ef24fb8..8e96ba16f2 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs @@ -124,9 +124,4 @@ public interface IApplicationCommand /// Gets a value indicating the contexts in which this command can be invoked. /// Optional> AllowedContextTypes { get; } - - /// - /// Gets a value indicating the callback hint for this command. - /// - Optional InteractionCallbackHint { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs index 95c474df4b..8af074ae41 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs @@ -49,6 +49,5 @@ public record ApplicationCommand Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default, - Optional InteractionCallbackHint = default + Optional> AllowedContextTypes = default ) : IApplicationCommand; From dbb4862f76d41cedda96896d9a5b0a6ea9c3e662 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:59:12 -0400 Subject: [PATCH 16/32] feat: Implement bulk of changes for user apps --- .../IApplicationCommandInteractionMetadata.cs | 34 ++++++++++ .../API/Objects/Interactions/IInteraction.cs | 18 ++++- .../IMessageComponentInteractionMetadata.cs | 36 ++++++++++ .../IMessageInteractionMetadata.cs | 66 +++++++++++++++++++ .../IModalSubmitInteractionMetadata.cs | 36 ++++++++++ .../Interactions/InteractionContextType.cs | 44 +++++++++++++ .../API/Objects/Messages/IMessage.cs | 9 +++ .../API/Objects/Messages/IPartialMessage.cs | 4 ++ .../Remora.Discord.API.Abstractions.csproj | 9 +++ .../Events/Interactions/InteractionCreate.cs | 3 +- .../Gateway/Events/Messages/MessageCreate.cs | 4 +- .../Gateway/Events/Messages/MessageUpdate.cs | 4 +- .../ApplicationCommandInteractionMetadata.cs | 38 +++++++++++ .../API/Objects/Interactions/Interaction.cs | 3 +- .../MessageComponentInteractionMetadata.cs | 38 +++++++++++ .../ModalSubmitInteractionMetadata.cs | 39 +++++++++++ .../API/Objects/Messages/Message.cs | 4 +- .../API/Objects/Messages/PartialMessage.cs | 4 +- 18 files changed, 385 insertions(+), 8 deletions(-) create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs new file mode 100644 index 0000000000..3bb4ca0ba6 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs @@ -0,0 +1,34 @@ +// +// IApplicationCommandInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents metadata related to application commands. +/// +public interface IApplicationCommandInteractionMetadata : IMessageInteractionMetadata +{ + /// + /// Gets the name of the command. + /// + string Name { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs index 92c56209af..52a8c6ea2f 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IInteraction.cs @@ -103,7 +103,7 @@ public interface IInteraction /// /// Gets the computed permissions for the application in the context of the interaction's execution. /// - Optional AppPermissions { get; } + IDiscordPermissionSet AppPermissions { get; } /// /// Gets the locale of the invoking user. @@ -124,7 +124,21 @@ public interface IInteraction IReadOnlyList Entitlements { get; } /// - /// Gets the authorizing integration owners, that is, the entity that has the integration installed. + /// Gets the context of the interaction. /// + Optional Context { get; } + + /// + /// Gets the integrations that authorized the interaction. + /// + /// + /// This is a mapping of the integration type to the ID of its resource. + /// + /// The dictionary contains the following, given the circumstances:
+ /// - If the integration is installed to a user, a key of and the value is the user ID.
+ /// - If the integration is installed to a guild, a key of and the value is the guild ID. + /// If the interaction is sent outside the context of a guild, the value is always zero.
+ ///
+ ///
Optional> AuthorizingIntegrationOwners { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs new file mode 100644 index 0000000000..82132c7c05 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs @@ -0,0 +1,36 @@ +// +// IMessageComponentInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using Remora.Rest.Core; + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents metadata related to a message component interaction. +/// +public interface IMessageComponentInteractionMetadata : IMessageInteractionMetadata +{ + /// + /// Gets the ID of the message that was interacted with. + /// + Snowflake InteractedMessageID { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs new file mode 100644 index 0000000000..19d2797b14 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs @@ -0,0 +1,66 @@ +// +// IMessageInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents the metadata of an application command interaction. +/// +public interface IMessageInteractionMetadata +{ + /// + /// Gets the ID of the interaction. + /// + Snowflake ID { get; } + + /// + /// Gets the ID of the user who triggered the interaction. + /// + Snowflake UserID { get; } + + /// + /// Gets the type of the interaction. + /// + InteractionType Type { get; } + + /// + /// Gets the ID of the original response message. Only applicable to followup messages. + /// + Optional OriginalResponseMessageID { get; } + + /// + /// Gets the integrations that authorized the interaction. + /// + /// + /// This is a mapping of the integration type to the ID of its resource. + /// + /// The dictionary contains the following, given the circumstances:
+ /// - If the integration is installed to a user, a key of and the value is the user ID.
+ /// - If the integration is installed to a guild, a key of and the value is the guild ID. + /// If the interaction is sent outside the context of a guild, the value is always zero.
+ ///
+ ///
+ IReadOnlyDictionary AuthorizingIntegrationOwners { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs new file mode 100644 index 0000000000..49bc3f7eb2 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs @@ -0,0 +1,36 @@ +// +// IModalSubmitInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using OneOf; + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Represents metadata related to a modal submit interaction. +/// +public interface IModalSubmitInteractionMetadata : IMessageInteractionMetadata +{ + /// + /// Gets the metadata for the interaction that triggered the modal. + /// + OneOf TriggeringInteractionMetadata { get; } +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs new file mode 100644 index 0000000000..d7014720f7 --- /dev/null +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs @@ -0,0 +1,44 @@ +// +// InteractionContextType.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +namespace Remora.Discord.API.Abstractions.Objects; + +/// +/// Enumerates various interaction context types. +/// +public enum InteractionContextType +{ + /// + /// The interaction was executed in the context of a guild. + /// + Guild = 1, + + /// + /// The interaction was executed in the context of a direct message to the bot associated with the application. + /// + BotDM = 2, + + /// + /// The interaction was executed in the context of a direct message or group direct message. + /// + PrivateChannel = 3, +} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IMessage.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IMessage.cs index 4944db72a3..6e8a968238 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IMessage.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IMessage.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Rest.Core; namespace Remora.Discord.API.Abstractions.Objects; @@ -193,6 +194,11 @@ public interface IMessage : IPartialMessage ///
new Optional Resolved { get; } + /// + /// Gets the metadata of the interaction, if any. + /// + new Optional> InteractionMetadata { get; } + /// Optional IPartialMessage.ID => this.ID; @@ -282,4 +288,7 @@ public interface IMessage : IPartialMessage /// Optional IPartialMessage.Resolved => this.Resolved; + + /// + Optional> IPartialMessage.InteractionMetadata => this.InteractionMetadata; } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IPartialMessage.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IPartialMessage.cs index 06feb3faf5..e8cd370eb8 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IPartialMessage.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Messages/IPartialMessage.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Rest.Core; namespace Remora.Discord.API.Abstractions.Objects; @@ -122,4 +123,7 @@ public interface IPartialMessage /// Optional Resolved { get; } + + /// + Optional> InteractionMetadata { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/Remora.Discord.API.Abstractions.csproj b/Backend/Remora.Discord.API.Abstractions/Remora.Discord.API.Abstractions.csproj index 6d51932ace..7ca89deb06 100644 --- a/Backend/Remora.Discord.API.Abstractions/Remora.Discord.API.Abstractions.csproj +++ b/Backend/Remora.Discord.API.Abstractions/Remora.Discord.API.Abstractions.csproj @@ -117,6 +117,15 @@ IDiscordRestGuildAPI.cs + + IMessageInteractionMetadata.cs + + + IMessageInteractionMetadata.cs + + + IMessageInteractionMetadata.cs + diff --git a/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs b/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs index 5f9f0015f6..b7a411f20f 100644 --- a/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs +++ b/Backend/Remora.Discord.API/API/Gateway/Events/Interactions/InteractionCreate.cs @@ -47,9 +47,10 @@ public record InteractionCreate string Token, int Version, Optional Message, - Optional AppPermissions, + IDiscordPermissionSet AppPermissions, Optional Locale, Optional GuildLocale, IReadOnlyList Entitlements, + Optional Context, Optional> AuthorizingIntegrationOwners ) : IInteractionCreate; diff --git a/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageCreate.cs b/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageCreate.cs index 098c2d7464..4ff3e7c950 100644 --- a/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageCreate.cs +++ b/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageCreate.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; @@ -64,5 +65,6 @@ public record MessageCreate Optional> Components = default, Optional> StickerItems = default, Optional Position = default, - Optional Resolved = default + Optional Resolved = default, + Optional> InteractionMetadata = default ) : IMessageCreate; diff --git a/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageUpdate.cs b/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageUpdate.cs index 4969f0d7f1..d3d5591ccf 100644 --- a/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageUpdate.cs +++ b/Backend/Remora.Discord.API/API/Gateway/Events/Messages/MessageUpdate.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; @@ -64,5 +65,6 @@ public record MessageUpdate Optional> Components = default, Optional> StickerItems = default, Optional Position = default, - Optional Resolved = default + Optional Resolved = default, + Optional> InteractionMetadata = default ) : IMessageUpdate; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs new file mode 100644 index 0000000000..11c6f61b9f --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs @@ -0,0 +1,38 @@ +// +// ApplicationCommandInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Objects; + +/// +public record ApplicationCommandInteractionMetadata +( + Snowflake ID, + Snowflake UserID, + InteractionType Type, + Optional OriginalResponseMessageID, + IReadOnlyDictionary AuthorizingIntegrationOwners, + string Name +) : IApplicationCommandInteractionMetadata; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs index 3ad4be5faa..1e65ef2a4d 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/Interaction.cs @@ -46,9 +46,10 @@ public record Interaction string Token, int Version, Optional Message, - Optional AppPermissions, + IDiscordPermissionSet AppPermissions, Optional Locale, Optional GuildLocale, IReadOnlyList Entitlements, + Optional Context, Optional> AuthorizingIntegrationOwners ) : IInteraction; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs new file mode 100644 index 0000000000..6b3f32d9c8 --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs @@ -0,0 +1,38 @@ +// +// MessageComponentInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Objects; + +/// +public record MessageComponentInteractionMetadata +( + Snowflake ID, + Snowflake UserID, + InteractionType Type, + Optional OriginalResponseMessageID, + IReadOnlyDictionary AuthorizingIntegrationOwners, + Snowflake InteractedMessageID +) : IMessageComponentInteractionMetadata; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs new file mode 100644 index 0000000000..76fe503fef --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs @@ -0,0 +1,39 @@ +// +// ModalSubmitInteractionMetadata.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using OneOf; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Rest.Core; + +namespace Remora.Discord.API.Objects; + +/// +public record ModalSubmitInteractionMetadata +( + Snowflake ID, + Snowflake UserID, + InteractionType Type, + Optional OriginalResponseMessageID, + IReadOnlyDictionary AuthorizingIntegrationOwners, + OneOf TriggeringInteractionMetadata +) : IModalSubmitInteractionMetadata; diff --git a/Backend/Remora.Discord.API/API/Objects/Messages/Message.cs b/Backend/Remora.Discord.API/API/Objects/Messages/Message.cs index 725eadcfc9..480d9ef1da 100644 --- a/Backend/Remora.Discord.API/API/Objects/Messages/Message.cs +++ b/Backend/Remora.Discord.API/API/Objects/Messages/Message.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; @@ -63,5 +64,6 @@ public record Message Optional> Components = default, Optional> StickerItems = default, Optional Position = default, - Optional Resolved = default + Optional Resolved = default, + Optional> InteractionMetadata = default ) : IMessage; diff --git a/Backend/Remora.Discord.API/API/Objects/Messages/PartialMessage.cs b/Backend/Remora.Discord.API/API/Objects/Messages/PartialMessage.cs index e6b6ea7e97..d1bd60826b 100644 --- a/Backend/Remora.Discord.API/API/Objects/Messages/PartialMessage.cs +++ b/Backend/Remora.Discord.API/API/Objects/Messages/PartialMessage.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; +using OneOf; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; @@ -63,5 +64,6 @@ public record PartialMessage Optional> Components = default, Optional> StickerItems = default, Optional Position = default, - Optional Resolved = default + Optional Resolved = default, + Optional> InteractionMetadata = default ) : IPartialMessage; From baac359bf6b92c7329f557162d9fa3c76c378320 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:19:32 -0400 Subject: [PATCH 17/32] feat: Implement relevant API changes --- .../API/Rest/IDiscordRestApplicationAPI.cs | 16 ++++++++++++++++ .../Applications/DiscordRestApplicationAPI.cs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs index c8c773b023..4a445bb7b3 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs @@ -72,6 +72,8 @@ Task>> GetGlobalApplicationCommandsAsy /// The permissions required to execute the command. /// Whether this command is executable in DMs. /// Whether the command is age-restricted. + /// The installation contexts the command can be installed to. + /// The contexts in which the command is allowed to be run in. /// The cancellation token for this operation. /// A creation result which may or may not have succeeded. Task> CreateGlobalApplicationCommandAsync @@ -86,6 +88,8 @@ Task> CreateGlobalApplicationCommandAsync Optional defaultMemberPermissions = default, Optional dmPermission = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -130,6 +134,8 @@ Task> GetGlobalApplicationCommandAsync /// The permissions required to execute the command. /// Whether this command is executable in DMs. /// Whether this command is age-restricted. + /// The installation contexts the command can be installed to. + /// The contexts in which the command is allowed to be run in. /// The cancellation token for this operation. /// A creation result which may or may not have succeeded. Task> EditGlobalApplicationCommandAsync @@ -144,6 +150,8 @@ Task> EditGlobalApplicationCommandAsync Optional defaultMemberPermissions = default, Optional dmPermission = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -197,6 +205,8 @@ Task>> GetGuildApplicationCommandsAsyn /// The localized descriptions of the command. /// The permissions required to execute the command. /// Whether the command is age-restricted. + /// The installation contexts the command can be installed to. + /// The contexts in which the command is allowed to be run in. /// The cancellation token for this operation. /// A creation result which may or may not have succeeded. Task> CreateGuildApplicationCommandAsync @@ -211,6 +221,8 @@ Task> CreateGuildApplicationCommandAsync Optional?> descriptionLocalizations = default, Optional defaultMemberPermissions = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -259,6 +271,8 @@ Task> GetGuildApplicationCommandAsync /// The localized descriptions of the command. /// The permissions required to execute the command. /// Whether this command is age-restricted. + /// The installation contexts the command can be installed to. + /// The contexts in which the command is allowed to be run in. /// The cancellation token for this operation. /// A creation result which may or may not have succeeded. /// @@ -276,6 +290,8 @@ Task> EditGuildApplicationCommandAsync Optional?> descriptionLocalizations = default, Optional defaultMemberPermissions = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); diff --git a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs index 8daab0e12f..50dac70d5f 100644 --- a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs @@ -103,6 +103,8 @@ public virtual async Task> CreateGlobalApplicationCo Optional defaultMemberPermissions = default, Optional dmPermission = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -151,6 +153,8 @@ public virtual async Task> CreateGlobalApplicationCo json.Write("default_member_permissions", defaultMemberPermissions, this.JsonOptions); json.Write("dm_permission", dmPermission, this.JsonOptions); json.Write("nsfw", isNsfw, this.JsonOptions); + json.Write("contexts", allowedContextTypes, this.JsonOptions); + json.Write("integration_types", allowedIntegrationTypes, this.JsonOptions); } ) .WithRateLimitContext(this.RateLimitCache), @@ -230,6 +234,8 @@ public virtual async Task> EditGlobalApplicationComm Optional defaultMemberPermissions = default, Optional dmPermission = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -267,6 +273,8 @@ public virtual async Task> EditGlobalApplicationComm json.Write("default_member_permissions", defaultMemberPermissions, this.JsonOptions); json.Write("dm_permission", dmPermission, this.JsonOptions); json.Write("nsfw", isNsfw, this.JsonOptions); + json.Write("contexts", allowedContextTypes, this.JsonOptions); + json.Write("integration_types", allowedIntegrationTypes, this.JsonOptions); } ) .WithRateLimitContext(this.RateLimitCache), @@ -379,6 +387,8 @@ public virtual async Task> CreateGuildApplicationCom Optional?> descriptionLocalizations = default, Optional defaultMemberPermissions = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -426,6 +436,8 @@ public virtual async Task> CreateGuildApplicationCom json.Write("description_localizations", descriptionLocalizations, this.JsonOptions); json.Write("default_member_permissions", defaultMemberPermissions, this.JsonOptions); json.Write("nsfw", isNsfw, this.JsonOptions); + json.Write("contexts", allowedContextTypes, this.JsonOptions); + json.Write("integration_types", allowedIntegrationTypes, this.JsonOptions); } ) .WithRateLimitContext(this.RateLimitCache), @@ -463,6 +475,8 @@ public virtual async Task> EditGuildApplicationComma Optional?> descriptionLocalizations = default, Optional defaultMemberPermissions = default, Optional isNsfw = default, + Optional> allowedIntegrationTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -498,6 +512,8 @@ public virtual async Task> EditGuildApplicationComma json.Write("description_localizations", descriptionLocalizations, this.JsonOptions); json.Write("default_member_permissions", defaultMemberPermissions, this.JsonOptions); json.Write("nsfw", isNsfw, this.JsonOptions); + json.Write("contexts", allowedContextTypes, this.JsonOptions); + json.Write("integration_types", allowedIntegrationTypes, this.JsonOptions); } ) .WithRateLimitContext(this.RateLimitCache), From 7120e480f373a7287154518f6469519c8c8ddfd9 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:28:31 -0400 Subject: [PATCH 18/32] fix: De-duplicate context enum --- .../ApplicationCommandContextType.cs | 44 ------------------- .../IApplicationCommand.cs | 2 +- .../IBulkApplicationCommandData.cs | 2 +- .../API/Rest/IDiscordRestApplicationAPI.cs | 8 ++-- .../ApplicationCommands/ApplicationCommand.cs | 2 +- .../BulkApplicationCommandData.cs | 2 +- .../Applications/DiscordRestApplicationAPI.cs | 8 ++-- .../Attributes/AllowedContextsAttribute.cs | 4 +- .../Extensions/CommandTreeExtensions.cs | 4 +- 9 files changed, 16 insertions(+), 60 deletions(-) delete mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs deleted file mode 100644 index 2d9904ae3f..0000000000 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationCommandContextType.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// ApplicationCommandContextType.cs -// -// Author: -// Jarl Gullberg -// -// Copyright (c) Jarl Gullberg -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// - -namespace Remora.Discord.API.Abstractions.Objects; - -/// -/// Represents valid contexts for application commands to be executed. -/// -public enum ApplicationCommandContextType -{ - /// - /// Specifies that the command can be invoked in a guild. - /// - Guild, - - /// - /// Specifies that the command can be invoked in the corresponding bot's DM. - /// - BotDM, - - /// - /// Specifies that the command can be invoked in a DM (Private Channel). - /// - PrivateChannel -} diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs index 8e96ba16f2..090f3cda52 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs @@ -123,5 +123,5 @@ public interface IApplicationCommand /// /// Gets a value indicating the contexts in which this command can be invoked. /// - Optional> AllowedContextTypes { get; } + Optional> AllowedContextTypes { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs index 39767a00c7..4563894f6f 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs @@ -66,5 +66,5 @@ public interface IBulkApplicationCommandData Optional> AllowedIntegrationTypes { get; } /// - Optional> AllowedContextTypes { get; } + Optional> AllowedContextTypes { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs index 4a445bb7b3..cb703bd09a 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestApplicationAPI.cs @@ -89,7 +89,7 @@ Task> CreateGlobalApplicationCommandAsync Optional dmPermission = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -151,7 +151,7 @@ Task> EditGlobalApplicationCommandAsync Optional dmPermission = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -222,7 +222,7 @@ Task> CreateGuildApplicationCommandAsync Optional defaultMemberPermissions = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); @@ -291,7 +291,7 @@ Task> EditGuildApplicationCommandAsync Optional defaultMemberPermissions = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ); diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs index 8af074ae41..4db9d8d315 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs @@ -49,5 +49,5 @@ public record ApplicationCommand Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> AllowedContextTypes = default ) : IApplicationCommand; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs index 79a209389e..226a03d24e 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs @@ -42,5 +42,5 @@ public record BulkApplicationCommandData Optional DMPermission = default, Optional IsNsfw = default, Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> AllowedContextTypes = default ) : IBulkApplicationCommandData; diff --git a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs index 50dac70d5f..dc97d60fc6 100644 --- a/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs +++ b/Backend/Remora.Discord.Rest/API/Applications/DiscordRestApplicationAPI.cs @@ -104,7 +104,7 @@ public virtual async Task> CreateGlobalApplicationCo Optional dmPermission = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -235,7 +235,7 @@ public virtual async Task> EditGlobalApplicationComm Optional dmPermission = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -388,7 +388,7 @@ public virtual async Task> CreateGuildApplicationCom Optional defaultMemberPermissions = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { @@ -476,7 +476,7 @@ public virtual async Task> EditGuildApplicationComma Optional defaultMemberPermissions = default, Optional isNsfw = default, Optional> allowedIntegrationTypes = default, - Optional> allowedContextTypes = default, + Optional> allowedContextTypes = default, CancellationToken ct = default ) { diff --git a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs index 9b84a4fc8d..1782fb690e 100644 --- a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs +++ b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs @@ -34,10 +34,10 @@ namespace Remora.Discord.Commands.Attributes; /// The contexts the command can be invoked. [PublicAPI] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -public class AllowedContextsAttribute(params ApplicationCommandContextType[] allowedContexts) : Attribute +public class AllowedContextsAttribute(params InteractionContextType[] allowedContexts) : Attribute { /// /// Gets a value specifying the allowed contexts. /// - public IReadOnlyList AllowedContexts { get; } = allowedContexts.ToArray(); + public IReadOnlyList AllowedContexts { get; } = allowedContexts.ToArray(); } diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index b9573443a5..f07bd0eb68 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -244,7 +244,7 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) IDiscordPermissionSet? defaultMemberPermissions = default; Optional isNsfw = default; Optional> allowedIntegrationTypes = default; - Optional> allowedContextTypes = default; + Optional> allowedContextTypes = default; switch (node) { @@ -1147,6 +1147,6 @@ private sealed record TopLevelMetadata IDiscordPermissionSet? DefaultMemberPermission, Optional IsNsfw, Optional> AllowedIntegrationTypes, - Optional> AllowedContextTypes + Optional> AllowedContextTypes ); } From 0c5bf514175d2ddeaa8e7aa767dfc14d33890cb8 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:53:44 -0400 Subject: [PATCH 19/32] fix: Rename integration types config property to match Discord --- .../API/Objects/Applications/IApplication.cs | 4 ++-- ...eConfiguration.cs => IApplicationIntegrationTypeConfig.cs} | 4 ++-- .../API/Objects/Applications/IPartialApplication.cs | 4 ++-- .../API/Objects/Applications/Application.cs | 2 +- .../API/Objects/Applications/PartialApplication.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/{IApplicationIntegrationTypeConfiguration.cs => IApplicationIntegrationTypeConfig.cs} (91%) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs index 317ba0644f..d4cb846a27 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs @@ -168,7 +168,7 @@ public interface IApplication : IPartialApplication /// /// Gets the application's integration type configurations. /// - new IReadOnlyDictionary> IntegrationTypeConfigurations { get; } + new IReadOnlyDictionary> IntegrationTypesConfig { get; } /// Optional IPartialApplication.ID => this.ID; @@ -249,5 +249,5 @@ public interface IApplication : IPartialApplication Optional IPartialApplication.CustomInstallUrl => this.CustomInstallUrl; /// - Optional>> IPartialApplication.IntegrationTypeConfigurations => new(this.IntegrationTypeConfigurations); + Optional>> IPartialApplication.IntegrationTypesConfig => new(this.IntegrationTypesConfig); } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs similarity index 91% rename from Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs rename to Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs index a287a2c772..c79bcd3893 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfiguration.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs @@ -1,5 +1,5 @@ // -// IApplicationIntegrationTypeConfiguration.cs +// IApplicationIntegrationTypeConfig.cs // // Author: // Jarl Gullberg @@ -25,7 +25,7 @@ namespace Remora.Discord.API.Abstractions.Objects; /// /// The integration type configuration for an application. /// -public interface IApplicationIntegrationTypeConfiguration +public interface IApplicationIntegrationTypeConfig { /// /// Gets the OAuth2 install parameters for the integration type. diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs index d9e7807cda..553c694161 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs @@ -111,6 +111,6 @@ public interface IPartialApplication /// Optional CustomInstallUrl { get; } - /// - Optional>> IntegrationTypeConfigurations { get; } + /// + Optional>> IntegrationTypesConfig { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs index fbd9c2ebf7..37f46c5990 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs @@ -47,7 +47,7 @@ public record Application Optional Owner, string VerifyKey, ITeam? Team, - IReadOnlyDictionary> IntegrationTypeConfigurations, + IReadOnlyDictionary> IntegrationTypesConfig, Optional GuildID = default, Optional Guild = default, Optional PrimarySKUID = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs index 080ef5bc5a..e3479b03a5 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs @@ -60,5 +60,5 @@ public record PartialApplication Optional> Tags = default, Optional InstallParams = default, Optional CustomInstallUrl = default, - Optional>> IntegrationTypeConfigurations = default + Optional>> IntegrationTypesConfig = default ) : IPartialApplication; From dba0317b4221883e936d359d41b89c2ef93ee30c Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:00:28 -0400 Subject: [PATCH 20/32] fix: Fix test sample data, mostly. --- .../INTERACTION_CREATE/INTERACTION_CREATE.optionals.json | 1 + .../Samples/Objects/APPLICATION/APPLICATION.json | 3 ++- .../Samples/Objects/APPLICATION/APPLICATION.nulls.json | 6 +++++- .../Samples/Objects/APPLICATION/APPLICATION.optionals.json | 3 ++- .../Samples/Objects/INTERACTION/INTERACTION.optionals.json | 1 + 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Tests/Remora.Discord.Tests/Samples/Gateway/Events/INTERACTION_CREATE/INTERACTION_CREATE.optionals.json b/Tests/Remora.Discord.Tests/Samples/Gateway/Events/INTERACTION_CREATE/INTERACTION_CREATE.optionals.json index 3887a7864c..a58a9b9a4c 100644 --- a/Tests/Remora.Discord.Tests/Samples/Gateway/Events/INTERACTION_CREATE/INTERACTION_CREATE.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Gateway/Events/INTERACTION_CREATE/INTERACTION_CREATE.optionals.json @@ -8,6 +8,7 @@ "type": 2, "token": "none", "version": 1, + "app_permissions": "180224", "entitlements": [ { "id": "999999999999999999", diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json index 7e27fe746a..5b62c5cab2 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json @@ -56,5 +56,6 @@ ], "permissions": "0" }, - "custom_install_url": "https://www.example.org" + "custom_install_url": "https://www.example.org", + "integration_types_config": { "0": null, "1": null } } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json index 1a9fa6485b..f7b9a58974 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json @@ -30,5 +30,9 @@ "permissions": "0" }, "custom_install_url": "https://www.example.org", - "role_connections_verification_url": "https://www.example.org" + "role_connections_verification_url": "https://www.example.org", + "integration_types_config": { + "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, + "1": { "scopes": [ "application.commands"] } + } } \ No newline at end of file diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json index 44497c1265..03106420b8 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json @@ -27,5 +27,6 @@ ], "name": "none", "owner_user_id": "999999999999999999" - } + }, + "integration_types_config": { "0": null, "1": null } } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/INTERACTION/INTERACTION.optionals.json b/Tests/Remora.Discord.Tests/Samples/Objects/INTERACTION/INTERACTION.optionals.json index 3d7449104e..d5c9ba6b03 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/INTERACTION/INTERACTION.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/INTERACTION/INTERACTION.optionals.json @@ -4,6 +4,7 @@ "type": 2, "token": "none", "version": 1, + "app_permissions": "180224", "entitlements": [ { "id": "999999999999999999", From a6ad66c5ef3db87bc64c34ab8eefbbff7451da34 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:05:12 -0400 Subject: [PATCH 21/32] fix: Fix remaining sample data --- .../API/Objects/Applications/ApplicationIntegrationType.cs | 4 ++-- .../Samples/Objects/APPLICATION/APPLICATION.json | 5 ++++- .../Samples/Objects/APPLICATION/APPLICATION.optionals.json | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs index ae72e3bd5a..222bab3943 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs @@ -30,10 +30,10 @@ public enum ApplicationIntegrationType /// /// Specifies that the integration can be installed on a guild. /// - GuildInstallable, + GuildInstallable = 0, /// /// Specifies that the integration can be installed on a user. /// - UserInstallable + UserInstallable = 1, } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json index 5b62c5cab2..f852195b1d 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json @@ -57,5 +57,8 @@ "permissions": "0" }, "custom_install_url": "https://www.example.org", - "integration_types_config": { "0": null, "1": null } + "integration_types_config": { + "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, + "1": { "scopes": [ "application.commands"] } + } } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json index 03106420b8..9f3cc3c2a9 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json @@ -28,5 +28,8 @@ "name": "none", "owner_user_id": "999999999999999999" }, - "integration_types_config": { "0": null, "1": null } + "integration_types_config": { + "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, + "1": { "scopes": [ "application.commands"] } + } } From 891d4e615becbc82153c0e02688b4c5d1f763249 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 19 Mar 2024 09:33:06 -0400 Subject: [PATCH 22/32] fix(rest): Add DOC for IApplicationIntegrationTypeConfig --- .../Extensions/ServiceCollectionExtensions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index d0851d9223..30153c2fd7 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1211,6 +1211,9 @@ private static JsonSerializerOptions AddOAuth2ObjectConverters(this JsonSerializ options.AddDataObjectConverter(); + options.AddDataObjectConverter() + .WithPropertyName(a => a.OAuth2InstallParams, "oauth2_install_params"); + return options; } From 395ca867244f54d138ff713488c583b5ed2f0e5e Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 19 Mar 2024 09:33:59 -0400 Subject: [PATCH 23/32] fix: Make type configs nullable instead of optional --- .../API/Objects/Applications/IApplication.cs | 4 ++-- .../API/Objects/Applications/IPartialApplication.cs | 2 +- .../API/Objects/Applications/Application.cs | 2 +- .../API/Objects/Applications/PartialApplication.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs index d4cb846a27..7e02553e0f 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplication.cs @@ -168,7 +168,7 @@ public interface IApplication : IPartialApplication /// /// Gets the application's integration type configurations. /// - new IReadOnlyDictionary> IntegrationTypesConfig { get; } + new IReadOnlyDictionary IntegrationTypesConfig { get; } /// Optional IPartialApplication.ID => this.ID; @@ -249,5 +249,5 @@ public interface IApplication : IPartialApplication Optional IPartialApplication.CustomInstallUrl => this.CustomInstallUrl; /// - Optional>> IPartialApplication.IntegrationTypesConfig => new(this.IntegrationTypesConfig); + Optional> IPartialApplication.IntegrationTypesConfig => new(this.IntegrationTypesConfig); } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs index 553c694161..57dfb37e98 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IPartialApplication.cs @@ -112,5 +112,5 @@ public interface IPartialApplication Optional CustomInstallUrl { get; } /// - Optional>> IntegrationTypesConfig { get; } + Optional> IntegrationTypesConfig { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs index 37f46c5990..11cf2e040c 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/Application.cs @@ -47,7 +47,7 @@ public record Application Optional Owner, string VerifyKey, ITeam? Team, - IReadOnlyDictionary> IntegrationTypesConfig, + IReadOnlyDictionary IntegrationTypesConfig, Optional GuildID = default, Optional Guild = default, Optional PrimarySKUID = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs index e3479b03a5..58726b36e3 100644 --- a/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs +++ b/Backend/Remora.Discord.API/API/Objects/Applications/PartialApplication.cs @@ -60,5 +60,5 @@ public record PartialApplication Optional> Tags = default, Optional InstallParams = default, Optional CustomInstallUrl = default, - Optional>> IntegrationTypesConfig = default + Optional> IntegrationTypesConfig = default ) : IPartialApplication; From aab305a21f70f2010d401f6d7c8fb19d5454e9b9 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 19 Mar 2024 09:34:24 -0400 Subject: [PATCH 24/32] chore: Fix test sample data (again) --- .../Samples/Objects/APPLICATION/APPLICATION.json | 4 ++-- .../Samples/Objects/APPLICATION/APPLICATION.nulls.json | 6 +++--- .../Samples/Objects/APPLICATION/APPLICATION.optionals.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json index f852195b1d..30321056db 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json @@ -58,7 +58,7 @@ }, "custom_install_url": "https://www.example.org", "integration_types_config": { - "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, - "1": { "scopes": [ "application.commands"] } + "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, + "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } } } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json index f7b9a58974..0bd3f6a3d8 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json @@ -31,8 +31,8 @@ }, "custom_install_url": "https://www.example.org", "role_connections_verification_url": "https://www.example.org", - "integration_types_config": { - "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, - "1": { "scopes": [ "application.commands"] } + "integration_types_config": { + "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, + "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } } } \ No newline at end of file diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json index 9f3cc3c2a9..2dc2676d58 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json @@ -29,7 +29,7 @@ "owner_user_id": "999999999999999999" }, "integration_types_config": { - "0": { "scopes": [ "bot", "application.commands" ], "permissions": "0"}, - "1": { "scopes": [ "application.commands"] } + "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, + "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } } } From 61034d36b1e3a2eaa61870aba46fc2bbd83396ed Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 19 Mar 2024 09:34:54 -0400 Subject: [PATCH 25/32] feat: Implement missing interface counterparts --- .../ApplicationIntegrationTypeConfig.cs | 28 ++++++++++++++++++ .../ApplicationOAuth2InstallParams.cs | 29 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs create mode 100644 Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs new file mode 100644 index 0000000000..d8b833d968 --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs @@ -0,0 +1,28 @@ +// +// ApplicationIntegrationTypeConfig.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using Remora.Discord.API.Abstractions.Objects; + +namespace Remora.Discord.API.Objects; + +/// +public record ApplicationIntegrationTypeConfig(IApplicationOAuth2InstallParams OAuth2InstallParams) : IApplicationIntegrationTypeConfig; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs new file mode 100644 index 0000000000..58a9af2a65 --- /dev/null +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs @@ -0,0 +1,29 @@ +// +// ApplicationOAuth2InstallParams.cs +// +// Author: +// Jarl Gullberg +// +// Copyright (c) Jarl Gullberg +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +using System.Collections.Generic; +using Remora.Discord.API.Abstractions.Objects; + +namespace Remora.Discord.API.Objects; + +/// +public record ApplicationOAuth2InstallParams(IDiscordPermissionSet Permissions, IReadOnlyList Scopes) : IApplicationOAuth2InstallParams; From 4a947fa8aa13a70bbbc7cb9ed5fc4cde13929217 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:00:36 -0400 Subject: [PATCH 26/32] fix: Remove more unimplemented stuff --- .../InteractionCallbackEphemerality.cs | 39 ----------- .../InteractionCallbackHintAttribute.cs | 64 ------------------- .../Extensions/CommandTreeExtensions.cs | 23 ------- 3 files changed, 126 deletions(-) delete mode 100644 Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs delete mode 100644 Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs deleted file mode 100644 index c565999497..0000000000 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionCallbackEphemerality.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// InteractionCallbackEphemerality.cs -// -// Author: -// Jarl Gullberg -// -// Copyright (c) Jarl Gullberg -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// - -namespace Remora.Discord.API.Abstractions.Objects; - -/// -/// Represents the ephemeral-ness of a command. -/// -public enum InteractionCallbackEphemerality -{ - /// - /// Represents that an ephemeral response is optional. - /// - Optional, - - /// - /// Represents that am ephemeral response is required. - /// - Required -} diff --git a/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs b/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs deleted file mode 100644 index 711234091f..0000000000 --- a/Remora.Discord.Commands/Attributes/InteractionCallbackHintAttribute.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// InteractionCallbackHintAttribute.cs -// -// Author: -// Jarl Gullberg -// -// Copyright (c) Jarl Gullberg -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . -// - -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using Remora.Discord.API.Abstractions.Objects; -using Remora.Discord.API.Objects; -using Remora.Rest.Core; - -namespace Remora.Discord.Commands.Attributes; - -/// -/// Represents a hint to Discord for how to handle an interaction callback. -/// -/// The allowed callback types. -/// Represents a hint as to whether the command can/will respond ephemerally. -/// If specifies a type that creates or updates a message, the required permissions. -[PublicAPI] -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -public class InteractionCallbackHintAttribute -( - IReadOnlyList allowedCallbackTypes, - InteractionCallbackEphemerality? ephemerality = default, - IReadOnlyList? requiredPermissions = default -) : Attribute -{ - /// - /// Gets a value specifying the allowed callback types. - /// - public IReadOnlyList AllowedCallbackTypes { get; } = allowedCallbackTypes; - - /// - /// Gets a value specifying the ephemeral nature of the callback, if required. - /// - public Optional Ephemerality { get; } = ephemerality.AsOptional(); - - /// - /// Gets a value specifying the required permissions for the callback, if required. - /// - public Optional RequiredPermissions { get; } = requiredPermissions - .AsOptional() - .Map(t => (IDiscordPermissionSet)new DiscordPermissionSet(t.ToArray())); -} diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index f07bd0eb68..043e688774 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -375,25 +375,6 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) t => t.GetCustomAttribute() ); - var callbackHintAttributes = groupNode.GroupTypes.Select - ( - t => t.GetCustomAttribute() - ); - - var callbackHints = callbackHintAttributes - .Where(attribute => attribute is not null) - .ToArray(); - - if (callbackHints.Length > 1) - { - throw new InvalidNodeException - ( - $"In a set of groups with the same name, only one may be marked with an callback hint attribute, but " - + $"{callbackHints.Length} were found.", - node - ); - } - break; } case CommandNode commandNode: @@ -449,10 +430,6 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) allowedIntegrationTypes = integrationAttribute.InstallTypes.AsOptional(); } - var callbackHintAttribute = - commandNode.GroupType.GetCustomAttribute() ?? - commandNode.CommandMethod.GetCustomAttribute(); - break; } } From 1269d3ee3f6fb2ad6de570cccf00eccfae32840b Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Sun, 31 Mar 2024 07:16:50 -0400 Subject: [PATCH 27/32] fix: Finally fix data (properly) This commit is broken, as the Remora.Rest dependency needs to be updated to the latest version to fix one (1) test. --- .idea/.idea.Remora.Discord/.idea/.gitignore | 2 ++ .../Extensions/ServiceCollectionExtensions.cs | 1 + .../API/Applications/DiscordRestApplicationAPITests.cs | 9 ++++----- .../Samples/Objects/APPLICATION/APPLICATION.json | 2 +- .../Samples/Objects/APPLICATION/APPLICATION.nulls.json | 2 +- .../Objects/APPLICATION/APPLICATION.optionals.json | 4 ++-- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.idea/.idea.Remora.Discord/.idea/.gitignore b/.idea/.idea.Remora.Discord/.idea/.gitignore index bc9371e1b5..343d51bf13 100644 --- a/.idea/.idea.Remora.Discord/.idea/.gitignore +++ b/.idea/.idea.Remora.Discord/.idea/.gitignore @@ -11,3 +11,5 @@ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index 30153c2fd7..7bc611f82c 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1214,6 +1214,7 @@ private static JsonSerializerOptions AddOAuth2ObjectConverters(this JsonSerializ options.AddDataObjectConverter() .WithPropertyName(a => a.OAuth2InstallParams, "oauth2_install_params"); + options.AddDataObjectConverter(); return options; } diff --git a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs index e77b62276e..fffb6a9f51 100644 --- a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs +++ b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs @@ -2542,12 +2542,11 @@ public async Task PerformsRequestCorrectly() ) .WithProperty ( - "integration_types", - p => p.IsArray + "integration_types_config", + p => p.IsObject ( - a => a - .WithElement(0, e => e.Is((int)ApplicationIntegrationType.UserInstallable)) - .WithElement(1, e => e.Is((int)ApplicationIntegrationType.GuildInstallable)) + j => j.WithProperty("0", e => e.IsObject()) + .WithProperty("1", e => e.IsObject()) ) ) ) diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json index 30321056db..6eeaf68a58 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.json @@ -59,6 +59,6 @@ "custom_install_url": "https://www.example.org", "integration_types_config": { "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, - "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } + "1": { "oauth2_install_params": { "scopes": [ "application.commands" ], "permissions": "0" } } } } diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json index 0bd3f6a3d8..344248eed6 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.nulls.json @@ -33,6 +33,6 @@ "role_connections_verification_url": "https://www.example.org", "integration_types_config": { "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, - "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } + "1": { "oauth2_install_params": { "scopes": [ "application.commands" ], "permissions": "0" } } } } \ No newline at end of file diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json index 2dc2676d58..926d3d2922 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/APPLICATION/APPLICATION.optionals.json @@ -29,7 +29,7 @@ "owner_user_id": "999999999999999999" }, "integration_types_config": { - "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0"} }, - "1": { "oauth2_install_params": {"scopes": [ "application.commands"] } } + "0": { "oauth2_install_params": { "scopes": [ "bot", "application.commands" ], "permissions": "0" } }, + "1": { "oauth2_install_params": { "scopes": [ "application.commands" ], "permissions": "0" } } } } From 9736b6514752599807f7bc0cc663cb3b0109d4a8 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 2 Apr 2024 02:56:15 -0400 Subject: [PATCH 28/32] chore: Update Remora.Rest to latest version --- Directory.Packages.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 3bce533a5d..f54917a7c6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,24 +13,24 @@ - + - + - + - + From 944f881d3b78e06bbba1fd85971f467313cce458 Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:03:05 -0400 Subject: [PATCH 29/32] fix: Finally fix tests --- .../Extensions/ServiceCollectionExtensions.cs | 2 ++ .../API/Applications/DiscordRestApplicationAPITests.cs | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index 7bc611f82c..673903956f 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1215,6 +1215,8 @@ private static JsonSerializerOptions AddOAuth2ObjectConverters(this JsonSerializ .WithPropertyName(a => a.OAuth2InstallParams, "oauth2_install_params"); options.AddDataObjectConverter(); + + options.Converters.Insert(0, new StringEnumConverter(options.PropertyNamingPolicy, true)); return options; } diff --git a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs index fffb6a9f51..90eca8f418 100644 --- a/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs +++ b/Tests/Remora.Discord.Rest.Tests/API/Applications/DiscordRestApplicationAPITests.cs @@ -2542,11 +2542,12 @@ public async Task PerformsRequestCorrectly() ) .WithProperty ( - "integration_types_config", - p => p.IsObject + "integration_types", + p => p.IsArray ( - j => j.WithProperty("0", e => e.IsObject()) - .WithProperty("1", e => e.IsObject()) + a => a.WithCount(2) + .WithElement(0, e => e.Is("1")) + .WithElement(1, e => e.Is("0")) ) ) ) From 85fd43488f20f82ccd4f2d550b53e4d75eea9c2d Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:21:13 -0400 Subject: [PATCH 30/32] fix: Cleanup some residual code --- .../Extensions/CommandTreeExtensions.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index 043e688774..5fefc960f1 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -351,29 +351,31 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) allowedContextTypes = context.AllowedContexts.AsOptional(); } - var integrationAttributes = groupNode.GroupTypes.Select + var installAttributes = groupNode.GroupTypes.Select ( t => t.GetCustomAttribute() ); - var integrations = integrationAttributes + var installs = installAttributes .Where(attribute => attribute is not null) .ToArray(); - if (integrations.Length > 1) + if (installs.Length > 1) { throw new InvalidNodeException ( - $"In a set of groups with the same name, only one may be marked with an integration attribute, but " - + $"{integrations.Length} were found.", + $"In a set of groups with the same name, only one may be marked with an install attribute, " + + $"but {installs.Length} were found.", node ); } - var integrationsAttributes = groupNode.GroupTypes.Select - ( - t => t.GetCustomAttribute() - ); + var install = installs.SingleOrDefault(); + + if (install is not null) + { + allowedIntegrationTypes = install.InstallTypes.AsOptional(); + } break; } From b76f8bfa86cc95e53cf75018b346c136e292135d Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Wed, 3 Apr 2024 13:27:01 -0400 Subject: [PATCH 31/32] chore: Fix warnings and notes --- .../Objects/Applications/IApplicationIntegrationTypeConfig.cs | 3 +++ .../Objects/Applications/IApplicationOAuth2InstallParams.cs | 2 ++ .../Interactions/IApplicationCommandInteractionMetadata.cs | 3 +++ .../Interactions/IMessageComponentInteractionMetadata.cs | 2 ++ .../API/Objects/Interactions/IMessageInteractionMetadata.cs | 2 ++ .../Objects/Interactions/IModalSubmitInteractionMetadata.cs | 2 ++ .../API/Objects/Interactions/InteractionContextType.cs | 3 +++ .../Interactions/ApplicationCommandInteractionMetadata.cs | 2 ++ .../Objects/Interactions/ApplicationIntegrationTypeConfig.cs | 2 ++ .../API/Objects/Interactions/ApplicationOAuth2InstallParams.cs | 2 ++ .../Interactions/MessageComponentInteractionMetadata.cs | 2 ++ .../API/Objects/Interactions/ModalSubmitInteractionMetadata.cs | 2 ++ Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs | 2 +- .../Attributes/DiscordInstallContextAttribute.cs | 3 +++ 14 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs index c79bcd3893..66cca05a81 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationIntegrationTypeConfig.cs @@ -20,11 +20,14 @@ // along with this program. If not, see . // +using JetBrains.Annotations; + namespace Remora.Discord.API.Abstractions.Objects; /// /// The integration type configuration for an application. /// +[PublicAPI] public interface IApplicationIntegrationTypeConfig { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs index 99a4a72bbf..2419832d46 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/IApplicationOAuth2InstallParams.cs @@ -21,12 +21,14 @@ // using System.Collections.Generic; +using JetBrains.Annotations; namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents the OAuth2 install parameters for an application. /// +[PublicAPI] public interface IApplicationOAuth2InstallParams { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs index 3bb4ca0ba6..2b7349b175 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IApplicationCommandInteractionMetadata.cs @@ -20,11 +20,14 @@ // along with this program. If not, see . // +using JetBrains.Annotations; + namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents metadata related to application commands. /// +[PublicAPI] public interface IApplicationCommandInteractionMetadata : IMessageInteractionMetadata { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs index 82132c7c05..36725b1112 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageComponentInteractionMetadata.cs @@ -20,6 +20,7 @@ // along with this program. If not, see . // +using JetBrains.Annotations; using Remora.Rest.Core; namespace Remora.Discord.API.Abstractions.Objects; @@ -27,6 +28,7 @@ namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents metadata related to a message component interaction. /// +[PublicAPI] public interface IMessageComponentInteractionMetadata : IMessageInteractionMetadata { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs index 19d2797b14..8e2decdbc1 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IMessageInteractionMetadata.cs @@ -21,6 +21,7 @@ // using System.Collections.Generic; +using JetBrains.Annotations; using Remora.Rest.Core; namespace Remora.Discord.API.Abstractions.Objects; @@ -28,6 +29,7 @@ namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents the metadata of an application command interaction. /// +[PublicAPI] public interface IMessageInteractionMetadata { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs index 49bc3f7eb2..2c2dfd30e1 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/IModalSubmitInteractionMetadata.cs @@ -20,6 +20,7 @@ // along with this program. If not, see . // +using JetBrains.Annotations; using OneOf; namespace Remora.Discord.API.Abstractions.Objects; @@ -27,6 +28,7 @@ namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents metadata related to a modal submit interaction. /// +[PublicAPI] public interface IModalSubmitInteractionMetadata : IMessageInteractionMetadata { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs index d7014720f7..f292c3b6d8 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/InteractionContextType.cs @@ -20,11 +20,14 @@ // along with this program. If not, see . // +using JetBrains.Annotations; + namespace Remora.Discord.API.Abstractions.Objects; /// /// Enumerates various interaction context types. /// +[PublicAPI] public enum InteractionContextType { /// diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs index 11c6f61b9f..83714785d2 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommandInteractionMetadata.cs @@ -21,12 +21,14 @@ // using System.Collections.Generic; +using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; namespace Remora.Discord.API.Objects; /// +[PublicAPI] public record ApplicationCommandInteractionMetadata ( Snowflake ID, diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs index d8b833d968..4be5c8f345 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationIntegrationTypeConfig.cs @@ -20,9 +20,11 @@ // along with this program. If not, see . // +using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; namespace Remora.Discord.API.Objects; /// +[PublicAPI] public record ApplicationIntegrationTypeConfig(IApplicationOAuth2InstallParams OAuth2InstallParams) : IApplicationIntegrationTypeConfig; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs index 58a9af2a65..ef86f77243 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationOAuth2InstallParams.cs @@ -21,9 +21,11 @@ // using System.Collections.Generic; +using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; namespace Remora.Discord.API.Objects; /// +[PublicAPI] public record ApplicationOAuth2InstallParams(IDiscordPermissionSet Permissions, IReadOnlyList Scopes) : IApplicationOAuth2InstallParams; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs index 6b3f32d9c8..701a08d5e8 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/MessageComponentInteractionMetadata.cs @@ -21,12 +21,14 @@ // using System.Collections.Generic; +using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; namespace Remora.Discord.API.Objects; /// +[PublicAPI] public record MessageComponentInteractionMetadata ( Snowflake ID, diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs index 76fe503fef..0ddf24ab7f 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ModalSubmitInteractionMetadata.cs @@ -21,6 +21,7 @@ // using System.Collections.Generic; +using JetBrains.Annotations; using OneOf; using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; @@ -28,6 +29,7 @@ namespace Remora.Discord.API.Objects; /// +[PublicAPI] public record ModalSubmitInteractionMetadata ( Snowflake ID, diff --git a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs index 1782fb690e..fb02c6675a 100644 --- a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs +++ b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs @@ -31,7 +31,7 @@ namespace Remora.Discord.Commands.Attributes; /// /// Defines the contexts in which a command can be invoked. /// -/// The contexts the command can be invoked. +/// The contexts the command can be invoked. [PublicAPI] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AllowedContextsAttribute(params InteractionContextType[] allowedContexts) : Attribute diff --git a/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs b/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs index 815719755f..8b6aca80d7 100644 --- a/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs +++ b/Remora.Discord.Commands/Attributes/DiscordInstallContextAttribute.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; using Remora.Discord.API.Abstractions.Objects; namespace Remora.Discord.Commands.Attributes; @@ -30,6 +31,8 @@ namespace Remora.Discord.Commands.Attributes; /// Specifies that the command is valid to install in the given contexts. /// /// The contexts that the command can be installed into. +[PublicAPI] +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class DiscordInstallContextAttribute(params ApplicationIntegrationType[] installTypes) : Attribute { /// From 5b4b0557ed5cfd19e8a70087ba57cb78714b363d Mon Sep 17 00:00:00 2001 From: Velvet Toroyashi <42438262+VelvetToroyashi@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:56:14 -0400 Subject: [PATCH 32/32] Address PR comments --- .../Objects/Applications/ApplicationIntegrationType.cs | 3 +++ .../ApplicationCommands/IApplicationCommand.cs | 4 ++-- .../ApplicationCommands/IBulkApplicationCommandData.cs | 8 ++++---- .../ApplicationCommands/ApplicationCommand.cs | 4 ++-- .../ApplicationCommands/BulkApplicationCommandData.cs | 4 ++-- .../Extensions/ServiceCollectionExtensions.cs | 9 +++------ .../Attributes/AllowedContextsAttribute.cs | 6 +++--- .../Extensions/CommandTreeExtensions.cs | 4 ++-- Remora.Discord.sln.DotSettings | 9 +++++++++ 9 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs index 222bab3943..c7115b5cfb 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Applications/ApplicationIntegrationType.cs @@ -20,11 +20,14 @@ // along with this program. If not, see . // +using JetBrains.Annotations; + namespace Remora.Discord.API.Abstractions.Objects; /// /// Represents valid locations for users to install application integrations. /// +[PublicAPI] public enum ApplicationIntegrationType { /// diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs index 090f3cda52..f4f8607d5b 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IApplicationCommand.cs @@ -118,10 +118,10 @@ public interface IApplicationCommand /// /// Gets a value indicating the contexts in which this command can be installed. /// - Optional> AllowedIntegrationTypes { get; } + Optional> IntegrationTypes { get; } /// /// Gets a value indicating the contexts in which this command can be invoked. /// - Optional> AllowedContextTypes { get; } + Optional> Contexts { get; } } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs index 4563894f6f..940b0012f4 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Interactions/ApplicationCommands/IBulkApplicationCommandData.cs @@ -62,9 +62,9 @@ public interface IBulkApplicationCommandData /// Optional IsNsfw { get; } - /// - Optional> AllowedIntegrationTypes { get; } + /// + Optional> IntegrationTypes { get; } - /// - Optional> AllowedContextTypes { get; } + /// + Optional> Contexts { get; } } diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs index 4db9d8d315..d909a12895 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/ApplicationCommand.cs @@ -48,6 +48,6 @@ public record ApplicationCommand IDiscordPermissionSet? DefaultMemberPermissions = default, Optional DMPermission = default, Optional IsNsfw = default, - Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> IntegrationTypes = default, + Optional> Contexts = default ) : IApplicationCommand; diff --git a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs index 226a03d24e..97df83b703 100644 --- a/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs +++ b/Backend/Remora.Discord.API/API/Objects/Interactions/ApplicationCommands/BulkApplicationCommandData.cs @@ -41,6 +41,6 @@ public record BulkApplicationCommandData IDiscordPermissionSet? DefaultMemberPermissions = default, Optional DMPermission = default, Optional IsNsfw = default, - Optional> AllowedIntegrationTypes = default, - Optional> AllowedContextTypes = default + Optional> IntegrationTypes = default, + Optional> Contexts = default ) : IBulkApplicationCommandData; diff --git a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs index 673903956f..5decb3ea76 100644 --- a/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs +++ b/Backend/Remora.Discord.API/Extensions/ServiceCollectionExtensions.cs @@ -1052,9 +1052,7 @@ private static JsonSerializerOptions AddInteractionObjectConverters(this JsonSer options.AddDataObjectConverter(); options.AddDataObjectConverter() - .WithPropertyName(d => d.IsNsfw, "nsfw") - .WithPropertyName(d => d.AllowedContextTypes, "contexts") - .WithPropertyName(d => d.AllowedIntegrationTypes, "integration_types"); + .WithPropertyName(d => d.IsNsfw, "nsfw"); options.AddDataObjectConverter() .WithPropertyName(o => o.IsDefault, "default") @@ -1063,10 +1061,9 @@ private static JsonSerializerOptions AddInteractionObjectConverters(this JsonSer options.AddDataObjectConverter(); options.AddDataObjectConverter(); + options.AddDataObjectConverter() - .WithPropertyName(d => d.IsNsfw, "nsfw") - .WithPropertyName(d => d.AllowedContextTypes, "contexts") - .WithPropertyName(d => d.AllowedIntegrationTypes, "integration_types"); + .WithPropertyName(d => d.IsNsfw, "nsfw"); options.AddDataObjectConverter < diff --git a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs index fb02c6675a..fa85204db0 100644 --- a/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs +++ b/Remora.Discord.Commands/Attributes/AllowedContextsAttribute.cs @@ -31,13 +31,13 @@ namespace Remora.Discord.Commands.Attributes; /// /// Defines the contexts in which a command can be invoked. /// -/// The contexts the command can be invoked. +/// The contexts the command can be invoked. [PublicAPI] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -public class AllowedContextsAttribute(params InteractionContextType[] allowedContexts) : Attribute +public class AllowedContextsAttribute(params InteractionContextType[] contexts) : Attribute { /// /// Gets a value specifying the allowed contexts. /// - public IReadOnlyList AllowedContexts { get; } = allowedContexts.ToArray(); + public IReadOnlyList Contexts { get; } = contexts.ToArray(); } diff --git a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs index 5fefc960f1..f3eee1077e 100644 --- a/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs +++ b/Remora.Discord.Commands/Extensions/CommandTreeExtensions.cs @@ -348,7 +348,7 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) if (context is not null) { - allowedContextTypes = context.AllowedContexts.AsOptional(); + allowedContextTypes = context.Contexts.AsOptional(); } var installAttributes = groupNode.GroupTypes.Select @@ -420,7 +420,7 @@ private static TopLevelMetadata GetNodeMetadata(IChildNode node) if (contextsAttribute is not null) { - allowedContextTypes = contextsAttribute.AllowedContexts.AsOptional(); + allowedContextTypes = contextsAttribute.Contexts.AsOptional(); } var integrationAttribute = diff --git a/Remora.Discord.sln.DotSettings b/Remora.Discord.sln.DotSettings index 41e5dd2154..c1b6756ce6 100644 --- a/Remora.Discord.sln.DotSettings +++ b/Remora.Discord.sln.DotSettings @@ -143,10 +143,19 @@ <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy> True True True True + True True True True