Files
Discord.Net/src/Discord.Net.Interactions/Info/ModuleInfo.cs
Mihail Gribkov 24a69785fe [Feature] Initial user apps support (#2883)
* omg it kinda works somehow

* more things added

* a bit of xmldocs

* added interaction framework support

* working? IF

* more builder stuff

* space

* rename attribute to prevent conflict with `ContextType` enum

* context type

* moar features

* remove integration types

* trigger workflow

* modelzzzz

* `InteractionContextType`

* allow setting custom status with `SetGameAsync`

* bugzzz

* app permissions

* message interaction context

* hm

* push for cd

* structs lets goooo

* whoops forgot to change types

* whoops x2

* tweak some things

* xmldocs + missing prop + fix enabled in dm

* moar validations

* deprecate a bunch of stuffz

* disable moar obsolete warnings

* add IF sample

* Apply suggestions from code review

Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com>

* Update src/Discord.Net.Rest/Entities/RestApplication.cs

Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com>

---------

Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com>
2024-03-18 21:24:05 +00:00

281 lines
10 KiB
C#

using Discord.Interactions.Builders;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Discord.Interactions
{
/// <summary>
/// Contains the information of a Interactions Module.
/// </summary>
public class ModuleInfo
{
internal ILookup<string, PreconditionAttribute> GroupedPreconditions { get; }
/// <summary>
/// Gets the underlying command service.
/// </summary>
public InteractionService CommandService { get; }
/// <summary>
/// Gets the name of this module class.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the group name of this module, if the module is marked with a <see cref="GroupAttribute"/>.
/// </summary>
public string SlashGroupName { get; }
/// <summary>
/// Gets <see langword="true"/> if this module is marked with a <see cref="GroupAttribute"/>.
/// </summary>
public bool IsSlashGroup => !string.IsNullOrEmpty(SlashGroupName);
/// <summary>
/// Gets the description of this module if <see cref="IsSlashGroup"/> is <see langword="true"/>.
/// </summary>
public string Description { get; }
/// <summary>
/// Gets the default Permission of this module.
/// </summary>
[Obsolete($"To be deprecated soon, use {nameof(IsEnabledInDm)} and {nameof(DefaultMemberPermissions)} instead.")]
public bool DefaultPermission { get; }
/// <summary>
/// Gets whether this command can be used in DMs.
/// </summary>
public bool IsEnabledInDm { get; }
/// <summary>
/// Gets whether this command is age restricted.
/// </summary>
public bool IsNsfw { get; }
/// <summary>
/// Gets the default permissions needed for executing this command.
/// </summary>
public GuildPermission? DefaultMemberPermissions { get; }
/// <summary>
/// Gets the collection of Sub Modules of this module.
/// </summary>
public IReadOnlyList<ModuleInfo> SubModules { get; }
/// <summary>
/// Gets the Slash Commands that are declared in this module.
/// </summary>
public IReadOnlyList<SlashCommandInfo> SlashCommands { get; }
/// <summary>
/// Gets the Context Commands that are declared in this module.
/// </summary>
public IReadOnlyList<ContextCommandInfo> ContextCommands { get; }
/// <summary>
/// Gets the Component Commands that are declared in this module.
/// </summary>
public IReadOnlyCollection<ComponentCommandInfo> ComponentCommands { get; }
/// <summary>
/// Gets the Autocomplete Commands that are declared in this module.
/// </summary>
public IReadOnlyCollection<AutocompleteCommandInfo> AutocompleteCommands { get; }
public IReadOnlyCollection<ModalCommandInfo> ModalCommands { get; }
/// <summary>
/// Gets the declaring type of this module, if <see cref="IsSubModule"/> is <see langword="true"/>.
/// </summary>
public ModuleInfo Parent { get; }
/// <summary>
/// Gets <see langword="true"/> if this module is declared by another <see cref="InteractionModuleBase{T}"/>.
/// </summary>
public bool IsSubModule => Parent != null;
/// <summary>
/// Gets a collection of the attributes of this module.
/// </summary>
public IReadOnlyCollection<Attribute> Attributes { get; }
/// <summary>
/// Gets a collection of the preconditions of this module.
/// </summary>
public IReadOnlyCollection<PreconditionAttribute> Preconditions { get; }
/// <summary>
/// Gets <see langword="true"/> if this module has a valid <see cref="GroupAttribute"/> and has no parent with a <see cref="GroupAttribute"/>.
/// </summary>
public bool IsTopLevelGroup { get; }
/// <summary>
/// Gets <see langword="true"/> if this module will not be registered by <see cref="InteractionService.RegisterCommandsGloballyAsync(bool)"/>
/// or <see cref="InteractionService.RegisterCommandsToGuildAsync(ulong, bool)"/> methods.
/// </summary>
public bool DontAutoRegister { get; }
/// <summary>
/// Gets the context types commands in this module can be executed in.
/// </summary>
public IReadOnlyCollection<InteractionContextType> ContextTypes { get; }
/// <summary>
/// Gets the install method for commands in this module.
/// </summary>
public IReadOnlyCollection<ApplicationIntegrationType> IntegrationTypes { get; }
internal ModuleInfo(ModuleBuilder builder, InteractionService commandService, IServiceProvider services, ModuleInfo parent = null)
{
CommandService = commandService;
Name = builder.Name;
SlashGroupName = builder.SlashGroupName;
Description = builder.Description;
Parent = parent;
#pragma warning disable CS0618 // Type or member is obsolete
DefaultPermission = builder.DefaultPermission;
#pragma warning restore CS0618 // Type or member is obsolete
IsNsfw = builder.IsNsfw;
#pragma warning disable CS0618 // Type or member is obsolete
IsEnabledInDm = builder.IsEnabledInDm;
#pragma warning restore CS0618 // Type or member is obsolete
DefaultMemberPermissions = BuildDefaultMemberPermissions(builder);
SlashCommands = BuildSlashCommands(builder).ToImmutableArray();
ContextCommands = BuildContextCommands(builder).ToImmutableArray();
ComponentCommands = BuildComponentCommands(builder).ToImmutableArray();
AutocompleteCommands = BuildAutocompleteCommands(builder).ToImmutableArray();
ModalCommands = BuildModalCommands(builder).ToImmutableArray();
SubModules = BuildSubModules(builder, commandService, services).ToImmutableArray();
Attributes = BuildAttributes(builder).ToImmutableArray();
Preconditions = BuildPreconditions(builder).ToImmutableArray();
IsTopLevelGroup = IsSlashGroup && CheckTopLevel(parent);
DontAutoRegister = builder.DontAutoRegister;
ContextTypes = builder.ContextTypes?.ToImmutableArray();
IntegrationTypes = builder.IntegrationTypes?.ToImmutableArray();
GroupedPreconditions = Preconditions.ToLookup(x => x.Group, x => x, StringComparer.Ordinal);
}
private IEnumerable<ModuleInfo> BuildSubModules(ModuleBuilder builder, InteractionService commandService, IServiceProvider services)
{
var result = new List<ModuleInfo>();
foreach (Builders.ModuleBuilder moduleBuilder in builder.SubModules)
result.Add(moduleBuilder.Build(commandService, services, this));
return result;
}
private IEnumerable<SlashCommandInfo> BuildSlashCommands(ModuleBuilder builder)
{
var result = new List<SlashCommandInfo>();
foreach (Builders.SlashCommandBuilder commandBuilder in builder.SlashCommands)
result.Add(commandBuilder.Build(this, CommandService));
return result;
}
private IEnumerable<ContextCommandInfo> BuildContextCommands(ModuleBuilder builder)
{
var result = new List<ContextCommandInfo>();
foreach (Builders.ContextCommandBuilder commandBuilder in builder.ContextCommands)
result.Add(commandBuilder.Build(this, CommandService));
return result;
}
private IEnumerable<ComponentCommandInfo> BuildComponentCommands(ModuleBuilder builder)
{
var result = new List<ComponentCommandInfo>();
foreach (var interactionBuilder in builder.ComponentCommands)
result.Add(interactionBuilder.Build(this, CommandService));
return result;
}
private IEnumerable<AutocompleteCommandInfo> BuildAutocompleteCommands(ModuleBuilder builder)
{
var result = new List<AutocompleteCommandInfo>();
foreach (var commandBuilder in builder.AutocompleteCommands)
result.Add(commandBuilder.Build(this, CommandService));
return result;
}
private IEnumerable<ModalCommandInfo> BuildModalCommands(ModuleBuilder builder)
{
var result = new List<ModalCommandInfo>();
foreach (var commandBuilder in builder.ModalCommands)
result.Add(commandBuilder.Build(this, CommandService));
return result;
}
private IEnumerable<Attribute> BuildAttributes(ModuleBuilder builder)
{
var result = new List<Attribute>();
var currentParent = builder;
while (currentParent != null)
{
result.AddRange(currentParent.Attributes);
currentParent = currentParent.Parent;
}
return result;
}
private static IEnumerable<PreconditionAttribute> BuildPreconditions(ModuleBuilder builder)
{
var preconditions = new List<PreconditionAttribute>();
var parent = builder;
while (parent != null)
{
preconditions.AddRange(parent.Preconditions);
parent = parent.Parent;
}
return preconditions;
}
private static bool CheckTopLevel(ModuleInfo parent)
{
var currentParent = parent;
while (currentParent != null)
{
if (currentParent.IsSlashGroup)
return false;
currentParent = currentParent.Parent;
}
return true;
}
private static GuildPermission? BuildDefaultMemberPermissions(ModuleBuilder builder)
{
var permissions = builder.DefaultMemberPermissions;
var parent = builder.Parent;
while (parent != null)
{
permissions = (permissions ?? 0) | (parent.DefaultMemberPermissions ?? 0).SanitizeGuildPermissions();
parent = parent.Parent;
}
return permissions;
}
}
}