diff --git a/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs b/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs
index 0f898cfa8..cfbec2be1 100644
--- a/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs
+++ b/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs
@@ -1,74 +1,74 @@
// 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;
namespace DisCatSharp.CommandsNext.Converters;
///
/// Represents a argument binding result.
///
-public struct ArgumentBindingResult
+public readonly struct ArgumentBindingResult
{
///
/// Gets a value indicating whether the binding is successful.
///
public bool IsSuccessful { get; }
///
/// Gets the converted.
///
public object[] Converted { get; }
///
/// Gets the raw.
///
public IReadOnlyList Raw { get; }
///
/// Gets the reason.
///
public Exception Reason { get; }
///
/// Initializes a new instance of the class.
///
/// The converted.
/// The raw.
public ArgumentBindingResult(object[] converted, IReadOnlyList raw)
{
this.IsSuccessful = true;
this.Reason = null;
this.Converted = converted;
this.Raw = raw;
}
///
/// Initializes a new instance of the class.
///
/// The ex.
public ArgumentBindingResult(Exception ex)
{
this.IsSuccessful = false;
this.Reason = ex;
this.Converted = null;
this.Raw = null;
}
}
diff --git a/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs b/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs
index cd4e26d96..597ccfaf2 100644
--- a/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs
+++ b/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs
@@ -1,52 +1,52 @@
// 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 DisCatSharp.Entities;
namespace DisCatSharp.CommandsNext.Entities;
///
/// Represents a formatted help message.
///
-public struct CommandHelpMessage
+public readonly struct CommandHelpMessage
{
///
/// Gets the contents of the help message.
///
public string Content { get; }
///
/// Gets the embed attached to the help message.
///
public DiscordEmbed Embed { get; }
///
/// Creates a new instance of a help message.
///
/// Contents of the message.
/// Embed to attach to the message.
public CommandHelpMessage(string content = null, DiscordEmbed embed = null)
{
this.Content = content;
this.Embed = embed;
}
}
diff --git a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
index 69cba3138..3fa4d24cf 100644
--- a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
+++ b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
@@ -1,207 +1,207 @@
// 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.Threading.Tasks;
using DisCatSharp.Entities;
using Microsoft.Extensions.DependencyInjection;
namespace DisCatSharp.CommandsNext;
///
/// Represents a context in which a command is executed.
///
public sealed class CommandContext
{
///
/// Gets the client which received the message.
///
public DiscordClient Client { get; internal set; }
///
/// Gets the message that triggered the execution.
///
public DiscordMessage Message { get; internal set; }
///
/// Gets the channel in which the execution was triggered,
///
public DiscordChannel Channel
=> this.Message.Channel;
///
/// Gets the guild in which the execution was triggered. This property is null for commands sent over direct messages.
///
public DiscordGuild Guild
=> this.Channel.Guild;
///
/// Gets the user who triggered the execution.
///
public DiscordUser User
=> this.Message.Author;
///
/// Gets the member who triggered the execution. This property is null for commands sent over direct messages.
///
public DiscordMember Member
=> this._lazyMember.Value;
private readonly Lazy _lazyMember;
///
/// Gets the CommandsNext service instance that handled this command.
///
public CommandsNextExtension CommandsNext { get; internal set; }
///
/// Gets the service provider for this CNext instance.
///
public IServiceProvider Services { get; internal set; }
///
/// Gets the command that is being executed.
///
public Command Command { get; internal set; }
///
/// Gets the overload of the command that is being executed.
///
public CommandOverload Overload { get; internal set; }
///
/// Gets the list of raw arguments passed to the command.
///
public IReadOnlyList RawArguments { get; internal set; }
///
/// Gets the raw string from which the arguments were extracted.
///
public string RawArgumentString { get; internal set; }
///
/// Gets the prefix used to invoke the command.
///
public string Prefix { get; internal set; }
///
/// Gets or sets the config.
///
internal CommandsNextConfiguration Config { get; set; }
///
/// Gets or sets the service scope context.
///
internal ServiceContext ServiceScopeContext { get; set; }
///
/// Initializes a new instance of the class.
///
internal CommandContext()
{
this._lazyMember = new Lazy(() => this.Guild != null && this.Guild.Members.TryGetValue(this.User.Id, out var member) ? member : this.Guild?.GetMemberAsync(this.User.Id).ConfigureAwait(false).GetAwaiter().GetResult());
}
///
/// Quickly respond to the message that triggered the command.
///
/// Message to respond with.
///
public Task RespondAsync(string content)
=> this.Message.RespondAsync(content);
///
/// Quickly respond to the message that triggered the command.
///
/// Embed to attach.
///
public Task RespondAsync(DiscordEmbed embed)
=> this.Message.RespondAsync(embed);
///
/// Quickly respond to the message that triggered the command.
///
/// Message to respond with.
/// Embed to attach.
///
public Task RespondAsync(string content, DiscordEmbed embed)
=> this.Message.RespondAsync(content, embed);
///
/// Quickly respond to the message that triggered the command.
///
/// The Discord Message builder.
///
public Task RespondAsync(DiscordMessageBuilder builder)
=> this.Message.RespondAsync(builder);
///
/// Quickly respond to the message that triggered the command.
///
/// The Discord Message builder.
///
public Task RespondAsync(Action action)
=> this.Message.RespondAsync(action);
///
/// Triggers typing in the channel containing the message that triggered the command.
///
///
public Task TriggerTypingAsync()
=> this.Channel.TriggerTypingAsync();
- internal struct ServiceContext : IDisposable
+ internal readonly struct ServiceContext : IDisposable
{
///
/// Gets the provider.
///
public IServiceProvider Provider { get; }
///
/// Gets the scope.
///
public IServiceScope Scope { get; }
///
/// Gets a value indicating whether is initialized.
///
public bool IsInitialized { get; }
///
/// Initializes a new instance of the class.
///
/// The services.
/// The scope.
public ServiceContext(IServiceProvider services, IServiceScope scope)
{
this.Provider = services;
this.Scope = scope;
this.IsInitialized = true;
}
///
/// Disposes the command context.
///
public void Dispose() => this.Scope?.Dispose();
}
}
diff --git a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj
new file mode 100644
index 000000000..85998cde2
--- /dev/null
+++ b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+ DisCatSharp.Experimental
+ DisCatSharp.Experimental
+
+
+
+ DisCatSharp.Experimental
+
+ DisCatSharp.Experimental
+
+ Experimental changes for DisCatSharp.
+
+ DisCatSharp,Experimental,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs b/DisCatSharp.Experimental/Program.cs
similarity index 62%
copy from DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs
copy to DisCatSharp.Experimental/Program.cs
index cd4e26d96..43840a31e 100644
--- a/DisCatSharp.CommandsNext/Entities/CommandHelpMessage.cs
+++ b/DisCatSharp.Experimental/Program.cs
@@ -1,52 +1,33 @@
// 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 DisCatSharp.Entities;
+using System;
-namespace DisCatSharp.CommandsNext.Entities;
+namespace DisCatSharp.Experimental;
-///
-/// Represents a formatted help message.
-///
-public struct CommandHelpMessage
+internal class Program
{
- ///
- /// Gets the contents of the help message.
- ///
- public string Content { get; }
-
- ///
- /// Gets the embed attached to the help message.
- ///
- public DiscordEmbed Embed { get; }
-
- ///
- /// Creates a new instance of a help message.
- ///
- /// Contents of the message.
- /// Embed to attach to the message.
- public CommandHelpMessage(string content = null, DiscordEmbed embed = null)
+ static void Main(string[] args)
{
- this.Content = content;
- this.Embed = embed;
+ Console.WriteLine("Hello, World!");
}
}
diff --git a/DisCatSharp.Lavalink/Entities/LavalinkEqualizerTypes.cs b/DisCatSharp.Lavalink/Entities/LavalinkEqualizerTypes.cs
index c06ba9c94..1d4af2375 100644
--- a/DisCatSharp.Lavalink/Entities/LavalinkEqualizerTypes.cs
+++ b/DisCatSharp.Lavalink/Entities/LavalinkEqualizerTypes.cs
@@ -1,84 +1,84 @@
// 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 Newtonsoft.Json;
namespace DisCatSharp.Lavalink;
///
/// Represents Lavalink equalizer band adjustment. This is used to alter the sound output by using Lavalink's equalizer.
///
-public struct LavalinkBandAdjustment
+public readonly struct LavalinkBandAdjustment
{
///
/// Gets the ID of the band to adjust.
///
[JsonProperty("band")]
public int BandId { get; }
///
/// Gets the gain of the specified band.
///
[JsonProperty("gain")]
public float Gain { get; }
///
/// Creates a new band adjustment with specified parameters.
///
/// Which band to adjust. Must be in 0-14 range.
/// By how much to adjust the band. Must be greater than or equal to -0.25 (muted), and less than or equal to +1.0. +0.25 means the band is doubled.
public LavalinkBandAdjustment(int bandId, float gain)
{
if (bandId < 0 || bandId > 14)
throw new ArgumentOutOfRangeException(nameof(bandId), "Band ID cannot be lower than 0 or greater than 14.");
if (gain < -0.25 || gain > 1.0)
throw new ArgumentOutOfRangeException(nameof(gain), "Gain cannot be lower than -0.25 or greater than 1.0.");
this.BandId = bandId;
this.Gain = gain;
}
}
///
/// The lavalink band adjustment comparer.
///
internal class LavalinkBandAdjustmentComparer : IEqualityComparer
{
///
/// Whether two band adjustments are equal.
///
/// The first band adjustments.
/// The second band adjustments.
public bool Equals(LavalinkBandAdjustment x, LavalinkBandAdjustment y)
=> x.BandId == y.BandId;
///
/// Gets the hash code.
///
/// The band adjustments.
public int GetHashCode(LavalinkBandAdjustment obj)
=> obj.BandId;
}
diff --git a/DisCatSharp.VoiceNext/AudioFormat.cs b/DisCatSharp.VoiceNext/AudioFormat.cs
index a2405bc26..2b037f789 100644
--- a/DisCatSharp.VoiceNext/AudioFormat.cs
+++ b/DisCatSharp.VoiceNext/AudioFormat.cs
@@ -1,163 +1,163 @@
// 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.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
namespace DisCatSharp.VoiceNext;
///
/// Defines the format of PCM data consumed or produced by Opus.
///
-public struct AudioFormat
+public readonly struct AudioFormat
{
///
/// Gets the collection of sampling rates (in Hz) the Opus encoder can use.
///
public static IReadOnlyCollection AllowedSampleRates { get; } = new ReadOnlyCollection(new[] { 8000, 12000, 16000, 24000, 48000 });
///
/// Gets the collection of channel counts the Opus encoder can use.
///
public static IReadOnlyCollection AllowedChannelCounts { get; } = new ReadOnlyCollection(new[] { 1, 2 });
///
/// Gets the collection of sample durations (in ms) the Opus encoder can use.
///
public static IReadOnlyCollection AllowedSampleDurations { get; } = new ReadOnlyCollection(new[] { 5, 10, 20, 40, 60 });
///
/// Gets the default audio format. This is a format configured for 48kHz sampling rate, 2 channels, with music quality preset.
///
public static AudioFormat Default { get; } = new(48000, 2, VoiceApplication.Music);
///
/// Gets the audio sampling rate in Hz.
///
public int SampleRate { get; }
///
/// Gets the audio channel count.
///
public int ChannelCount { get; }
///
/// Gets the voice application, which dictates the quality preset.
///
public VoiceApplication VoiceApplication { get; }
///
/// Creates a new audio format for use with Opus encoder.
///
/// Audio sampling rate in Hz.
/// Number of audio channels in the data.
/// Encoder preset to use.
public AudioFormat(int sampleRate = 48000, int channelCount = 2, VoiceApplication voiceApplication = VoiceApplication.Music)
{
if (!AllowedSampleRates.Contains(sampleRate))
throw new ArgumentOutOfRangeException(nameof(sampleRate), "Invalid sample rate specified.");
if (!AllowedChannelCounts.Contains(channelCount))
throw new ArgumentOutOfRangeException(nameof(channelCount), "Invalid channel count specified.");
if (voiceApplication != VoiceApplication.Music && voiceApplication != VoiceApplication.Voice && voiceApplication != VoiceApplication.LowLatency)
throw new ArgumentOutOfRangeException(nameof(voiceApplication), "Invalid voice application specified.");
this.SampleRate = sampleRate;
this.ChannelCount = channelCount;
this.VoiceApplication = voiceApplication;
}
///
/// Calculates a sample size in bytes.
///
/// Millisecond duration of a sample.
/// Calculated sample size in bytes.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CalculateSampleSize(int sampleDuration)
{
if (!AllowedSampleDurations.Contains(sampleDuration))
throw new ArgumentOutOfRangeException(nameof(sampleDuration), "Invalid sample duration specified.");
// Sample size in bytes is a product of the following:
// - duration in milliseconds
// - number of channels
// - sample rate in kHz
// - size of data (in this case, sizeof(int16_t))
// which comes down to below:
return sampleDuration * this.ChannelCount * (this.SampleRate / 1000) * 2;
}
///
/// Gets the maximum buffer size for decoding. This method should be called when decoding Opus data to PCM, to ensure sufficient buffer size.
///
/// Buffer size required to decode data.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetMaximumBufferSize()
=> this.CalculateMaximumFrameSize();
///
/// Calculates the sample duration.
///
/// The sample size.
/// An int.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int CalculateSampleDuration(int sampleSize)
=> sampleSize / (this.SampleRate / 1000) / this.ChannelCount / 2 /* sizeof(int16_t) */;
///
/// Calculates the frame size.
///
/// The sample duration.
/// An int.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int CalculateFrameSize(int sampleDuration)
=> sampleDuration * (this.SampleRate / 1000);
///
/// Calculates the maximum frame size.
///
/// An int.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int CalculateMaximumFrameSize()
=> 120 * (this.SampleRate / 1000);
///
/// Samples the count to sample size.
///
/// The sample count.
/// An int.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int SampleCountToSampleSize(int sampleCount)
=> sampleCount * this.ChannelCount * 2 /* sizeof(int16_t) */;
///
/// Are the valid.
///
/// A bool.
internal bool IsValid()
=> AllowedSampleRates.Contains(this.SampleRate) && AllowedChannelCounts.Contains(this.ChannelCount) &&
(this.VoiceApplication == VoiceApplication.Music || this.VoiceApplication == VoiceApplication.Voice || this.VoiceApplication == VoiceApplication.LowLatency);
}
diff --git a/DisCatSharp.sln b/DisCatSharp.sln
index 0aba3f024..12ba97394 100644
--- a/DisCatSharp.sln
+++ b/DisCatSharp.sln
@@ -1,151 +1,153 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.31911.260
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp", "DisCatSharp\DisCatSharp.csproj", "{EB3D8310-DFAD-4295-97F9-82E253647583}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.VoiceNext", "DisCatSharp.VoiceNext\DisCatSharp.VoiceNext.csproj", "{FB6B9EE9-65FB-4DFB-8D51-06F0BE6C1BA5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4255B64D-92EC-46B3-BC3B-ED2C3A8073EE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
BUILDING.md = BUILDING.md
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
CONTRIBUTING.md = CONTRIBUTING.md
LICENSE.md = LICENSE.md
README.md = README.md
SECURITY.md = SECURITY.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.CommandsNext", "DisCatSharp.CommandsNext\DisCatSharp.CommandsNext.csproj", "{C8ED55FB-E028-468D-955F-1534C20274EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Interactivity", "DisCatSharp.Interactivity\DisCatSharp.Interactivity.csproj", "{DD32BEC3-0189-479F-86DC-CCF95E5634A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F953F5D0-F0C9-41E6-ADBF-60A76D295899}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.config = .nuget\NuGet.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build Items", "Build Items", "{84464D70-687B-40A8-836D-C4F737698969}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
.github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml
.github\dependabot.yml = .github\dependabot.yml
DisCatSharp.targets = DisCatSharp.targets
docs-oneclick-rebuild.ps1 = docs-oneclick-rebuild.ps1
.github\workflows\docs.yml = .github\workflows\docs.yml
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
Library.targets = Library.targets
NuGet.targets = NuGet.targets
oneclick-rebuild.ps1 = oneclick-rebuild.ps1
Package.targets = Package.targets
rebuild-all.ps1 = rebuild-all.ps1
rebuild-docs.ps1 = rebuild-docs.ps1
rebuild-lib.ps1 = rebuild-lib.ps1
Version.targets = Version.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{430C28D8-5F85-4D6E-AA68-211549435245}"
ProjectSection(SolutionItems) = preProject
.github\ISSUE_TEMPLATE\bug_report.md = .github\ISSUE_TEMPLATE\bug_report.md
.github\CODEOWNERS = .github\CODEOWNERS
.github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml
.github\workflows\docs-preview.yml = .github\workflows\docs-preview.yml
.github\workflows\docs.yml = .github\workflows\docs.yml
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
.github\ISSUE_TEMPLATE\feature_request.md = .github\ISSUE_TEMPLATE\feature_request.md
.github\FUNDING.yml = .github\FUNDING.yml
.github\pull_request_template.md = .github\pull_request_template.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Lavalink", "DisCatSharp.Lavalink\DisCatSharp.Lavalink.csproj", "{A8B8FB09-C6AF-4F28-89B8-B53EE0DCE6E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.VoiceNext.Natives", "DisCatSharp.VoiceNext.Natives\DisCatSharp.VoiceNext.Natives.csproj", "{BEC47B41-71E4-41D1-A4F9-BB7C56A1B82B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Common", "DisCatSharp.Common\DisCatSharp.Common.csproj", "{CD84A5C7-C7FF-48CA-B23D-FA726CF80E09}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.ApplicationCommands", "DisCatSharp.ApplicationCommands\DisCatSharp.ApplicationCommands.csproj", "{AD530FD0-523C-4DE7-9AF6-B9A3785492C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Configuration", "DisCatSharp.Configuration\DisCatSharp.Configuration.csproj", "{603287D3-1EF2-47F1-A611-C7F25869DE14}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Configuration.Tests", "DisCatSharp.Configuration.Tests\DisCatSharp.Configuration.Tests.csproj", "{E15E88B4-63AD-42DE-B685-D31697C62194}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Hosting", "DisCatSharp.Hosting\DisCatSharp.Hosting.csproj", "{72CCE5D5-926B-432A-876A-065FA2BC9B7B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Hosting.Tests", "DisCatSharp.Hosting.Tests\DisCatSharp.Hosting.Tests.csproj", "{D02B598A-F0C9-4A8C-B8DE-7C0BAC8C9B94}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DisCatSharp.Hosting.DependencyInjection", "DisCatSharp.Hosting.DependencyInjection\DisCatSharp.Hosting.DependencyInjection.csproj", "{2D67D1DD-E5B2-40C7-80E2-54D63730E7F0}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DisCatSharp.Experimental", "DisCatSharp.Experimental\DisCatSharp.Experimental.csproj", "{CF03EADC-E178-45B3-BD72-B6F70B625C8F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EB3D8310-DFAD-4295-97F9-82E253647583}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB3D8310-DFAD-4295-97F9-82E253647583}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB3D8310-DFAD-4295-97F9-82E253647583}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB3D8310-DFAD-4295-97F9-82E253647583}.Release|Any CPU.Build.0 = Release|Any CPU
{FB6B9EE9-65FB-4DFB-8D51-06F0BE6C1BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB6B9EE9-65FB-4DFB-8D51-06F0BE6C1BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB6B9EE9-65FB-4DFB-8D51-06F0BE6C1BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB6B9EE9-65FB-4DFB-8D51-06F0BE6C1BA5}.Release|Any CPU.Build.0 = Release|Any CPU
{C8ED55FB-E028-468D-955F-1534C20274EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8ED55FB-E028-468D-955F-1534C20274EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8ED55FB-E028-468D-955F-1534C20274EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8ED55FB-E028-468D-955F-1534C20274EF}.Release|Any CPU.Build.0 = Release|Any CPU
{DD32BEC3-0189-479F-86DC-CCF95E5634A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD32BEC3-0189-479F-86DC-CCF95E5634A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD32BEC3-0189-479F-86DC-CCF95E5634A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD32BEC3-0189-479F-86DC-CCF95E5634A9}.Release|Any CPU.Build.0 = Release|Any CPU
{A8B8FB09-C6AF-4F28-89B8-B53EE0DCE6E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8B8FB09-C6AF-4F28-89B8-B53EE0DCE6E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8B8FB09-C6AF-4F28-89B8-B53EE0DCE6E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8B8FB09-C6AF-4F28-89B8-B53EE0DCE6E5}.Release|Any CPU.Build.0 = Release|Any CPU
{BEC47B41-71E4-41D1-A4F9-BB7C56A1B82B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEC47B41-71E4-41D1-A4F9-BB7C56A1B82B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEC47B41-71E4-41D1-A4F9-BB7C56A1B82B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEC47B41-71E4-41D1-A4F9-BB7C56A1B82B}.Release|Any CPU.Build.0 = Release|Any CPU
{CD84A5C7-C7FF-48CA-B23D-FA726CF80E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD84A5C7-C7FF-48CA-B23D-FA726CF80E09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD84A5C7-C7FF-48CA-B23D-FA726CF80E09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD84A5C7-C7FF-48CA-B23D-FA726CF80E09}.Release|Any CPU.Build.0 = Release|Any CPU
{AD530FD0-523C-4DE7-9AF6-B9A3785492C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD530FD0-523C-4DE7-9AF6-B9A3785492C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD530FD0-523C-4DE7-9AF6-B9A3785492C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD530FD0-523C-4DE7-9AF6-B9A3785492C2}.Release|Any CPU.Build.0 = Release|Any CPU
{603287D3-1EF2-47F1-A611-C7F25869DE14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{603287D3-1EF2-47F1-A611-C7F25869DE14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{603287D3-1EF2-47F1-A611-C7F25869DE14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{603287D3-1EF2-47F1-A611-C7F25869DE14}.Release|Any CPU.Build.0 = Release|Any CPU
{E15E88B4-63AD-42DE-B685-D31697C62194}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E15E88B4-63AD-42DE-B685-D31697C62194}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E15E88B4-63AD-42DE-B685-D31697C62194}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E15E88B4-63AD-42DE-B685-D31697C62194}.Release|Any CPU.Build.0 = Release|Any CPU
{72CCE5D5-926B-432A-876A-065FA2BC9B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72CCE5D5-926B-432A-876A-065FA2BC9B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72CCE5D5-926B-432A-876A-065FA2BC9B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72CCE5D5-926B-432A-876A-065FA2BC9B7B}.Release|Any CPU.Build.0 = Release|Any CPU
{D02B598A-F0C9-4A8C-B8DE-7C0BAC8C9B94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D02B598A-F0C9-4A8C-B8DE-7C0BAC8C9B94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D02B598A-F0C9-4A8C-B8DE-7C0BAC8C9B94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D02B598A-F0C9-4A8C-B8DE-7C0BAC8C9B94}.Release|Any CPU.Build.0 = Release|Any CPU
{2D67D1DD-E5B2-40C7-80E2-54D63730E7F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D67D1DD-E5B2-40C7-80E2-54D63730E7F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D67D1DD-E5B2-40C7-80E2-54D63730E7F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D67D1DD-E5B2-40C7-80E2-54D63730E7F0}.Release|Any CPU.Build.0 = Release|Any CPU
- {1407FAE8-DAC1-4E89-AA15-4E4592CCC8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1407FAE8-DAC1-4E89-AA15-4E4592CCC8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1407FAE8-DAC1-4E89-AA15-4E4592CCC8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1407FAE8-DAC1-4E89-AA15-4E4592CCC8A0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CF03EADC-E178-45B3-BD72-B6F70B625C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CF03EADC-E178-45B3-BD72-B6F70B625C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CF03EADC-E178-45B3-BD72-B6F70B625C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CF03EADC-E178-45B3-BD72-B6F70B625C8F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {23F3A981-51B8-4285-A38C-3267F1D25FE7}
EndGlobalSection
EndGlobal
diff --git a/DisCatSharp/Entities/Color/DiscordColor.Colors.cs b/DisCatSharp/Entities/Color/DiscordColor.Colors.cs
index f451a0845..82542b1c9 100644
--- a/DisCatSharp/Entities/Color/DiscordColor.Colors.cs
+++ b/DisCatSharp/Entities/Color/DiscordColor.Colors.cs
@@ -1,242 +1,242 @@
// 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.
namespace DisCatSharp.Entities;
-public partial struct DiscordColor
+public readonly partial struct DiscordColor
{
#region Black and White
///
/// Represents no color, or integer 0;
///
public static DiscordColor None { get; } = new(0);
///
/// A near-black color. Due to API limitations, the color is #010101, rather than #000000, as the latter is treated as no color.
///
public static DiscordColor Black { get; } = new(0x010101);
///
/// White, or #FFFFFF.
///
public static DiscordColor White { get; } = new(0xFFFFFF);
///
/// Gray, or #808080.
///
public static DiscordColor Gray { get; } = new(0x808080);
///
/// Dark gray, or #A9A9A9.
///
public static DiscordColor DarkGray { get; } = new(0xA9A9A9);
///
/// Light gray, or #808080.
///
public static DiscordColor LightGray { get; } = new(0xD3D3D3);
///
/// Very dark gray, or #666666.
///
public static DiscordColor VeryDarkGray { get; } = new(0x666666);
#endregion
#region Discord branding colors
// See https://discord.com/branding.
///
/// Discord Blurple, or #5865F2.
///
public static DiscordColor Blurple { get; } = new(0x5865F2);
///
/// Discord Fuchsia, or #EB459E.
///
public static DiscordColor Fuchsia { get; } = new(0xEB459E);
///
/// Discord Green, or #57F287.
///
public static DiscordColor Green { get; } = new(0x57F287);
///
/// Discord Yellow, or #FEE75C.
///
public static DiscordColor Yellow { get; } = new(0xFEE75C);
///
/// Discord Red, or #ED4245.
///
public static DiscordColor Red { get; } = new(0xED4245);
#endregion
#region Other colors
///
/// Dark red, or #7F0000.
///
public static DiscordColor DarkRed { get; } = new(0x7F0000);
///
/// Dark green, or #007F00.
///
public static DiscordColor DarkGreen { get; } = new(0x007F00);
///
/// Blue, or #0000FF.
///
public static DiscordColor Blue { get; } = new(0x0000FF);
///
/// Dark blue, or #00007F.
///
public static DiscordColor DarkBlue { get; } = new(0x00007F);
///
/// Cyan, or #00FFFF.
///
public static DiscordColor Cyan { get; } = new(0x00FFFF);
///
/// Magenta, or #FF00FF.
///
public static DiscordColor Magenta { get; } = new(0xFF00FF);
///
/// Teal, or #008080.
///
public static DiscordColor Teal { get; } = new(0x008080);
// meme
///
/// Aquamarine, or #00FFBF.
///
public static DiscordColor Aquamarine { get; } = new(0x00FFBF);
///
/// Gold, or #FFD700.
///
public static DiscordColor Gold { get; } = new(0xFFD700);
///
/// Goldenrod, or #DAA520.
///
public static DiscordColor Goldenrod { get; } = new(0xDAA520);
///
/// Azure, or #007FFF.
///
public static DiscordColor Azure { get; } = new(0x007FFF);
///
/// Rose, or #FF007F.
///
public static DiscordColor Rose { get; } = new(0xFF007F);
///
/// Spring green, or #00FF7F.
///
public static DiscordColor SpringGreen { get; } = new(0x00FF7F);
///
/// Chartreuse, or #7FFF00.
///
public static DiscordColor Chartreuse { get; } = new(0x7FFF00);
///
/// Orange, or #FFA500.
///
public static DiscordColor Orange { get; } = new(0xFFA500);
///
/// Purple, or #800080.
///
public static DiscordColor Purple { get; } = new(0x800080);
///
/// Violet, or #EE82EE.
///
public static DiscordColor Violet { get; } = new(0xEE82EE);
///
/// Brown, or #A52A2A.
///
public static DiscordColor Brown { get; } = new(0xA52A2A);
///
/// Hot pink, or #FF69B4
///
public static DiscordColor HotPink { get; } = new(0xFF69B4);
///
/// Lilac, or #C8A2C8.
///
public static DiscordColor Lilac { get; } = new(0xC8A2C8);
///
/// Cornflower blue, or #6495ED.
///
public static DiscordColor CornflowerBlue { get; } = new(0x6495ED);
///
/// Midnight blue, or #191970.
///
public static DiscordColor MidnightBlue { get; } = new(0x191970);
///
/// Wheat, or #F5DEB3.
///
public static DiscordColor Wheat { get; } = new(0xF5DEB3);
///
/// Indian red, or #CD5C5C.
///
public static DiscordColor IndianRed { get; } = new(0xCD5C5C);
///
/// Turquoise, or #30D5C8.
///
public static DiscordColor Turquoise { get; } = new(0x30D5C8);
///
/// Sap green, or #507D2A.
///
public static DiscordColor SapGreen { get; } = new(0x507D2A);
// meme, specifically bob ross
///
/// Phthalo blue, or #000F89.
///
public static DiscordColor PhthaloBlue { get; } = new(0x000F89);
// meme, specifically bob ross
///
/// Phthalo green, or #123524.
///
public static DiscordColor PhthaloGreen { get; } = new(0x123524);
///
/// Sienna, or #882D17.
///
public static DiscordColor Sienna { get; } = new(0x882D17);
#endregion
}
diff --git a/DisCatSharp/Enums/Application/ApplicationFlags.cs b/DisCatSharp/Enums/Application/ApplicationFlags.cs
index 4e615400f..eeae30b2b 100644
--- a/DisCatSharp/Enums/Application/ApplicationFlags.cs
+++ b/DisCatSharp/Enums/Application/ApplicationFlags.cs
@@ -1,133 +1,138 @@
// 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;
namespace DisCatSharp.Enums;
///
/// Represents additional details of an application.
///
[Flags]
public enum ApplicationFlags : long
{
///
/// The application is embedded and can be used by users.
/// This was introduced to avoid users using in-dev apps.
///
EmbeddedReleased = 1L << 1,
///
/// The application is a managed emoji.
///
ManagedEmoji = 1L << 2,
+ ///
+ /// Unknown, relates to in app purchase.
+ ///
+ EmbeddedIap = 1L << 3,
+
///
/// The application can create group dms.
///
- GroupDmCreate = 1L << 5,
+ GroupDmCreate = 1L << 4,
///
/// Allows the application to access the local RPC server.
///
- RpcPrivateBeta = 1L << 5,
+ RpcPrivateBeta = 1L << 6,
///
/// Allows the application to create activity assets.
///
AllowAssets = 1L<<8,
///
/// Allows the application to enable activity spectating.
///
AllowActivityActionSpectate = 1L<<9,
///
/// Allows the application to enable join requests for activities.
///
AllowActivityActionJoinRequest = 1L<<10,
///
/// The application has connected to RPC.
///
RpcHasConnected = 1L << 11,
///
/// The application can track presence data.
///
GatewayPresence = 1L << 12,
///
/// The application can track presence data (limited).
///
GatewayPresenceLimited = 1L << 13,
///
/// The application can track guild members.
///
GatewayGuildMembers = 1L << 14,
///
/// The application can track guild members (limited).
///
GatewayGuildMembersLimited = 1L << 15,
///
/// The application can track pending guild member verifications (limited).
///
VerificationPendingGuildLimit = 1L << 16,
///
/// The application is embedded.
///
Embedded = 1L << 17,
///
/// The application can track message content.
///
GatewayMessageContent = 1L << 18,
///
/// The application can track message content (limited).
///
GatewayMessageContentLimited = 1L << 19,
///
/// Related to embedded applications.
///
EmbeddedFirstParty = 1L << 20,
///
/// To be datamined.
///
UnknownFlag = 1L << 21,
///
/// The application has registered global application commands.
///
ApplicationCommandBadge = 1L << 23,
///
/// Indicates if an app is considered active. This means that it has had any global command executed in the past 30 days.
///
Active = 1L << 24
}
diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs
index 24baf4ed0..98f173e38 100644
--- a/DisCatSharp/Net/Rest/DiscordApiClient.cs
+++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs
@@ -1,5675 +1,5675 @@
// 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.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using DisCatSharp.Entities;
using DisCatSharp.Enums;
using DisCatSharp.Net.Abstractions;
using DisCatSharp.Net.Serialization;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace DisCatSharp.Net;
///
/// Represents a discord api client.
///
public sealed class DiscordApiClient
{
///
/// The audit log reason header name.
///
private const string REASON_HEADER_NAME = "X-Audit-Log-Reason";
///
/// Gets the discord client.
///
internal BaseDiscordClient Discord { get; }
///
/// Gets the rest client.
///
internal RestClient Rest { get; }
///
/// Initializes a new instance of the class.
///
/// The client.
internal DiscordApiClient(BaseDiscordClient client)
{
this.Discord = client;
this.Rest = new RestClient(client);
}
///
/// Initializes a new instance of the class.
///
/// The proxy.
/// The timeout.
/// If true, use relative rate limit.
/// The logger.
internal DiscordApiClient(IWebProxy proxy, TimeSpan timeout, bool useRelativeRateLimit, ILogger logger) // This is for meta-clients, such as the webhook client
{
this.Rest = new RestClient(proxy, timeout, useRelativeRateLimit, logger);
}
///
/// Builds the query string.
///
/// The values.
/// Whether this query will be transmitted via POST.
private static string BuildQueryString(IDictionary values, bool post = false)
{
if (values == null || values.Count == 0)
return string.Empty;
var valsCollection = values.Select(xkvp =>
$"{WebUtility.UrlEncode(xkvp.Key)}={WebUtility.UrlEncode(xkvp.Value)}");
var vals = string.Join("&", valsCollection);
return !post ? $"?{vals}" : vals;
}
///
/// Prepares the message.
///
/// The msg_raw.
/// A DiscordMessage.
private DiscordMessage PrepareMessage(JToken msgRaw)
{
var author = msgRaw["author"].ToObject();
var ret = msgRaw.ToDiscordObject();
ret.Discord = this.Discord;
this.PopulateMessage(author, ret);
var referencedMsg = msgRaw["referenced_message"];
if (ret.MessageType == MessageType.Reply && !string.IsNullOrWhiteSpace(referencedMsg?.ToString()))
{
author = referencedMsg["author"].ToObject();
ret.ReferencedMessage.Discord = this.Discord;
this.PopulateMessage(author, ret.ReferencedMessage);
}
if (ret.Channel != null)
return ret;
var channel = !ret.GuildId.HasValue
? new DiscordDmChannel
{
Id = ret.ChannelId,
Discord = this.Discord,
Type = ChannelType.Private
}
: new DiscordChannel
{
Id = ret.ChannelId,
GuildId = ret.GuildId,
Discord = this.Discord
};
ret.Channel = channel;
return ret;
}
///
/// Populates the message.
///
/// The author.
/// The message.
private void PopulateMessage(TransportUser author, DiscordMessage ret)
{
var guild = ret.Channel?.Guild;
//If this is a webhook, it shouldn't be in the user cache.
if (author.IsBot && int.Parse(author.Discriminator) == 0)
{
ret.Author = new DiscordUser(author) { Discord = this.Discord };
}
else
{
if (!this.Discord.UserCache.TryGetValue(author.Id, out var usr))
{
this.Discord.UserCache[author.Id] = usr = new DiscordUser(author) { Discord = this.Discord };
}
if (guild != null)
{
if (!guild.Members.TryGetValue(author.Id, out var mbr))
mbr = new DiscordMember(usr) { Discord = this.Discord, GuildId = guild.Id };
ret.Author = mbr;
}
else
{
ret.Author = usr;
}
}
ret.PopulateMentions();
ret.ReactionsInternal ??= new List();
foreach (var xr in ret.ReactionsInternal)
xr.Emoji.Discord = this.Discord;
}
///
/// Executes a rest request.
///
/// The client.
/// The bucket.
/// The url.
/// The method.
/// The route.
/// The headers.
/// The payload.
/// The ratelimit wait override.
internal Task DoRequestAsync(BaseDiscordClient client, RateLimitBucket bucket, Uri url, RestRequestMethod method, string route, IReadOnlyDictionary headers = null, string payload = null, double? ratelimitWaitOverride = null)
{
var req = new RestRequest(client, bucket, url, method, route, headers, payload, ratelimitWaitOverride);
if (this.Discord != null)
this.Rest.ExecuteRequestAsync(req).LogTaskFault(this.Discord.Logger, LogLevel.Error, LoggerEvents.RestError, $"Error while executing request. Url: {url.AbsoluteUri}");
else
_ = this.Rest.ExecuteRequestAsync(req);
return req.WaitForCompletionAsync();
}
///
/// Executes a multipart rest request for stickers.
///
/// The client.
/// The bucket.
/// The url.
/// The method.
/// The route.
/// The headers.
/// The file.
/// The sticker name.
/// The sticker tag.
/// The sticker description.
/// The ratelimit wait override.
private Task DoStickerMultipartAsync(BaseDiscordClient client, RateLimitBucket bucket, Uri url, RestRequestMethod method, string route, IReadOnlyDictionary headers = null,
DiscordMessageFile file = null, string name = "", string tags = "", string description = "", double? ratelimitWaitOverride = null)
{
var req = new MultipartStickerWebRequest(client, bucket, url, method, route, headers, file, name, tags, description, ratelimitWaitOverride);
if (this.Discord != null)
this.Rest.ExecuteRequestAsync(req).LogTaskFault(this.Discord.Logger, LogLevel.Error, LoggerEvents.RestError, "Error while executing request");
else
_ = this.Rest.ExecuteRequestAsync(req);
return req.WaitForCompletionAsync();
}
///
/// Executes a multipart request.
///
/// The client.
/// The bucket.
/// The url.
/// The method.
/// The route.
/// The headers.
/// The values.
/// The files.
/// The ratelimit wait override.
private Task DoMultipartAsync(BaseDiscordClient client, RateLimitBucket bucket, Uri url, RestRequestMethod method, string route, IReadOnlyDictionary headers = null, IReadOnlyDictionary values = null,
IReadOnlyCollection files = null, double? ratelimitWaitOverride = null)
{
var req = new MultipartWebRequest(client, bucket, url, method, route, headers, values, files, ratelimitWaitOverride);
if (this.Discord != null)
this.Rest.ExecuteRequestAsync(req).LogTaskFault(this.Discord.Logger, LogLevel.Error, LoggerEvents.RestError, "Error while executing request");
else
_ = this.Rest.ExecuteRequestAsync(req);
return req.WaitForCompletionAsync();
}
#region Guild
///
/// Searches the members async.
///
/// The guild_id.
/// The name.
/// The limit.
internal async Task> SearchMembersAsync(ulong guildId, string name, int? limit)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}{Endpoints.SEARCH}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var querydict = new Dictionary
{
["query"] = name,
["limit"] = limit.ToString()
};
var url = Utilities.GetApiUriFor(path, BuildQueryString(querydict), this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var json = JArray.Parse(res.Response);
var tms = json.ToObject>();
var mbrs = new List();
foreach (var xtm in tms)
{
var usr = new DiscordUser(xtm.User) { Discord = this.Discord };
this.Discord.UserCache.AddOrUpdate(xtm.User.Id, usr, (id, old) =>
{
old.Username = usr.Username;
old.Discord = usr.Discord;
old.AvatarHash = usr.AvatarHash;
return old;
});
mbrs.Add(new DiscordMember(xtm) { Discord = this.Discord, GuildId = guildId });
}
return mbrs;
}
///
/// Gets the guild ban async.
///
/// The guild_id.
/// The user_id.
internal async Task GetGuildBanAsync(ulong guildId, ulong userId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.BANS}/:user_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, user_id = userId}, out var path);
var uri = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, uri, RestRequestMethod.GET, route).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var ban = json.ToObject();
return ban;
}
///
/// Creates the guild async.
///
/// The name.
/// The region_id.
/// The iconb64.
/// The verification_level.
/// The default_message_notifications.
/// The system_channel_flags.
internal async Task CreateGuildAsync(string name, string regionId, Optional iconb64, VerificationLevel? verificationLevel,
DefaultMessageNotifications? defaultMessageNotifications, SystemChannelFlags? systemChannelFlags)
{
var pld = new RestGuildCreatePayload
{
Name = name,
RegionId = regionId,
DefaultMessageNotifications = defaultMessageNotifications,
VerificationLevel = verificationLevel,
IconBase64 = iconb64,
SystemChannelFlags = systemChannelFlags
};
var route = $"{Endpoints.GUILDS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawMembers = (JArray)json["members"];
var guild = json.ToDiscordObject();
if (this.Discord is DiscordClient dc)
await dc.OnGuildCreateEventAsync(guild, rawMembers, null).ConfigureAwait(false);
return guild;
}
///
/// Creates the guild from template async.
///
/// The template_code.
/// The name.
/// The iconb64.
internal async Task CreateGuildFromTemplateAsync(string templateCode, string name, Optional iconb64)
{
var pld = new RestGuildCreateFromTemplatePayload
{
Name = name,
IconBase64 = iconb64
};
var route = $"{Endpoints.GUILDS}{Endpoints.TEMPLATES}/:template_code";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {template_code = templateCode }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawMembers = (JArray)json["members"];
var guild = json.ToDiscordObject();
if (this.Discord is DiscordClient dc)
await dc.OnGuildCreateEventAsync(guild, rawMembers, null).ConfigureAwait(false);
return guild;
}
///
/// Deletes the guild async.
///
/// The guild_id.
internal async Task DeleteGuildAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false);
if (this.Discord is DiscordClient dc)
{
var gld = dc.GuildsInternal[guildId];
await dc.OnGuildDeleteEventAsync(gld).ConfigureAwait(false);
}
}
///
/// Modifies the guild.
///
/// The guild id.
/// The name.
/// The verification level.
/// The default message notifications.
/// The mfa level.
/// The explicit content filter.
/// The afk channel id.
/// The afk timeout.
/// The iconb64.
/// The owner id.
/// The splashb64.
/// The system channel id.
/// The system channel flags.
/// The public updates channel id.
/// The rules channel id.
/// The description.
/// The banner base64.
/// The discovery base64.
/// The preferred locale.
/// Whether the premium progress bar should be enabled.
/// The reason.
internal async Task ModifyGuildAsync(ulong guildId, Optional name, Optional verificationLevel,
Optional defaultMessageNotifications, Optional mfaLevel,
Optional explicitContentFilter, Optional afkChannelId,
Optional afkTimeout, Optional iconb64, Optional ownerId, Optional splashb64,
Optional systemChannelId, Optional systemChannelFlags,
Optional publicUpdatesChannelId, Optional rulesChannelId, Optional description,
Optional bannerb64, Optional discoverySplashb64, Optional preferredLocale, Optional premiumProgressBarEnabled, string reason)
{
var pld = new RestGuildModifyPayload
{
Name = name,
VerificationLevel = verificationLevel,
DefaultMessageNotifications = defaultMessageNotifications,
MfaLevel = mfaLevel,
ExplicitContentFilter = explicitContentFilter,
AfkChannelId = afkChannelId,
AfkTimeout = afkTimeout,
IconBase64 = iconb64,
SplashBase64 = splashb64,
BannerBase64 = bannerb64,
DiscoverySplashBase64 = discoverySplashb64,
OwnerId = ownerId,
SystemChannelId = systemChannelId,
SystemChannelFlags = systemChannelFlags,
RulesChannelId = rulesChannelId,
PublicUpdatesChannelId = publicUpdatesChannelId,
PreferredLocale = preferredLocale,
Description = description,
PremiumProgressBarEnabled = premiumProgressBarEnabled
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawMembers = (JArray)json["members"];
var guild = json.ToDiscordObject();
foreach (var r in guild.RolesInternal.Values)
r.GuildId = guild.Id;
if (this.Discord is DiscordClient dc)
await dc.OnGuildUpdateEventAsync(guild, rawMembers).ConfigureAwait(false);
return guild;
}
///
/// Modifies the guild community settings.
///
/// The guild id.
/// The guild features.
/// The rules channel id.
/// The public updates channel id.
/// The preferred locale.
/// The description.
/// The default message notifications.
/// The explicit content filter.
/// The verification level.
/// The reason.
internal async Task ModifyGuildCommunitySettingsAsync(ulong guildId, List features, Optional rulesChannelId, Optional publicUpdatesChannelId, string preferredLocale, string description, DefaultMessageNotifications defaultMessageNotifications, ExplicitContentFilter explicitContentFilter, VerificationLevel verificationLevel, string reason)
{
var pld = new RestGuildCommunityModifyPayload
{
VerificationLevel = verificationLevel,
DefaultMessageNotifications = defaultMessageNotifications,
ExplicitContentFilter = explicitContentFilter,
RulesChannelId = rulesChannelId,
PublicUpdatesChannelId = publicUpdatesChannelId,
PreferredLocale = preferredLocale,
Description = Optional.FromNullable(description),
Features = features
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawMembers = (JArray)json["members"];
var guild = json.ToDiscordObject();
foreach (var r in guild.RolesInternal.Values)
r.GuildId = guild.Id;
if (this.Discord is DiscordClient dc)
await dc.OnGuildUpdateEventAsync(guild, rawMembers).ConfigureAwait(false);
return guild;
}
///
/// Modifies the guild features.
///
/// The guild id.
/// The guild features.
/// The reason.
///
internal async Task ModifyGuildFeaturesAsync(ulong guildId, List features, string reason)
{
var pld = new RestGuildFeatureModifyPayload
{
Features = features
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawMembers = (JArray)json["members"];
var guild = json.ToDiscordObject();
foreach (var r in guild.RolesInternal.Values)
r.GuildId = guild.Id;
if (this.Discord is DiscordClient dc)
await dc.OnGuildUpdateEventAsync(guild, rawMembers).ConfigureAwait(false);
return guild;
}
///
/// Enables the guilds mfa requirement.
///
/// The guild id.
/// The reason.
internal async Task EnableGuildMfaAsync(ulong guildId, string reason)
{
var pld = new RestGuildMfaLevelModifyPayload
{
Level = MfaLevel.Enabled
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MFA}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
}
///
/// Disables the guilds mfa requirement.
///
/// The guild id.
/// The reason.
internal async Task DisableGuildMfaAsync(ulong guildId, string reason)
{
var pld = new RestGuildMfaLevelModifyPayload
{
Level = MfaLevel.Disabled
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MFA}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
}
///
/// Implements https://discord.com/developers/docs/resources/guild#get-guild-bans.
///
internal async Task> GetGuildBansAsync(ulong guildId, int? limit, ulong? before, ulong? after)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.BANS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var urlParams = new Dictionary();
if (limit != null)
urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture);
if (before != null)
urlParams["before"] = before.Value.ToString(CultureInfo.InvariantCulture);
if (after != null)
urlParams["after"] = after.Value.ToString(CultureInfo.InvariantCulture);
var url = Utilities.GetApiUriFor(path, BuildQueryString(urlParams), this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var bansRaw = JsonConvert.DeserializeObject>(res.Response).Select(xb =>
{
if (!this.Discord.TryGetCachedUserInternal(xb.RawUser.Id, out var usr))
{
usr = new DiscordUser(xb.RawUser) { Discord = this.Discord };
usr = this.Discord.UserCache.AddOrUpdate(usr.Id, usr, (id, old) =>
{
old.Username = usr.Username;
old.Discriminator = usr.Discriminator;
old.AvatarHash = usr.AvatarHash;
return old;
});
}
xb.User = usr;
return xb;
});
var bans = new ReadOnlyCollection(new List(bansRaw));
return bans;
}
///
/// Creates the guild ban async.
///
/// The guild_id.
/// The user_id.
/// The delete_message_days.
/// The reason.
internal Task CreateGuildBanAsync(ulong guildId, ulong userId, int deleteMessageDays, string reason)
{
if (deleteMessageDays < 0 || deleteMessageDays > 7)
throw new ArgumentException("Delete message days must be a number between 0 and 7.", nameof(deleteMessageDays));
var urlParams = new Dictionary
{
["delete_message_days"] = deleteMessageDays.ToString(CultureInfo.InvariantCulture)
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.BANS}/:user_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {guild_id = guildId, user_id = userId }, out var path);
var url = Utilities.GetApiUriFor(path, BuildQueryString(urlParams), this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, headers);
}
///
/// Removes the guild ban async.
///
/// The guild_id.
/// The user_id.
/// The reason.
internal Task RemoveGuildBanAsync(ulong guildId, ulong userId, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.BANS}/:user_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, user_id = userId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers);
}
///
/// Leaves the guild async.
///
/// The guild_id.
internal Task LeaveGuildAsync(ulong guildId)
{
var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.GUILDS}/:guild_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route);
}
///
/// Adds the guild member async.
///
/// The guild_id.
/// The user_id.
/// The access_token.
/// The nick.
/// The roles.
/// If true, muted.
/// If true, deafened.
internal async Task AddGuildMemberAsync(ulong guildId, ulong userId, string accessToken, string nick, IEnumerable roles, bool muted, bool deafened)
{
var pld = new RestGuildMemberAddPayload
{
AccessToken = accessToken,
Nickname = nick ?? "",
Roles = roles ?? new List(),
Deaf = deafened,
Mute = muted
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {guild_id = guildId, user_id = userId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var tm = JsonConvert.DeserializeObject(res.Response);
return new DiscordMember(tm) { Discord = this.Discord, GuildId = guildId };
}
///
/// Lists the guild members async.
///
/// The guild_id.
/// The limit.
/// The after.
internal async Task> ListGuildMembersAsync(ulong guildId, int? limit, ulong? after)
{
var urlParams = new Dictionary();
if (limit != null && limit > 0)
urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture);
if (after != null)
urlParams["after"] = after.Value.ToString(CultureInfo.InvariantCulture);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var membersRaw = JsonConvert.DeserializeObject>(res.Response);
return new ReadOnlyCollection(membersRaw);
}
///
/// Adds the guild member role async.
///
/// The guild_id.
/// The user_id.
/// The role_id.
/// The reason.
internal Task AddGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id{Endpoints.ROLES}/:role_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {guild_id = guildId, user_id = userId, role_id = roleId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, headers);
}
///
/// Removes the guild member role async.
///
/// The guild_id.
/// The user_id.
/// The role_id.
/// The reason.
internal Task RemoveGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id{Endpoints.ROLES}/:role_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, user_id = userId, role_id = roleId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers);
}
///
/// Modifies the guild channel position async.
///
/// The guild_id.
/// The pld.
/// The reason.
internal Task ModifyGuildChannelPositionAsync(ulong guildId, IEnumerable pld, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
///
/// Modifies the guild channel parent async.
///
/// The guild_id.
/// The pld.
/// The reason.
internal Task ModifyGuildChannelParentAsync(ulong guildId, IEnumerable pld, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
///
/// Detaches the guild channel parent async.
///
/// The guild_id.
/// The pld.
/// The reason.
internal Task DetachGuildChannelParentAsync(ulong guildId, IEnumerable pld, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
///
/// Modifies the guild role position async.
///
/// The guild_id.
/// The pld.
/// The reason.
internal Task ModifyGuildRolePositionAsync(ulong guildId, IEnumerable pld, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ROLES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
///
/// Gets the audit logs async.
///
/// The guild_id.
/// The limit.
/// The after.
/// The before.
/// The responsible.
/// The action_type.
internal async Task GetAuditLogsAsync(ulong guildId, int limit, ulong? after, ulong? before, ulong? responsible, int? actionType)
{
var urlParams = new Dictionary
{
["limit"] = limit.ToString(CultureInfo.InvariantCulture)
};
if (after != null)
urlParams["after"] = after?.ToString(CultureInfo.InvariantCulture);
if (before != null)
urlParams["before"] = before?.ToString(CultureInfo.InvariantCulture);
if (responsible != null)
urlParams["user_id"] = responsible?.ToString(CultureInfo.InvariantCulture);
if (actionType != null)
urlParams["action_type"] = actionType?.ToString(CultureInfo.InvariantCulture);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.AUDIT_LOGS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var auditLogDataRaw = JsonConvert.DeserializeObject(res.Response);
return auditLogDataRaw;
}
///
/// Gets the guild vanity url async.
///
/// The guild_id.
internal async Task GetGuildVanityUrlAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.VANITY_URL}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var invite = JsonConvert.DeserializeObject(res.Response);
return invite;
}
///
/// Gets the guild widget async.
///
/// The guild_id.
internal async Task GetGuildWidgetAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WIDGET_JSON}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var json = JObject.Parse(res.Response);
var rawChannels = (JArray)json["channels"];
var ret = json.ToDiscordObject();
ret.Discord = this.Discord;
ret.Guild = this.Discord.Guilds.ContainsKey(guildId) ? this.Discord.Guilds[guildId] : null;
ret.Channels = ret.Guild == null
? rawChannels.Select(r => new DiscordChannel
{
Id = (ulong)r["id"],
Name = r["name"].ToString(),
Position = (int)r["position"]
}).ToList()
: rawChannels.Select(r =>
{
var c = ret.Guild.GetChannel((ulong)r["id"]);
c.Position = (int)r["position"];
return c;
}).ToList();
return ret;
}
///
/// Gets the guild widget settings async.
///
/// The guild_id.
internal async Task GetGuildWidgetSettingsAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WIDGET}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Guild = this.Discord.Guilds[guildId];
return ret;
}
///
/// Modifies the guild widget settings async.
///
/// The guild_id.
/// If true, is enabled.
/// The channel id.
/// The reason.
internal async Task ModifyGuildWidgetSettingsAsync(ulong guildId, bool? isEnabled, ulong? channelId, string reason)
{
var pld = new RestGuildWidgetSettingsPayload
{
Enabled = isEnabled,
ChannelId = channelId
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WIDGET}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Guild = this.Discord.Guilds[guildId];
return ret;
}
///
/// Gets the guild templates async.
///
/// The guild_id.
internal async Task> GetGuildTemplatesAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.TEMPLATES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var templatesRaw = JsonConvert.DeserializeObject>(res.Response);
return new ReadOnlyCollection(new List(templatesRaw));
}
///
/// Creates the guild template async.
///
/// The guild_id.
/// The name.
/// The description.
internal async Task CreateGuildTemplateAsync(ulong guildId, string name, string description)
{
var pld = new RestGuildTemplateCreateOrModifyPayload
{
Name = name,
Description = description
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.TEMPLATES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
return ret;
}
///
/// Syncs the guild template async.
///
/// The guild_id.
/// The template_code.
internal async Task SyncGuildTemplateAsync(ulong guildId, string templateCode)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.TEMPLATES}/:template_code";
var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {guild_id = guildId, template_code = templateCode }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route).ConfigureAwait(false);
var templateRaw = JsonConvert.DeserializeObject(res.Response);
return templateRaw;
}
///
/// Modifies the guild template async.
///
/// The guild_id.
/// The template_code.
/// The name.
/// The description.
internal async Task ModifyGuildTemplateAsync(ulong guildId, string templateCode, string name, string description)
{
var pld = new RestGuildTemplateCreateOrModifyPayload
{
Name = name,
Description = description
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.TEMPLATES}/:template_code";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, template_code = templateCode }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var templateRaw = JsonConvert.DeserializeObject(res.Response);
return templateRaw;
}
///
/// Deletes the guild template async.
///
/// The guild_id.
/// The template_code.
internal async Task DeleteGuildTemplateAsync(ulong guildId, string templateCode)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.TEMPLATES}/:template_code";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, template_code = templateCode }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false);
var templateRaw = JsonConvert.DeserializeObject(res.Response);
return templateRaw;
}
///
/// Gets the guild membership screening form async.
///
/// The guild_id.
internal async Task GetGuildMembershipScreeningFormAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBER_VERIFICATION}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var screeningRaw = JsonConvert.DeserializeObject(res.Response);
return screeningRaw;
}
///
/// Modifies the guild membership screening form async.
///
/// The guild_id.
/// The enabled.
/// The fields.
/// The description.
internal async Task ModifyGuildMembershipScreeningFormAsync(ulong guildId, Optional enabled, Optional fields, Optional description)
{
var pld = new RestGuildMembershipScreeningFormModifyPayload
{
Enabled = enabled,
Description = description,
Fields = fields
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBER_VERIFICATION}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var screeningRaw = JsonConvert.DeserializeObject(res.Response);
return screeningRaw;
}
///
/// Gets the guild welcome screen async.
///
/// The guild_id.
internal async Task GetGuildWelcomeScreenAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WELCOME_SCREEN}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route);
var ret = JsonConvert.DeserializeObject(res.Response);
return ret;
}
///
/// Modifies the guild welcome screen async.
///
/// The guild_id.
/// The enabled.
/// The welcome channels.
/// The description.
internal async Task ModifyGuildWelcomeScreenAsync(ulong guildId, Optional enabled, Optional> welcomeChannels, Optional description)
{
var pld = new RestGuildWelcomeScreenModifyPayload
{
Enabled = enabled,
WelcomeChannels = welcomeChannels,
Description = description
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WELCOME_SCREEN}";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld));
var ret = JsonConvert.DeserializeObject(res.Response);
return ret;
}
///
/// Updates the current user voice state async.
///
/// The guild_id.
/// The channel id.
/// If true, suppress.
/// The request to speak timestamp.
internal async Task UpdateCurrentUserVoiceStateAsync(ulong guildId, ulong channelId, bool? suppress, DateTimeOffset? requestToSpeakTimestamp)
{
var pld = new RestGuildUpdateCurrentUserVoiceStatePayload
{
ChannelId = channelId,
Suppress = suppress,
RequestToSpeakTimestamp = requestToSpeakTimestamp
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.VOICE_STATES}/@me";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld));
}
///
/// Updates the user voice state async.
///
/// The guild_id.
/// The user_id.
/// The channel id.
/// If true, suppress.
internal async Task UpdateUserVoiceStateAsync(ulong guildId, ulong userId, ulong channelId, bool? suppress)
{
var pld = new RestGuildUpdateUserVoiceStatePayload
{
ChannelId = channelId,
Suppress = suppress
};
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.VOICE_STATES}/:user_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, user_id = userId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, payload: DiscordJson.SerializeObject(pld));
}
///
/// Gets all auto mod rules for a guild.
///
/// The guild id.
/// A collection of all auto mod rules in the guild.
internal async Task> GetAutomodRulesAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id/auto-moderation/rules";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route);
var ret = JsonConvert.DeserializeObject>(res.Response);
return ret.AsReadOnly();
}
///
/// Gets a specific auto mod rule in the guild.
///
/// The guild id for the rule.
/// The rule id.
/// The rule if one is found.
internal async Task GetAutomodRuleAsync(ulong guildId, ulong ruleId)
{
var route = $"{Endpoints.GUILDS}/:guild_id/auto-moderation/rules/:rule_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId, rule_id = ruleId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route);
var ret = JsonConvert.DeserializeObject(res.Response);
return ret;
}
///
/// Creates an auto mod rule.
///
/// The guild id of the rule.
/// The name of the rule.
/// The event type of the rule.
/// The trigger type.
/// The actions of the rule.
/// The metadata of the rule.
/// Whether this rule is enabled.
/// The exempt roles of the rule.
/// The exempt channels of the rule.
/// The reason for this addition.
/// The new auto mod rule.
internal async Task CreateAutomodRuleAsync(ulong guildId, string name, AutomodEventType eventType, AutomodTriggerType triggerType, IEnumerable actions,
AutomodTriggerMetadata triggerMetadata = null, bool enabled = false, IEnumerable exemptRoles = null, IEnumerable exemptChannels = null, string reason = null)
{
var route = $"{Endpoints.GUILDS}/:guild_id/auto-moderation/rules";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { guild_id = guildId }, out var path);
RestAutomodRuleModifyPayload pld = new()
{
Name = name,
EventType = eventType,
TriggerType = triggerType,
Actions = actions.ToArray(),
Enabled = enabled,
TriggerMetadata = triggerMetadata ?? null
};
if (exemptChannels != null)
pld.ExemptChannels = exemptChannels.ToArray();
if (exemptRoles != null)
pld.ExemptRoles = exemptRoles.ToArray();
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
if (this.Discord is DiscordClient dc)
{
await dc.OnAutomodRuleCreated(ret).ConfigureAwait(false);
}
return ret;
}
///
/// Modifies an auto mod role
///
/// The guild id.
/// The rule id.
/// The new name of the rule.
/// The new event type of the rule.
/// The new metadata of the rule.
/// The new actions of the rule.
/// Whether this rule is enabled.
/// The new exempt roles of the rule.
/// The new exempt channels of the rule.
/// The reason for this modification.
/// The updated automod rule
internal async Task ModifyAutomodRuleAsync(ulong guildId, ulong ruleId, Optional name, Optional eventType, Optional metadata, Optional> actions,
Optional enabled, Optional> exemptRoles, Optional> exemptChannels, string reason = null)
{
var pld = new RestAutomodRuleModifyPayload
{
Name = name,
EventType = eventType,
TriggerMetadata = metadata,
Enabled = enabled
};
if (actions.HasValue)
pld.Actions = actions.Value?.ToArray();
if (exemptChannels.HasValue)
pld.ExemptChannels = exemptChannels.Value?.ToArray();
if (exemptRoles.HasValue)
pld.ExemptRoles = exemptRoles.Value?.ToArray();
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id/auto-moderation/rules/:rule_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { guild_id = guildId, rule_id = ruleId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, payload: DiscordJson.SerializeObject(pld));
var ret = JsonConvert.DeserializeObject(res.Response);
if (this.Discord is DiscordClient dc)
{
await dc.OnAutomodRuleUpdated(ret).ConfigureAwait(false);
}
return ret;
}
///
/// Deletes an auto mod rule.
///
/// The guild id of the rule.
/// The rule id.
/// The reason for this deletion.
/// The deleted auto mod rule.
internal async Task DeleteAutomodRuleAsync(ulong guildId, ulong ruleId, string reason = null)
{
var route = $"{Endpoints.GUILDS}/:guild_id/auto-moderation/rules/:rule_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new { guild_id = guildId, rule_id = ruleId }, out var path);
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
if (this.Discord is DiscordClient dc)
{
await dc.OnAutomodRuleDeleted(ret).ConfigureAwait(false);
}
return ret;
}
#endregion
#region Guild Scheduled Events
///
/// Creates a scheduled event.
///
internal async Task CreateGuildScheduledEventAsync(ulong guildId, ulong? channelId, DiscordScheduledEventEntityMetadata metadata, string name, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime, string description, ScheduledEventEntityType type, Optional coverb64, string reason = null)
{
var pld = new RestGuildScheduledEventCreatePayload
{
ChannelId = channelId,
EntityMetadata = metadata,
Name = name,
ScheduledStartTime = scheduledStartTime,
ScheduledEndTime = scheduledEndTime,
Description = description,
EntityType = type,
CoverBase64 = coverb64
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers[REASON_HEADER_NAME] = reason;
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld));
var scheduledEvent = JsonConvert.DeserializeObject(res.Response);
var guild = this.Discord.Guilds[guildId];
scheduledEvent.Discord = this.Discord;
if (scheduledEvent.Creator != null)
scheduledEvent.Creator.Discord = this.Discord;
if (this.Discord is DiscordClient dc)
await dc.OnGuildScheduledEventCreateEventAsync(scheduledEvent, guild);
return scheduledEvent;
}
///
/// Modifies a scheduled event.
///
internal async Task ModifyGuildScheduledEventAsync(ulong guildId, ulong scheduledEventId, Optional channelId, Optional metadata, Optional name, Optional scheduledStartTime, Optional scheduledEndTime, Optional description, Optional type, Optional status, Optional coverb64, string reason = null)
{
var pld = new RestGuildScheduledEventModifyPayload
{
ChannelId = channelId,
EntityMetadata = metadata,
Name = name,
ScheduledStartTime = scheduledStartTime,
ScheduledEndTime = scheduledEndTime,
Description = description,
EntityType = type,
Status = status,
CoverBase64 = coverb64
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers[REASON_HEADER_NAME] = reason;
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}/:scheduled_event_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, scheduled_event_id = scheduledEventId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
var scheduledEvent = JsonConvert.DeserializeObject(res.Response);
var guild = this.Discord.Guilds[guildId];
scheduledEvent.Discord = this.Discord;
if (scheduledEvent.Creator != null)
{
scheduledEvent.Creator.Discord = this.Discord;
this.Discord.UserCache.AddOrUpdate(scheduledEvent.Creator.Id, scheduledEvent.Creator, (id, old) =>
{
old.Username = scheduledEvent.Creator.Username;
old.Discriminator = scheduledEvent.Creator.Discriminator;
old.AvatarHash = scheduledEvent.Creator.AvatarHash;
old.Flags = scheduledEvent.Creator.Flags;
return old;
});
}
if (this.Discord is DiscordClient dc)
await dc.OnGuildScheduledEventUpdateEventAsync(scheduledEvent, guild);
return scheduledEvent;
}
///
/// Modifies a scheduled event.
///
internal async Task ModifyGuildScheduledEventStatusAsync(ulong guildId, ulong scheduledEventId, ScheduledEventStatus status, string reason = null)
{
var pld = new RestGuildScheduledEventModifyPayload
{
Status = status
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers[REASON_HEADER_NAME] = reason;
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}/:scheduled_event_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, scheduled_event_id = scheduledEventId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
var scheduledEvent = JsonConvert.DeserializeObject(res.Response);
var guild = this.Discord.Guilds[guildId];
scheduledEvent.Discord = this.Discord;
if (scheduledEvent.Creator != null)
{
scheduledEvent.Creator.Discord = this.Discord;
this.Discord.UserCache.AddOrUpdate(scheduledEvent.Creator.Id, scheduledEvent.Creator, (id, old) =>
{
old.Username = scheduledEvent.Creator.Username;
old.Discriminator = scheduledEvent.Creator.Discriminator;
old.AvatarHash = scheduledEvent.Creator.AvatarHash;
old.Flags = scheduledEvent.Creator.Flags;
return old;
});
}
if (this.Discord is DiscordClient dc)
await dc.OnGuildScheduledEventUpdateEventAsync(scheduledEvent, guild);
return scheduledEvent;
}
///
/// Gets a scheduled event.
///
/// The guild_id.
/// The event id.
/// Whether to include user count.
internal async Task GetGuildScheduledEventAsync(ulong guildId, ulong scheduledEventId, bool? withUserCount)
{
var urlParams = new Dictionary();
if (withUserCount.HasValue)
urlParams["with_user_count"] = withUserCount?.ToString();
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}/:scheduled_event_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, scheduled_event_id = scheduledEventId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route);
var scheduledEvent = JsonConvert.DeserializeObject(res.Response);
var guild = this.Discord.Guilds[guildId];
scheduledEvent.Discord = this.Discord;
if (scheduledEvent.Creator != null)
{
scheduledEvent.Creator.Discord = this.Discord;
this.Discord.UserCache.AddOrUpdate(scheduledEvent.Creator.Id, scheduledEvent.Creator, (id, old) =>
{
old.Username = scheduledEvent.Creator.Username;
old.Discriminator = scheduledEvent.Creator.Discriminator;
old.AvatarHash = scheduledEvent.Creator.AvatarHash;
old.Flags = scheduledEvent.Creator.Flags;
return old;
});
}
return scheduledEvent;
}
///
/// Gets the guilds scheduled events.
///
/// The guild_id.
/// Whether to include the count of users subscribed to the scheduled event.
internal async Task> ListGuildScheduledEventsAsync(ulong guildId, bool? withUserCount)
{
var urlParams = new Dictionary();
if (withUserCount.HasValue)
urlParams["with_user_count"] = withUserCount?.ToString();
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route);
var events = new Dictionary();
var eventsRaw = JsonConvert.DeserializeObject>(res.Response);
var guild = this.Discord.Guilds[guildId];
foreach (var ev in eventsRaw)
{
ev.Discord = this.Discord;
if (ev.Creator != null)
{
ev.Creator.Discord = this.Discord;
this.Discord.UserCache.AddOrUpdate(ev.Creator.Id, ev.Creator, (id, old) =>
{
old.Username = ev.Creator.Username;
old.Discriminator = ev.Creator.Discriminator;
old.AvatarHash = ev.Creator.AvatarHash;
old.Flags = ev.Creator.Flags;
return old;
});
}
events.Add(ev.Id, ev);
}
return new ReadOnlyDictionary(new Dictionary(events));
}
///
/// Deletes a guild scheduled event.
///
/// The guild_id.
/// The scheduled event id.
/// The reason.
internal Task DeleteGuildScheduledEventAsync(ulong guildId, ulong scheduledEventId, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}/:scheduled_event_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, scheduled_event_id = scheduledEventId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers);
}
///
/// Gets the users who RSVP'd to a scheduled event.
/// Optional with member objects.
/// This endpoint is paginated.
///
/// The guild_id.
/// The scheduled event id.
/// The limit how many users to receive from the event.
/// Get results before the given id.
/// Get results after the given id.
/// Whether to include guild member data. attaches guild_member property to the user object.
internal async Task> GetGuildScheduledEventRspvUsersAsync(ulong guildId, ulong scheduledEventId, int? limit, ulong? before, ulong? after, bool? withMember)
{
var urlParams = new Dictionary();
if (limit != null && limit > 0)
urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture);
if (before != null)
urlParams["before"] = before.Value.ToString(CultureInfo.InvariantCulture);
if (after != null)
urlParams["after"] = after.Value.ToString(CultureInfo.InvariantCulture);
if (withMember != null)
urlParams["with_member"] = withMember.Value.ToString(CultureInfo.InvariantCulture);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.SCHEDULED_EVENTS}/:scheduled_event_id{Endpoints.USERS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, scheduled_event_id = scheduledEventId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var rspvUsers = JsonConvert.DeserializeObject>(res.Response);
Dictionary rspv = new();
foreach (var rspvUser in rspvUsers)
{
rspvUser.Discord = this.Discord;
rspvUser.GuildId = guildId;
rspvUser.User.Discord = this.Discord;
rspvUser.User = this.Discord.UserCache.AddOrUpdate(rspvUser.User.Id, rspvUser.User, (id, old) =>
{
old.Username = rspvUser.User.Username;
old.Discriminator = rspvUser.User.Discriminator;
old.AvatarHash = rspvUser.User.AvatarHash;
old.BannerHash = rspvUser.User.BannerHash;
old.BannerColorInternal = rspvUser.User.BannerColorInternal;
return old;
});
/*if (with_member.HasValue && with_member.Value && rspv_user.Member != null)
{
rspv_user.Member.Discord = this.Discord;
}*/
rspv.Add(rspvUser.User.Id, rspvUser);
}
return new ReadOnlyDictionary(new Dictionary(rspv));
}
#endregion
#region Channel
///
/// Creates a guild channel.
///
/// The guild_id.
/// The name.
/// The type.
/// The parent.
/// The topic.
/// The bitrate.
/// The user_limit.
/// The overwrites.
/// If true, nsfw.
/// The per user rate limit.
/// The quality mode.
/// The default auto archive duration.
/// The reason.
internal async Task CreateGuildChannelAsync(ulong guildId, string name, ChannelType type, ulong? parent, Optional topic, int? bitrate, int? userLimit, IEnumerable overwrites, bool? nsfw, Optional perUserRateLimit, VideoQualityMode? qualityMode, ThreadAutoArchiveDuration? defaultAutoArchiveDuration, Optional flags, string reason)
{
var restOverwrites = new List();
if (overwrites != null)
foreach (var ow in overwrites)
restOverwrites.Add(ow.Build());
var pld = new RestChannelCreatePayload
{
Name = name,
Type = type,
Parent = parent,
Topic = topic,
Bitrate = bitrate,
UserLimit = userLimit,
PermissionOverwrites = restOverwrites,
Nsfw = nsfw,
PerUserRateLimit = perUserRateLimit,
QualityMode = qualityMode,
DefaultAutoArchiveDuration = defaultAutoArchiveDuration,
Flags = flags
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Initialize(this.Discord);
return ret;
}
///
/// Creates a guild forum channel.
///
/// The guild_id.
/// The name.
/// The parent.
/// The topic.
/// The template.
/// The default reaction emoji.
/// The overwrites.
/// If true, nsfw.
/// The per user rate limit.
/// The per user post create rate limit.
/// The default auto archive duration.
/// The reason.
internal async Task CreateForumChannelAsync(ulong guildId, string name, ulong? parent,
Optional topic, Optional template,
bool? nsfw, Optional defaultReactionEmoji,
Optional perUserRateLimit, Optional postCreateUserRateLimit, Optional defaultSortOrder,
ThreadAutoArchiveDuration? defaultAutoArchiveDuration, IEnumerable permissionOverwrites, Optional flags, string reason)
{
List restoverwrites = null;
if (permissionOverwrites != null)
{
restoverwrites = new List();
foreach (var ow in permissionOverwrites)
restoverwrites.Add(ow.Build());
}
var pld = new RestChannelCreatePayload
{
Name = name,
Topic = topic,
//Template = template,
Nsfw = nsfw,
Parent = parent,
PerUserRateLimit = perUserRateLimit,
PostCreateUserRateLimit = postCreateUserRateLimit,
DefaultAutoArchiveDuration = defaultAutoArchiveDuration,
DefaultReactionEmoji = defaultReactionEmoji,
PermissionOverwrites = restoverwrites,
DefaultSortOrder = defaultSortOrder,
Flags = flags,
Type = ChannelType.Forum
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Initialize(this.Discord);
return ret;
}
///
/// Modifies the channel async.
///
/// The channel_id.
/// The name.
/// The position.
/// The topic.
/// If true, nsfw.
/// The parent.
/// The bitrate.
/// The user_limit.
/// The per user rate limit.
/// The rtc region.
/// The quality mode.
/// The default auto archive duration.
/// The type.
/// The permission overwrites.
/// The reason.
internal Task ModifyChannelAsync(ulong channelId, string name, int? position, Optional topic, bool? nsfw, Optional parent, int? bitrate, int? userLimit, Optional perUserRateLimit, Optional rtcRegion, VideoQualityMode? qualityMode, ThreadAutoArchiveDuration? autoArchiveDuration, Optional type, IEnumerable permissionOverwrites, Optional flags, string reason)
{
List restoverwrites = null;
if (permissionOverwrites != null)
{
restoverwrites = new List();
foreach (var ow in permissionOverwrites)
restoverwrites.Add(ow.Build());
}
var pld = new RestChannelModifyPayload
{
Name = name,
Position = position,
Topic = topic,
Nsfw = nsfw,
Parent = parent,
Bitrate = bitrate,
UserLimit = userLimit,
PerUserRateLimit = perUserRateLimit,
RtcRegion = rtcRegion,
QualityMode = qualityMode,
DefaultAutoArchiveDuration = autoArchiveDuration,
Type = type,
Flags = flags,
PermissionOverwrites = restoverwrites
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.CHANNELS}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
internal async Task ModifyForumChannelAsync(ulong channelId, string name, int? position,
Optional topic, Optional template, bool? nsfw,
Optional parent, Optional?> availableTags, Optional defaultReactionEmoji,
Optional perUserRateLimit, Optional postCreateUserRateLimit, Optional defaultSortOrder,
Optional defaultAutoArchiveDuration, IEnumerable permissionOverwrites, Optional flags, string reason)
{
List restoverwrites = null;
if (permissionOverwrites != null)
{
restoverwrites = new List();
foreach (var ow in permissionOverwrites)
restoverwrites.Add(ow.Build());
}
var pld = new RestChannelModifyPayload
{
Name = name,
Position = position,
Topic = topic,
//Template = template,
Nsfw = nsfw,
Parent = parent,
PerUserRateLimit = perUserRateLimit,
PostCreateUserRateLimit = postCreateUserRateLimit,
DefaultAutoArchiveDuration = defaultAutoArchiveDuration,
DefaultReactionEmoji = defaultReactionEmoji,
PermissionOverwrites = restoverwrites,
DefaultSortOrder = defaultSortOrder,
Flags = flags,
AvailableTags = availableTags
};
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.CHANNELS}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Initialize(this.Discord);
return ret;
}
///
/// Gets the channel async.
///
/// The channel_id.
internal async Task GetChannelAsync(ulong channelId)
{
var route = $"{Endpoints.CHANNELS}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var ret = JsonConvert.DeserializeObject(res.Response);
ret.Initialize(this.Discord);
return ret;
}
///
/// Deletes the channel async.
///
/// The channel_id.
/// The reason.
internal Task DeleteChannelAsync(ulong channelId, string reason)
{
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var route = $"{Endpoints.CHANNELS}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers);
}
///
/// Gets the message async.
///
/// The channel_id.
/// The message_id.
internal async Task GetMessageAsync(ulong channelId, ulong messageId)
{
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId, message_id = messageId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var ret = this.PrepareMessage(JObject.Parse(res.Response));
return ret;
}
///
/// Creates the message async.
///
/// The channel_id.
/// The content.
/// The embeds.
/// The sticker.
/// The reply message id.
/// If true, mention reply.
/// If true, fail on invalid reply.
/// The components.
internal async Task CreateMessageAsync(ulong channelId, string content, IEnumerable embeds, DiscordSticker sticker, ulong? replyMessageId, bool mentionReply, bool failOnInvalidReply, ReadOnlyCollection? components = null)
{
if (content != null && content.Length > 2000)
throw new ArgumentException("Message content length cannot exceed 2000 characters.");
if (!embeds?.Any() ?? true)
{
if (content == null && sticker == null && components == null)
throw new ArgumentException("You must specify message content, a sticker, components or an embed.");
if (content.Length == 0)
throw new ArgumentException("Message content must not be empty.");
}
if (embeds != null)
foreach (var embed in embeds)
if (embed.Timestamp != null)
embed.Timestamp = embed.Timestamp.Value.ToUniversalTime();
var pld = new RestChannelMessageCreatePayload
{
HasContent = content != null,
Content = content,
StickersIds = sticker is null ? Array.Empty() : new[] {sticker.Id},
IsTts = false,
HasEmbed = embeds?.Any() ?? false,
Embeds = embeds,
Components = components
};
if (replyMessageId != null)
pld.MessageReference = new InternalDiscordMessageReference { MessageId = replyMessageId, FailIfNotExists = failOnInvalidReply };
if (replyMessageId != null)
pld.Mentions = new DiscordMentions(Mentions.All, true, mentionReply);
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = this.PrepareMessage(JObject.Parse(res.Response));
return ret;
}
///
/// Creates the message async.
///
/// The channel_id.
/// The builder.
internal async Task CreateMessageAsync(ulong channelId, DiscordMessageBuilder builder)
{
builder.Validate();
if (builder.Embeds != null)
foreach (var embed in builder.Embeds)
if (embed?.Timestamp != null)
embed.Timestamp = embed.Timestamp.Value.ToUniversalTime();
var pld = new RestChannelMessageCreatePayload
{
HasContent = builder.Content != null,
Content = builder.Content,
StickersIds = builder.Sticker is null ? Array.Empty() : new[] {builder.Sticker.Id},
IsTts = builder.IsTts,
HasEmbed = builder.Embeds != null,
Embeds = builder.Embeds,
Components = builder.Components
};
if (builder.ReplyId != null)
pld.MessageReference = new InternalDiscordMessageReference { MessageId = builder.ReplyId, FailIfNotExists = builder.FailOnInvalidReply };
pld.Mentions = new DiscordMentions(builder.Mentions ?? Mentions.All, builder.Mentions?.Any() ?? false, builder.MentionOnReply);
if (builder.Files.Count == 0)
{
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var ret = this.PrepareMessage(JObject.Parse(res.Response));
return ret;
}
else
{
ulong fileId = 0;
List attachments = new(builder.Files.Count);
foreach (var file in builder.Files)
{
DiscordAttachment att = new()
{
Id = fileId,
Discord = this.Discord,
Description = file.Description,
FileName = file.FileName
};
attachments.Add(att);
fileId++;
}
pld.Attachments = attachments;
var values = new Dictionary
{
["payload_json"] = DiscordJson.SerializeObject(pld)
};
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoMultipartAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, values: values, files: builder.Files).ConfigureAwait(false);
var ret = this.PrepareMessage(JObject.Parse(res.Response));
foreach (var file in builder.FilesInternal.Where(x => x.ResetPositionTo.HasValue))
{
file.Stream.Position = file.ResetPositionTo.Value;
}
return ret;
}
}
///
/// Gets the guild channels async.
///
/// The guild_id.
internal async Task> GetGuildChannelsAsync(ulong guildId)
{
var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.CHANNELS}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var channelsRaw = JsonConvert.DeserializeObject>(res.Response).Select(xc => { xc.Discord = this.Discord; return xc; });
foreach (var ret in channelsRaw)
ret.Initialize(this.Discord);
return new ReadOnlyCollection(new List(channelsRaw));
}
///
/// Creates the stage instance async.
///
/// The channel_id.
/// The topic.
/// Whether everyone should be notified about the stage.
/// The privacy_level.
/// The reason.
internal async Task CreateStageInstanceAsync(ulong channelId, string topic, bool sendStartNotification, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, string reason = null)
{
var pld = new RestStageInstanceCreatePayload
{
ChannelId = channelId,
Topic = topic,
PrivacyLevel = privacyLevel,
SendStartNotification = sendStartNotification
};
var route = $"{Endpoints.STAGE_INSTANCES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path);
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false);
var stageInstance = JsonConvert.DeserializeObject(res.Response);
return stageInstance;
}
///
/// Gets the stage instance async.
///
/// The channel_id.
internal async Task GetStageInstanceAsync(ulong channelId)
{
var route = $"{Endpoints.STAGE_INSTANCES}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var stageInstance = JsonConvert.DeserializeObject(res.Response);
return stageInstance;
}
///
/// Modifies the stage instance async.
///
/// The channel_id.
/// The topic.
/// The privacy_level.
/// The reason.
internal Task ModifyStageInstanceAsync(ulong channelId, Optional topic, Optional privacyLevel, string reason)
{
var pld = new RestStageInstanceModifyPayload
{
Topic = topic,
PrivacyLevel = privacyLevel
};
var route = $"{Endpoints.STAGE_INSTANCES}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {channel_id = channelId }, out var path);
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld));
}
///
/// Deletes the stage instance async.
///
/// The channel_id.
/// The reason.
internal Task DeleteStageInstanceAsync(ulong channelId, string reason)
{
var route = $"{Endpoints.STAGE_INSTANCES}/:channel_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId }, out var path);
var headers = Utilities.GetBaseHeaders();
if (!string.IsNullOrWhiteSpace(reason))
headers.Add(REASON_HEADER_NAME, reason);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers);
}
///
/// Gets the channel messages async.
///
/// The channel id.
/// The limit.
/// The before.
/// The after.
/// The around.
internal async Task> GetChannelMessagesAsync(ulong channelId, int limit, ulong? before, ulong? after, ulong? around)
{
var urlParams = new Dictionary();
if (around != null)
urlParams["around"] = around?.ToString(CultureInfo.InvariantCulture);
if (before != null)
urlParams["before"] = before?.ToString(CultureInfo.InvariantCulture);
if (after != null)
urlParams["after"] = after?.ToString(CultureInfo.InvariantCulture);
if (limit > 0)
urlParams["limit"] = limit.ToString(CultureInfo.InvariantCulture);
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path);
var url = Utilities.GetApiUriFor(path, urlParams.Any() ? BuildQueryString(urlParams) : "", this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var msgsRaw = JArray.Parse(res.Response);
var msgs = new List();
foreach (var xj in msgsRaw)
msgs.Add(this.PrepareMessage(xj));
return new ReadOnlyCollection(new List(msgs));
}
///
/// Gets the channel message async.
///
/// The channel_id.
/// The message_id.
internal async Task GetChannelMessageAsync(ulong channelId, ulong messageId)
{
var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id";
var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId, message_id = messageId }, out var path);
var url = Utilities.GetApiUriFor(path, this.Discord.Configuration);
var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false);
var ret = this.PrepareMessage(JObject.Parse(res.Response));
return ret;
}
///
/// Edits the message async.
///
/// The channel_id.
/// The message_id.
/// The content.
/// The embeds.
/// The mentions.
/// The components.
/// The suppress_embed.
/// The files.
/// The attachments to keep.
internal async Task EditMessageAsync(ulong channelId, ulong messageId, Optional content, Optional> embeds, Optional> mentions, IReadOnlyList components, Optional suppressEmbed, IReadOnlyCollection