diff --git a/.github/workflows/dotnet.yml b/.github/workflows/build.yml
similarity index 100%
rename from .github/workflows/dotnet.yml
rename to .github/workflows/build.yml
diff --git a/.github/workflows/docs.yml b/.github/workflows/documentation.yml
similarity index 94%
rename from .github/workflows/docs.yml
rename to .github/workflows/documentation.yml
index 2ff09f741..e5bfcce65 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/documentation.yml
@@ -1,105 +1,105 @@
name: "Documentation"
on:
push:
branches: [ main ]
workflow_dispatch:
env:
DOTNET_NOLOGO: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build:
runs-on: ubuntu-latest
name: Build documentation
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
path: DisCatSharp
- name: Setup .NET
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 6.0.400
- name: Restore packages
working-directory: DisCatSharp
run: dotnet restore
- name: Build library
working-directory: DisCatSharp
run: dotnet build -c Release
- name: Test library
working-directory: DisCatSharp
run: dotnet test -c Release
continue-on-error: true
- name: Build Docs
working-directory: DisCatSharp
shell: pwsh
run: ./rebuild-docs.ps1 -DocsPath "./DisCatSharp.Docs" -Output ".." -PackageName "dcs-docs"
- name: Upload packed docs
uses: actions/upload-artifact@v3
with:
name: dcs-docs.zip
path: dcs-docs.zip
retention-days: 30
documentation:
runs-on: windows-latest
name: Upload documentation
needs: build
steps:
- name: Checkout docs repository
uses: actions/checkout@v3
with:
repository: Aiko-IT-Systems/DisCatSharp.Docs
path: DisCatSharp.Docs
token: ${{ secrets.NYUW_TOKEN_GH }}
- name: Download packed docs
uses: actions/download-artifact@v3
with:
name: dcs-docs.zip
- name: Purge old docs
working-directory: DisCatSharp.Docs
shell: pwsh
- run: Get-ChildItem -Exclude .git*,.htaccess | Remove-Item -Recurse -Force
+ run: Get-ChildItem -Exclude .git* | Remove-Item -Recurse -Force
- name: Extract new docs
shell: pwsh
run: Expand-Archive -Path dcs-docs.zip DisCatSharp.Docs/
- #- name: Delete packed docs
- # uses: geekyeggo/delete-artifact@v2
- # with:
- # name: dcs-docs.zip
+ - name: Delete packed docs
+ uses: geekyeggo/delete-artifact@v2
+ with:
+ name: dcs-docs.zip
- name: Commit and push changes
uses: EndBug/add-and-commit@main
with:
cwd: DisCatSharp.Docs
default_author: user_info
author_name: DisCatSharp
author_email: team@aitsys.dev
committer_name: NyuwBot
committer_email: nyuw@aitsys.dev
commit: --signoff
message: 'Docs update for commit ${{ github.repository }} (${{ github.sha }})'
publish-main:
runs-on: ubuntu-latest
name: Publish documentation on main server
needs: documentation
steps:
- name: Get SSH Agent
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.AITSYS_SSH }}
- name: Publish on server
continue-on-error: true
run: ssh -o StrictHostKeyChecking=no -T root@80.153.182.68 -f 'cd /var/www/dcs.aitsys.dev/docs && git pull -f && service apache2 restart'
publish-backup:
runs-on: ubuntu-latest
name: Publish documentation on backup server
needs: documentation
steps:
- name: Get SSH Agent
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.AITSYS_SSH }}
- name: Publish on server
continue-on-error: true
run: ssh -o StrictHostKeyChecking=no -T root@207.180.240.241 -f 'cd /var/www/dcsdocs && git pull -f && service apache2 restart'
diff --git a/.github/workflows/test_docs.yml b/.github/workflows/documentation_test.yml
similarity index 97%
rename from .github/workflows/test_docs.yml
rename to .github/workflows/documentation_test.yml
index 3ce379c7e..5e0505299 100644
--- a/.github/workflows/test_docs.yml
+++ b/.github/workflows/documentation_test.yml
@@ -1,44 +1,42 @@
name: "Test Documentation"
on:
- push:
- branches: [ test ]
workflow_dispatch:
env:
DOTNET_NOLOGO: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build:
runs-on: ubuntu-latest
name: Build documentation
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
path: DisCatSharp
- name: Setup .NET
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 6.0.400
- name: Restore packages
working-directory: DisCatSharp
run: dotnet restore
- name: Build library
working-directory: DisCatSharp
run: dotnet build -c Release
- name: Test library
working-directory: DisCatSharp
run: dotnet test -c Release
continue-on-error: true
- name: Build Docs
working-directory: DisCatSharp
shell: pwsh
run: ./rebuild-docs.ps1 -DocsPath "./DisCatSharp.Docs" -Output ".." -PackageName "dcs-docs"
- name: Upload packed docs
uses: actions/upload-artifact@v3
with:
name: dcs-docs.zip
path: dcs-docs.zip
retention-days: 30
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..4c1532aaf
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,47 @@
+name: "Release DisCatSharp"
+
+on:
+ workflow_dispatch:
+ inputs:
+ version_suffix:
+ description: "Version Suffix"
+ required: false
+ type: string
+ release_as_prerelease:
+ description: "Release as pre-release"
+ required: true
+ type: boolean
+
+jobs:
+ release:
+ runs-on: windows-latest
+ name: Build library and release
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3.0.3
+ with:
+ dotnet-version: 6.0.400
+ - name: Restore dependencies
+ run: dotnet restore
+ - name: Build library as full release
+ if: ${{!inputs.release_as_prerelease}}
+ shell: pwsh
+ run: .\rebuild-lib.ps1 -ArtifactLocation ../dcs-artifacts -Configuration Release
+ - name: Build library as pre-release
+ if: ${{inputs.release_as_prerelease}}
+ shell: pwsh
+ run: .\rebuild-lib.ps1 -ArtifactLocation ../dcs-artifacts -Configuration Release -VersionSuffix ${{github.event.inputs.version_suffix}}
+ - name: Remove invalid packages
+ shell: pwsh
+ run: rm *.symbols.*
+ working-directory: ../dcs-artifacts
+ - name: Publish to NuGet
+ shell: pwsh
+ run: dotnet nuget push --source https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} * --skip-duplicate
+ working-directory: ../dcs-artifacts
+ - name: Publish to GitHub Packages
+ shell: pwsh
+ run: dotnet nuget push --source https://nuget.pkg.github.com/Aiko-IT-Systems/index.json -k ${{secrets.NYUW_TOKEN_GH}} *
+ working-directory: ../dcs-artifacts
diff --git a/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs b/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs
index 3e380d725..9308fa485 100644
--- a/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs
+++ b/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs
@@ -1,329 +1,327 @@
// This file is part of the DisCatSharp project, based off DSharpPlus.
//
// Copyright (c) 2021-2022 AITSYS
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System.Collections.Generic;
using System.Linq;
using DisCatSharp.Entities;
using DisCatSharp.Enums;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace DisCatSharp.ApplicationCommands.Checks;
internal static class ApplicationCommandEqualityChecks
{
///
/// Whether two application commands are equal.
///
/// Source command.
/// Command to check against.
/// The discord client.
/// Whether the equal check is performed for a guild command.
internal static bool IsEqualTo(this DiscordApplicationCommand ac1, DiscordApplicationCommand targetApplicationCommand, DiscordClient client, bool IsGuild)
{
if (targetApplicationCommand is null || ac1 is null)
return false;
DiscordApplicationCommand sourceApplicationCommand = new(
ac1.Name, ac1.Description, ac1.Options,
ac1.Type,
ac1.NameLocalizations, ac1.DescriptionLocalizations,
- ac1.DefaultMemberPermissions, ac1.DmPermission ?? true//, ac1.IsNsfw
+ ac1.DefaultMemberPermissions, ac1.DmPermission ?? true, ac1.IsNsfw
);
if (sourceApplicationCommand.DefaultMemberPermissions == Permissions.None && targetApplicationCommand.DefaultMemberPermissions == null)
sourceApplicationCommand.DefaultMemberPermissions = null;
if (IsGuild)
{
sourceApplicationCommand.DmPermission = null;
targetApplicationCommand.DmPermission = null;
}
client.Logger.Log(ApplicationCommandsExtension.ApplicationCommandsLogLevel, "[AC Change Check] Command {name}\n\n[{jsonOne},{jsontwo}]\n\n", ac1.Name, JsonConvert.SerializeObject(sourceApplicationCommand), JsonConvert.SerializeObject(targetApplicationCommand));
return ac1.Type == targetApplicationCommand.Type && sourceApplicationCommand.SoftEqual(targetApplicationCommand, ac1.Type, ApplicationCommandsExtension.Configuration?.EnableLocalization ?? false, IsGuild);
}
///
/// Checks softly whether two s are the same.
/// Excluding id, application id and version here.
///
/// Source application command.
/// Application command to check against.
/// The application command type.
/// Whether localization is enabled.
/// Whether the equal check is performed for a guild command.
internal static bool SoftEqual(this DiscordApplicationCommand source, DiscordApplicationCommand target, ApplicationCommandType type, bool localizationEnabled = false, bool guild = false)
{
bool? sDmPerm = source.DmPermission ?? true;
bool? tDmPerm = target.DmPermission ?? true;
if (guild)
{
sDmPerm = null;
tDmPerm = null;
}
return localizationEnabled
? type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, true, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type && source.NameLocalizations == target.NameLocalizations
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
- && sDmPerm == tDmPerm
- //&& (source.IsNsfw == target.IsNsfw)
+ && sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw
}
: type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, false, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
- && sDmPerm == tDmPerm
- //&& (source.IsNsfw == target.IsNsfw)
+ && sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw
};
}
///
/// Checks deeply whether two s are the same.
/// Excluding id, application id and version here.
///
/// Source application command.
/// Application command to check against.
/// Whether localization is enabled.
/// The source dm permission.
/// The target dm permission.
internal static bool DeepEqual(DiscordApplicationCommand source, DiscordApplicationCommand target, bool localizationEnabled = false, bool? sDmPerm = null, bool? tDmPerm = null)
{
var rootCheck = true;
/*Console.WriteLine($"{source.Name == target.Name}");
Console.WriteLine($"{source.Description == target.Description}");
Console.WriteLine($"{source.Type == target.Type}");
Console.WriteLine($"{source.DefaultMemberPermissions == target.DefaultMemberPermissions} - {source.DefaultMemberPermissions} == {target.DefaultMemberPermissions}");
Console.WriteLine($"{sDmPerm == tDmPerm}");*/
- rootCheck = source.Name == target.Name && source.Description == target.Description && source.Type == target.Type && source.DefaultMemberPermissions == target.DefaultMemberPermissions && sDmPerm == tDmPerm;
+ rootCheck = source.Name == target.Name && source.Description == target.Description && source.Type == target.Type && source.DefaultMemberPermissions == target.DefaultMemberPermissions && sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw;
if (localizationEnabled)
rootCheck = rootCheck && source.NameLocalizations == target.NameLocalizations && source.DescriptionLocalizations == target.DescriptionLocalizations;
//Console.WriteLine($"{rootCheck}");
if (source.Options == null && target.Options == null)
return rootCheck;
else if ((source.Options != null && target.Options == null) || (source.Options == null && target.Options != null))
return false;
else if (source.Options.Any(o => o.Type == ApplicationCommandOptionType.SubCommandGroup) && target.Options.Any(o => o.Type == ApplicationCommandOptionType.SubCommandGroup))
{
List minimalSourceOptions = new();
List minimalTargetOptions = new();
foreach (var option in source.Options)
{
List minimalSubSourceOptions = new();
if (option.Options != null)
{
foreach (var subOption in option.Options)
{
List minimalSubSubSourceOptions = null;
if (subOption.Options != null)
{
minimalSubSubSourceOptions = new();
foreach (var subSubOption in subOption.Options)
minimalSubSubSourceOptions.Add(new DiscordApplicationCommandOption(
subSubOption.Name, subSubOption.Description, subSubOption.Type, subSubOption.Required,
subSubOption.Choices, null, subSubOption.ChannelTypes, subSubOption.AutoComplete,
subSubOption.MinimumValue, subSubOption.MaximumValue,
localizationEnabled ? subSubOption.NameLocalizations : null,
localizationEnabled ? subSubOption.DescriptionLocalizations : null,
subSubOption.MinimumLength, subSubOption.MaximumLength
));
minimalSubSourceOptions.Add(new DiscordApplicationCommandOption(
subOption.Name, subOption.Description, subOption.Type,
options: minimalSubSubSourceOptions,
nameLocalizations: localizationEnabled ? subOption.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? subOption.DescriptionLocalizations : null
));
}
}
}
minimalSourceOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type,
options: minimalSubSourceOptions,
nameLocalizations: localizationEnabled ? option.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? option.DescriptionLocalizations : null
));
}
foreach (var option in target.Options)
{
List minimalSubTargetOptions = new();
foreach (var subOption in option.Options)
{
List minimalSubSubTargetOptions = null;
if (subOption.Options != null && subOption.Options.Any())
{
minimalSubSubTargetOptions = new();
foreach (var subSubOption in subOption.Options)
minimalSubSubTargetOptions.Add(new DiscordApplicationCommandOption(
subSubOption.Name, subSubOption.Description, subSubOption.Type, subSubOption.Required,
subSubOption.Choices, null, subSubOption.ChannelTypes, subSubOption.AutoComplete,
subSubOption.MinimumValue, subSubOption.MaximumValue,
localizationEnabled ? subSubOption.NameLocalizations : null,
localizationEnabled ? subSubOption.DescriptionLocalizations : null,
subSubOption.MinimumLength, subSubOption.MaximumLength
));
minimalSubTargetOptions.Add(new DiscordApplicationCommandOption(
subOption.Name, subOption.Description, subOption.Type,
options: minimalSubSubTargetOptions,
nameLocalizations: localizationEnabled ? subOption.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? subOption.DescriptionLocalizations : null
));
}
}
minimalTargetOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type,
options: minimalSubTargetOptions,
nameLocalizations: localizationEnabled ? option.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? option.DescriptionLocalizations : null
));
}
var sOpt = JsonConvert.SerializeObject(minimalSourceOptions, Formatting.None);
var tOpt = JsonConvert.SerializeObject(minimalTargetOptions, Formatting.None);
//Console.WriteLine("Checking equality subcommandgroup");
//Console.WriteLine($"{rootCheck}");
//Console.WriteLine($"{sOpt}");
//Console.WriteLine($"{tOpt}");
return rootCheck && sOpt == tOpt;
}
else if (source.Options.Any(o => o.Type == ApplicationCommandOptionType.SubCommand) && target.Options.Any(o => o.Type == ApplicationCommandOptionType.SubCommand))
{
List minimalSourceOptions = new();
List minimalTargetOptions = new();
foreach (var option in source.Options)
{
List minimalSubSourceOptions =null;
if (option.Options != null)
{
minimalSubSourceOptions = new();
foreach (var subOption in option.Options)
minimalSubSourceOptions.Add(new DiscordApplicationCommandOption(
subOption.Name, subOption.Description, subOption.Type, subOption.Required,
subOption.Choices, null, subOption.ChannelTypes, subOption.AutoComplete,
subOption.MinimumValue, subOption.MaximumValue,
localizationEnabled ? subOption.NameLocalizations : null,
localizationEnabled ? subOption.DescriptionLocalizations : null,
subOption.MinimumLength, subOption.MaximumLength
));
}
minimalSourceOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type,
options: minimalSubSourceOptions,
nameLocalizations: localizationEnabled ? option.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? option.DescriptionLocalizations : null
));
}
foreach (var option in target.Options)
{
List minimalSubTargetOptions = null;
if (option.Options != null && option.Options.Any())
{
minimalSubTargetOptions = new();
foreach (var subOption in option.Options)
minimalSubTargetOptions.Add(new DiscordApplicationCommandOption(
subOption.Name, subOption.Description, subOption.Type, subOption.Required,
subOption.Choices, null, subOption.ChannelTypes, subOption.AutoComplete,
subOption.MinimumValue, subOption.MaximumValue,
localizationEnabled ? subOption.NameLocalizations : null,
localizationEnabled ? subOption.DescriptionLocalizations : null,
subOption.MinimumLength, subOption.MaximumLength
));
}
minimalTargetOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type,
options: minimalSubTargetOptions,
nameLocalizations: localizationEnabled ? option.NameLocalizations : null,
descriptionLocalizations: localizationEnabled ? option.DescriptionLocalizations : null
));
}
var sOpt = JsonConvert.SerializeObject(minimalSourceOptions, Formatting.None);
var tOpt = JsonConvert.SerializeObject(minimalTargetOptions, Formatting.None);
//Console.WriteLine("Checking equality subcommand");
//Console.WriteLine($"{rootCheck}");
//Console.WriteLine($"{sOpt}");
//Console.WriteLine($"{tOpt}");
return rootCheck && sOpt == tOpt;
}
else
{
List minimalSourceOptions = new();
List minimalTargetOptions = new();
foreach (var option in source.Options)
minimalSourceOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type, option.Required,
option.Choices, null, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue,
localizationEnabled ? option.NameLocalizations : null,
localizationEnabled ? option.DescriptionLocalizations : null,
option.MinimumLength, option.MaximumLength
));
foreach (var option in target.Options)
minimalTargetOptions.Add(new DiscordApplicationCommandOption(
option.Name, option.Description, option.Type, option.Required,
option.Choices, null, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue,
localizationEnabled ? option.NameLocalizations : null,
localizationEnabled ? option.DescriptionLocalizations : null,
option.MinimumLength, option.MaximumLength
));
var sOpt = JsonConvert.SerializeObject(minimalSourceOptions, Formatting.None);
var tOpt = JsonConvert.SerializeObject(minimalTargetOptions, Formatting.None);
//Console.WriteLine("Checking equality other");
//Console.WriteLine($"{rootCheck}");
//Console.WriteLine($"{sOpt}");
//Console.WriteLine($"{tOpt}");
return rootCheck && sOpt == tOpt;
}
}
}
diff --git a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj
index 489e86ed2..8d8b27b4f 100644
--- a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj
+++ b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj
@@ -1,38 +1,38 @@
DisCatSharp.ApplicationCommands
DisCatSharp.ApplicationCommands
DisCatSharp.ApplicationCommands
DisCatSharp Application Commands Extension
Use it on top of your DisCatSharp powered bot and unleash the power of application commands in discord.
Documentation: https://docs.discatsharp.tech/articles/modules/application_commands/intro.html
DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Application Commands,Context Menu Commands
-
-
+
+
diff --git a/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs b/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs
index b676b5d01..abdc0560a 100644
--- a/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs
+++ b/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs
@@ -1,371 +1,371 @@
// This file is part of the DisCatSharp project, based off DSharpPlus.
//
// Copyright (c) 2021-2022 AITSYS
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using DisCatSharp.ApplicationCommands.Attributes;
using DisCatSharp.ApplicationCommands.Context;
using DisCatSharp.ApplicationCommands.Entities;
using DisCatSharp.ApplicationCommands.Enums;
using DisCatSharp.Entities;
using DisCatSharp.Enums;
namespace DisCatSharp.ApplicationCommands.Workers;
///
/// Represents a .
///
internal class CommandWorker
{
///
/// Parses context menu application commands.
///
/// The type.
/// List of method infos.
/// The optional command translations.
/// Too much.
internal static Task<
(
List applicationCommands,
List> commandTypeSources,
List contextMenuCommands,
bool withLocalization
)
> ParseContextMenuCommands(Type type, IEnumerable methods, List translator = null)
{
List commands = new();
List> commandTypeSources = new();
List contextMenuCommands = new();
foreach (var contextMethod in methods)
{
var contextAttribute = contextMethod.GetCustomAttribute();
DiscordApplicationCommandLocalization nameLocalizations = null;
var commandTranslation = translator?.Single(c => c.Name == contextAttribute.Name && c.Type == contextAttribute.Type);
if (commandTranslation != null)
nameLocalizations = commandTranslation.NameTranslations;
- var command = new DiscordApplicationCommand(contextAttribute.Name, null, null, contextAttribute.Type, nameLocalizations, null, contextAttribute.DefaultMemberPermissions, contextAttribute.DmPermission ?? true);
+ var command = new DiscordApplicationCommand(contextAttribute.Name, null, null, contextAttribute.Type, nameLocalizations, null, contextAttribute.DefaultMemberPermissions, contextAttribute.DmPermission ?? true, isNsfw: contextAttribute.IsNsfw);
var parameters = contextMethod.GetParameters();
if (parameters.Length == 0 || parameters == null || !ReferenceEquals(parameters.FirstOrDefault()?.ParameterType, typeof(ContextMenuContext)))
throw new ArgumentException($"The first argument of the command '{contextAttribute.Name}' has to be an ContextMenuContext!");
if (parameters.Length > 1)
throw new ArgumentException($"The context menu command '{contextAttribute.Name}' cannot have parameters!");
contextMenuCommands.Add(new ContextMenuCommand { Method = contextMethod, Name = contextAttribute.Name });
commands.Add(command);
commandTypeSources.Add(new KeyValuePair(type, type));
}
return Task.FromResult((commands, commandTypeSources, contextMenuCommands, translator != null));
}
///
/// Parses single application commands.
///
/// The type.
/// List of method infos.
/// The optional guild id.
/// The optional command translations.
/// Too much.
internal static async Task<
(
List applicationCommands,
List> commandTypeSources,
List commandMethods,
bool withLocalization
)
> ParseBasicSlashCommandsAsync(Type type, IEnumerable methods, ulong? guildId = null, List translator = null)
{
List commands = new();
List> commandTypeSources = new();
List commandMethods = new();
foreach (var method in methods)
{
var commandAttribute = method.GetCustomAttribute();
var parameters = method.GetParameters();
if (parameters.Length == 0 || parameters == null || !ReferenceEquals(parameters.FirstOrDefault()?.ParameterType, typeof(InteractionContext)))
throw new ArgumentException($"The first argument of the command '{commandAttribute.Name}' has to be an InteractionContext!");
var options = await ApplicationCommandsExtension.ParseParametersAsync(parameters.Skip(1), commandAttribute.Name, guildId);
commandMethods.Add(new CommandMethod { Method = method, Name = commandAttribute.Name });
DiscordApplicationCommandLocalization nameLocalizations = null;
DiscordApplicationCommandLocalization descriptionLocalizations = null;
List localizedOptions = null;
var commandTranslation = translator?.Single(c => c.Name == commandAttribute.Name && c.Type == ApplicationCommandType.ChatInput);
if (commandTranslation != null && commandTranslation.Options != null)
{
localizedOptions = new List(options.Count);
foreach (var option in options)
{
var choices = option.Choices != null ? new List(option.Choices.Count) : null;
if (option.Choices != null)
foreach (var choice in option.Choices)
choices.Add(new DiscordApplicationCommandOptionChoice(choice.Name, choice.Value, commandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations));
localizedOptions.Add(new DiscordApplicationCommandOption(option.Name, option.Description, option.Type, option.Required,
choices, option.Options, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue,
commandTranslation.Options.Single(o => o.Name == option.Name).NameTranslations, commandTranslation.Options.Single(o => o.Name == option.Name).DescriptionTranslations,
option.MinimumLength, option.MaximumLength
));
}
nameLocalizations = commandTranslation.NameTranslations;
descriptionLocalizations = commandTranslation.DescriptionTranslations;
}
- var payload = new DiscordApplicationCommand(commandAttribute.Name, commandAttribute.Description, (localizedOptions != null && localizedOptions.Any() ? localizedOptions : null) ?? (options != null && options.Any() ? options : null), ApplicationCommandType.ChatInput, nameLocalizations, descriptionLocalizations, commandAttribute.DefaultMemberPermissions, commandAttribute.DmPermission ?? true);
+ var payload = new DiscordApplicationCommand(commandAttribute.Name, commandAttribute.Description, (localizedOptions != null && localizedOptions.Any() ? localizedOptions : null) ?? (options != null && options.Any() ? options : null), ApplicationCommandType.ChatInput, nameLocalizations, descriptionLocalizations, commandAttribute.DefaultMemberPermissions, commandAttribute.DmPermission ?? true, isNsfw: commandAttribute.IsNsfw);
commands.Add(payload);
commandTypeSources.Add(new KeyValuePair(type, type));
}
return (commands, commandTypeSources, commandMethods, translator != null);
}
}
///
/// Represents a .
///
internal class NestedCommandWorker
{
///
/// Parses application command groups.
///
/// The type.
/// List of type infos.
/// The optional guild id.
/// The optional group translations.
/// Too much.
internal static async Task<
(
List applicationCommands,
List> commandTypeSources,
List