diff --git a/.nuget/NuGet.config b/.nuget/NuGet.config index 4a4e2f52b4..f672dcab53 100644 --- a/.nuget/NuGet.config +++ b/.nuget/NuGet.config @@ -1,11 +1,12 @@ + - - - - - - - - + + + + + + + + diff --git a/Directory.Build.props b/Directory.Build.props index 63fb1b5f0e..f38df2a939 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,10 +1,11 @@ + - - - + + + - true + true diff --git a/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs b/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs index 8b36f5e5a3..750b2af07a 100644 --- a/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs +++ b/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs @@ -88,7 +88,8 @@ public sealed class ApplicationCommandsExtension : BaseExtension public IReadOnlyList>> RegisteredCommands => s_registeredCommands.Select(guild => new KeyValuePair>(guild.Key, guild.Value - .Select(parent => new RegisteredDiscordApplicationCommand(parent)).ToList())).ToList(); + .Select(parent => new RegisteredDiscordApplicationCommand(parent)).ToList())).ToList(); + private static List>> s_registeredCommands = new(); /// @@ -96,6 +97,7 @@ public sealed class ApplicationCommandsExtension : BaseExtension /// public IReadOnlyList GlobalCommands => GlobalCommandsInternal; + internal static List GlobalCommandsInternal = new(); /// @@ -103,6 +105,7 @@ public IReadOnlyList GlobalCommands /// public IReadOnlyDictionary> GuildCommands => GuildCommandsInternal; + internal static Dictionary> GuildCommandsInternal = new(); /// @@ -150,7 +153,6 @@ internal static LogLevel ApplicationCommandsLogLevel /// internal bool StartupFinished { get; set; } = false; - /// /// Gets the service provider this module was configured with. /// @@ -168,7 +170,7 @@ public IServiceProvider Services /// The configuration. internal ApplicationCommandsExtension(ApplicationCommandsConfiguration configuration = null) { - configuration ??= new ApplicationCommandsConfiguration(); + configuration ??= new(); Configuration = configuration; DebugEnabled = configuration?.DebugStartup ?? false; CheckAllGuilds = configuration?.CheckAllGuilds ?? false; @@ -189,14 +191,14 @@ protected internal override void Setup(DiscordClient client) this.Client = client; Logger = client.Logger; - this._slashError = new AsyncEvent("SLASHCOMMAND_ERRORED", TimeSpan.Zero, null); - this._slashExecuted = new AsyncEvent("SLASHCOMMAND_EXECUTED", TimeSpan.Zero, null); - this._contextMenuErrored = new AsyncEvent("CONTEXTMENU_ERRORED", TimeSpan.Zero, null); - this._contextMenuExecuted = new AsyncEvent("CONTEXTMENU_EXECUTED", TimeSpan.Zero, null); - this._applicationCommandsModuleReady = new AsyncEvent("APPLICATION_COMMANDS_MODULE_READY", TimeSpan.Zero, null); - this._applicationCommandsModuleStartupFinished = new AsyncEvent("APPLICATION_COMMANDS_MODULE_STARTUP_FINISHED", TimeSpan.Zero, null); - this._globalApplicationCommandsRegistered = new AsyncEvent("GLOBAL_COMMANDS_REGISTERED", TimeSpan.Zero, null); - this._guildApplicationCommandsRegistered = new AsyncEvent("GUILD_COMMANDS_REGISTERED", TimeSpan.Zero, null); + this._slashError = new("SLASHCOMMAND_ERRORED", TimeSpan.Zero, null); + this._slashExecuted = new("SLASHCOMMAND_EXECUTED", TimeSpan.Zero, null); + this._contextMenuErrored = new("CONTEXTMENU_ERRORED", TimeSpan.Zero, null); + this._contextMenuExecuted = new("CONTEXTMENU_EXECUTED", TimeSpan.Zero, null); + this._applicationCommandsModuleReady = new("APPLICATION_COMMANDS_MODULE_READY", TimeSpan.Zero, null); + this._applicationCommandsModuleStartupFinished = new("APPLICATION_COMMANDS_MODULE_STARTUP_FINISHED", TimeSpan.Zero, null); + this._globalApplicationCommandsRegistered = new("GLOBAL_COMMANDS_REGISTERED", TimeSpan.Zero, null); + this._guildApplicationCommandsRegistered = new("GUILD_COMMANDS_REGISTERED", TimeSpan.Zero, null); this.Client.GuildDownloadCompleted += (c, e) => { @@ -233,6 +235,7 @@ private void FinishedRegistration() this.Client.InteractionCreated += this.InteractionHandler; this.Client.ContextMenuInteractionCreated += this.ContextMenuHandler; } + /// /// Cleans the module for a new start of the bot. /// DO NOT USE IF YOU DON'T KNOW WHAT IT DOES. @@ -309,7 +312,7 @@ public void RegisterGlobalCommands(Assembly assembly) /// The guild id to register it on. /// A callback to setup translations with. public void RegisterGuildCommands(ulong guildId, Action translationSetup = null) where T : ApplicationCommandsModule - => this._updateList.Add(new KeyValuePair(guildId, new ApplicationCommandsModuleConfiguration(typeof(T), translationSetup))); + => this._updateList.Add(new(guildId, new(typeof(T), translationSetup))); /// /// Registers a command class with optional translation setup for a guild. @@ -321,7 +324,8 @@ public void RegisterGuildCommands(Type type, ulong guildId, Action(guildId, new ApplicationCommandsModuleConfiguration(type, translationSetup))); + + this._updateList.Add(new(guildId, new(type, translationSetup))); } /// @@ -330,7 +334,7 @@ public void RegisterGuildCommands(Type type, ulong guildId, ActionThe command class to register. /// A callback to setup translations with. public void RegisterGlobalCommands(Action translationSetup = null) where T : ApplicationCommandsModule - => this._updateList.Add(new KeyValuePair(null, new ApplicationCommandsModuleConfiguration(typeof(T), translationSetup))); + => this._updateList.Add(new(null, new(typeof(T), translationSetup))); /// /// Registers a command class with optional translation setup globally. @@ -341,7 +345,8 @@ public void RegisterGlobalCommands(Type type, Action(null, new ApplicationCommandsModuleConfiguration(type, translationSetup))); + + this._updateList.Add(new(null, new(type, translationSetup))); } /// @@ -352,6 +357,7 @@ public event AsyncEventHandler this._applicationCommandsModuleReady.Register(value); remove => this._applicationCommandsModuleReady.Unregister(value); } + private AsyncEvent _applicationCommandsModuleReady; /// @@ -362,8 +368,8 @@ public event AsyncEventHandler this._applicationCommandsModuleStartupFinished.Register(value); remove => this._applicationCommandsModuleStartupFinished.Unregister(value); } - private AsyncEvent _applicationCommandsModuleStartupFinished; + private AsyncEvent _applicationCommandsModuleStartupFinished; /// /// Fired when guild commands are registered on a guild. @@ -373,6 +379,7 @@ public event AsyncEventHandler this._guildApplicationCommandsRegistered.Register(value); remove => this._guildApplicationCommandsRegistered.Unregister(value); } + private AsyncEvent _guildApplicationCommandsRegistered; /// @@ -383,6 +390,7 @@ public event AsyncEventHandler this._globalApplicationCommandsRegistered.Register(value); remove => this._globalApplicationCommandsRegistered.Unregister(value); } + private AsyncEvent _globalApplicationCommandsRegistered; /// @@ -446,15 +454,16 @@ internal async Task UpdateAsync() //Default should be to add the help and slash commands can be added without setting any configuration //so this should still add the default help - if (Configuration is null || (Configuration is not null && Configuration.EnableDefaultHelp)) + if (Configuration is null || Configuration is not null && Configuration.EnableDefaultHelp) { - updateList.Add(new KeyValuePair - (null, new ApplicationCommandsModuleConfiguration(typeof(DefaultHelpModule)))); + updateList.Add(new(null, new(typeof(DefaultHelpModule)))); commandsPending = updateList.Select(x => x.Key).Distinct().ToList(); - } else { - try { - updateList.Remove(new KeyValuePair - (null, new ApplicationCommandsModuleConfiguration(typeof(DefaultHelpModule)))); + } + else + { + try + { + updateList.Remove(new(null, new(typeof(DefaultHelpModule)))); } catch { } @@ -473,12 +482,13 @@ internal async Task UpdateAsync() this.Client.Logger.Log(ApplicationCommandsLogLevel, "Found guild {guild} in shard {shard}!", key.Value, this.Client.ShardId); this.Client.Logger.Log(ApplicationCommandsLogLevel, "Registering"); } + await this.RegisterCommands(updateList.Where(x => x.Key == key).Select(x => x.Value).ToList(), key).ConfigureAwait(false); } this._missingScopeGuildIds = new(failedGuilds); - await this._applicationCommandsModuleReady.InvokeAsync(this, new ApplicationCommandsModuleReadyEventArgs(Configuration?.ServiceProvider) + await this._applicationCommandsModuleReady.InvokeAsync(this, new(Configuration?.ServiceProvider) { GuildsWithoutScope = failedGuilds }).ConfigureAwait(false); @@ -519,9 +529,7 @@ private async Task RegisterCommands(List //Add module to classes list if it's a group var extremeNestedGroup = false; if (module.GetCustomAttribute() != null) - { classes.Add(module); - } else if (module.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Any(x => x.IsDefined(typeof(SlashCommandGroupAttribute)))) { //Otherwise add the extreme nested groups @@ -531,19 +539,15 @@ private async Task RegisterCommands(List extremeNestedGroup = true; } else - { //Otherwise add the nested groups classes = module.DeclaredNestedTypes.Where(x => x.GetCustomAttribute() != null).ToList(); - } if (module.GetCustomAttribute() != null || extremeNestedGroup) { List groupTranslations = null; if (!string.IsNullOrEmpty(ctx.GroupTranslations)) - { groupTranslations = JsonConvert.DeserializeObject>(ctx.GroupTranslations); - } var slashGroupsTuple = await NestedCommandWorker.ParseSlashGroupsAsync(type, classes, guildId, groupTranslations).ConfigureAwait(false); @@ -555,7 +559,6 @@ private async Task RegisterCommands(List var cgwsgs = new List(); var cgs2 = new List(); foreach (var cmd in slashGroupsTuple.applicationCommands) - { if (cmd.Type == ApplicationCommandType.ChatInput) { var cgs = new List(); @@ -563,28 +566,24 @@ private async Task RegisterCommands(List { var cs = new List(); foreach (var sc in scg.Options) - { if (sc.Options == null || !sc.Options.Any()) - cs.Add(new Command(sc.Name, sc.Description, null, null)); + cs.Add(new(sc.Name, sc.Description, null, null)); else - cs.Add(new Command(sc.Name, sc.Description, sc.Options.ToList(), null)); - } - cgs.Add(new CommandGroup(scg.Name, scg.Description, cs, null)); + cs.Add(new(sc.Name, sc.Description, sc.Options.ToList(), null)); + cgs.Add(new(scg.Name, scg.Description, cs, null)); } - cgwsgs.Add(new CommandGroupWithSubGroups(cmd.Name, cmd.Description, cgs, ApplicationCommandType.ChatInput)); + + cgwsgs.Add(new(cmd.Name, cmd.Description, cgs, ApplicationCommandType.ChatInput)); var cs2 = new List(); foreach (var sc2 in cmd.Options.Where(x => x.Type == ApplicationCommandOptionType.SubCommand)) - { if (sc2.Options == null || !sc2.Options.Any()) - cs2.Add(new Command(sc2.Name, sc2.Description, null, null)); + cs2.Add(new(sc2.Name, sc2.Description, null, null)); else - cs2.Add(new Command(sc2.Name, sc2.Description, sc2.Options.ToList(), null)); - } - cgs2.Add(new CommandGroup(cmd.Name, cmd.Description, cs2, ApplicationCommandType.ChatInput)); - + cs2.Add(new(sc2.Name, sc2.Description, sc2.Options.ToList(), null)); + cgs2.Add(new(cmd.Name, cmd.Description, cs2, ApplicationCommandType.ChatInput)); } - } + if (cgwsgs.Any()) foreach (var cgwsg in cgwsgs) groupTranslation.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(cgwsg))); @@ -613,9 +612,7 @@ private async Task RegisterCommands(List List commandTranslations = null; if (!string.IsNullOrEmpty(ctx.SingleTranslations)) - { commandTranslations = JsonConvert.DeserializeObject>(ctx.SingleTranslations); - } //Slash commands var methods = module.DeclaredMethods.Where(x => x.GetCustomAttribute() != null); @@ -632,10 +629,11 @@ private async Task RegisterCommands(List if (cmd.Type == ApplicationCommandType.ChatInput && (cmd.Options == null || !cmd.Options.Any(x => x.Type == ApplicationCommandOptionType.SubCommand || x.Type == ApplicationCommandOptionType.SubCommandGroup))) { if (cmd.Options == null || !cmd.Options.Any()) - cs.Add(new Command(cmd.Name, cmd.Description, null, ApplicationCommandType.ChatInput)); + cs.Add(new(cmd.Name, cmd.Description, null, ApplicationCommandType.ChatInput)); else - cs.Add(new Command(cmd.Name, cmd.Description, cmd.Options.ToList(), ApplicationCommandType.ChatInput)); + cs.Add(new(cmd.Name, cmd.Description, cmd.Options.ToList(), ApplicationCommandType.ChatInput)); } + if (cs.Any()) foreach (var c in cs) translation.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(c))); @@ -661,7 +659,7 @@ private async Task RegisterCommands(List var cs = new List(); foreach (var cmd in contextCommands.applicationCommands) if (cmd.Type == ApplicationCommandType.Message || cmd.Type == ApplicationCommandType.User) - cs.Add(new Command(cmd.Name, null, null, cmd.Type)); + cs.Add(new(cmd.Name, null, null, cmd.Type)); if (cs.Any()) foreach (var c in cs) translation.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(c))); @@ -686,9 +684,7 @@ private async Task RegisterCommands(List catch (Exception ex) { if (ex is BadRequestException brex) - { this.Client.Logger.LogCritical(brex, @"There was an error registering application commands: {res}", brex.WebResponse.Response); - } else { if (ex.InnerException is not null && ex.InnerException is BadRequestException brex1) @@ -696,9 +692,11 @@ private async Task RegisterCommands(List else this.Client.Logger.LogCritical(ex, @"There was an error parsing the application commands"); } + s_errored = true; } } + if (!s_errored) { updateList = updateList.DistinctBy(x => x.Name).ToList(); @@ -708,7 +706,6 @@ private async Task RegisterCommands(List this.CheckRegistrationStartup(ManOr, translation, groupTranslation); } else - { try { List commands = new(); @@ -725,9 +722,7 @@ private async Task RegisterCommands(List GlobalCommandsInternal.AddRange(actualCommands); } else - { foreach (var cmd in GlobalDiscordCommands) - { try { await this.Client.DeleteGlobalApplicationCommandAsync(cmd.Id).ConfigureAwait(false); @@ -736,8 +731,6 @@ private async Task RegisterCommands(List { this.Client.Logger.Log(ApplicationCommandsLogLevel, "Could not delete global command {cmdId}. Please clean up manually", cmd.Id); } - } - } } else { @@ -756,9 +749,7 @@ private async Task RegisterCommands(List { } } else - { foreach (var cmd in GuildDiscordCommands.First(x => x.Key == guildId.Value).Value) - { try { await this.Client.DeleteGuildApplicationCommandAsync(guildId.Value, cmd.Id).ConfigureAwait(false); @@ -767,8 +758,6 @@ private async Task RegisterCommands(List { this.Client.Logger.Log(ApplicationCommandsLogLevel, "Could not delete guild command {cmdId} in guild {guildId}. Please clean up manually", cmd.Id, guildId.Value); } - } - } } } catch (UnauthorizedException ex) @@ -776,6 +765,7 @@ private async Task RegisterCommands(List this.Client.Logger.LogError("Could not register application commands for guild {guildId}.\nError: {exc}", guildId, ex.JsonMessage); return; } + //Creates a guild command if a guild id is specified, otherwise global //Checks against the ids and adds them to the command method lists foreach (var command in commands) @@ -796,7 +786,7 @@ private async Task RegisterCommands(List SubGroupCommands.AddRange(subGroupCommands.DistinctBy(x => x.Name)); ContextMenuCommands.AddRange(contextMenuCommands.DistinctBy(x => x.Name)); - s_registeredCommands.Add(new KeyValuePair>(guildId, commands.ToList())); + s_registeredCommands.Add(new(guildId, commands.ToList())); foreach (var command in commandMethods) { @@ -806,22 +796,15 @@ private async Task RegisterCommands(List this.Client.Logger.Log(ApplicationCommandsLogLevel, "Expected Count: {exp}\nCurrent Count: {cur}", s_expectedCount, s_registrationCount); if (guildId.HasValue) - { - await this._guildApplicationCommandsRegistered.InvokeAsync(this, new GuildApplicationCommandsRegisteredEventArgs(Configuration?.ServiceProvider) + await this._guildApplicationCommandsRegistered.InvokeAsync(this, new(Configuration?.ServiceProvider) { - Handled = true, - GuildId = guildId.Value, - RegisteredCommands = GuildCommandsInternal.Any(c => c.Key == guildId.Value) ? GuildCommandsInternal.FirstOrDefault(c => c.Key == guildId.Value).Value : null + Handled = true, GuildId = guildId.Value, RegisteredCommands = GuildCommandsInternal.Any(c => c.Key == guildId.Value) ? GuildCommandsInternal.FirstOrDefault(c => c.Key == guildId.Value).Value : null }).ConfigureAwait(false); - } else - { - await this._globalApplicationCommandsRegistered.InvokeAsync(this, new GlobalApplicationCommandsRegisteredEventArgs(Configuration?.ServiceProvider) + await this._globalApplicationCommandsRegistered.InvokeAsync(this, new(Configuration?.ServiceProvider) { - Handled = true, - RegisteredCommands = GlobalCommandsInternal + Handled = true, RegisteredCommands = GlobalCommandsInternal }).ConfigureAwait(false); - } s_registrationCount++; this.CheckRegistrationStartup(ManOr); @@ -833,9 +816,7 @@ private async Task RegisterCommands(List catch (Exception ex) { if (ex is BadRequestException brex) - { this.Client.Logger.LogCritical(brex, @"There was an error registering application commands: {res}", brex.WebResponse.Response); - } else { if (ex.InnerException is not null && ex.InnerException is BadRequestException brex1) @@ -843,9 +824,9 @@ private async Task RegisterCommands(List else this.Client.Logger.LogCritical(ex, @"There was an general error registering application commands"); } + s_errored = true; } - } } } @@ -855,12 +836,9 @@ private async void CheckRegistrationStartup(bool man = false, List { @@ -1028,11 +1005,17 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs } } - await this._slashExecuted.InvokeAsync(this, new SlashCommandExecutedEventArgs(this.Client.ServiceProvider) { Context = context }).ConfigureAwait(false); + await this._slashExecuted.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = context + }).ConfigureAwait(false); } catch (Exception ex) { - await this._slashError.InvokeAsync(this, new SlashCommandErrorEventArgs(this.Client.ServiceProvider) { Context = context, Exception = ex }).ConfigureAwait(false); + await this._slashError.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = context, Exception = ex + }).ConfigureAwait(false); this.Client.Logger.LogError(ex, "Error in slash interaction"); } @@ -1082,7 +1065,10 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs EntitlementSkuIds = e.Interaction.EntitlementSkuIds }; - var choices = await ((Task>) providerMethod.Invoke(providerInstance, new[] { context })).ConfigureAwait(false); + var choices = await ((Task>)providerMethod.Invoke(providerInstance, new[] + { + context + })).ConfigureAwait(false); await e.Interaction.CreateResponseAsync(InteractionResponseType.AutoCompleteResult, new DiscordInteractionResponseBuilder().AddAutoCompleteChoices(choices)).ConfigureAwait(false); } @@ -1115,7 +1101,10 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs EntitlementSkuIds = e.Interaction.EntitlementSkuIds }; - var choices = await ((Task>) providerMethod.Invoke(providerInstance, new[] { context })).ConfigureAwait(false); + var choices = await ((Task>)providerMethod.Invoke(providerInstance, new[] + { + context + })).ConfigureAwait(false); await e.Interaction.CreateResponseAsync(InteractionResponseType.AutoCompleteResult, new DiscordInteractionResponseBuilder().AddAutoCompleteChoices(choices)).ConfigureAwait(false); } @@ -1149,7 +1138,10 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs EntitlementSkuIds = e.Interaction.EntitlementSkuIds }; - var choices = await ((Task>) providerMethod.Invoke(providerInstance, new[] { context })).ConfigureAwait(false); + var choices = await ((Task>)providerMethod.Invoke(providerInstance, new[] + { + context + })).ConfigureAwait(false); await e.Interaction.CreateResponseAsync(InteractionResponseType.AutoCompleteResult, new DiscordInteractionResponseBuilder().AddAutoCompleteChoices(choices)).ConfigureAwait(false); } } @@ -1171,9 +1163,10 @@ private ApplicationCommandFinalType GetInteractionType(DiscordInteractionData da if (data.Options == null!) return ApplicationCommandFinalType.Command; if (data.Options.All(x => - x.Type is not ApplicationCommandOptionType.SubCommand - and not ApplicationCommandOptionType.SubCommandGroup)) + x.Type is not ApplicationCommandOptionType.SubCommand + and not ApplicationCommandOptionType.SubCommandGroup)) return ApplicationCommandFinalType.Command; + if (data.Options.Any(x => x.Type is ApplicationCommandOptionType.SubCommandGroup)) type = ApplicationCommandFinalType.SubCommandGroup; else if (data.Options.Any(x => x.Type is ApplicationCommandOptionType.SubCommand)) @@ -1239,13 +1232,22 @@ private Task ContextMenuHandler(DiscordClient client, ContextMenuInteractionCrea throw new InvalidOperationException("A context menu command was executed, but no command was registered for it."); } - await this.RunCommandAsync(context, method.Method, new[] { context }).ConfigureAwait(false); + await this.RunCommandAsync(context, method.Method, new[] + { + context + }).ConfigureAwait(false); - await this._contextMenuExecuted.InvokeAsync(this, new ContextMenuExecutedEventArgs(this.Client.ServiceProvider) { Context = context }).ConfigureAwait(false); + await this._contextMenuExecuted.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = context + }).ConfigureAwait(false); } catch (Exception ex) { - await this._contextMenuErrored.InvokeAsync(this, new ContextMenuErrorEventArgs(this.Client.ServiceProvider) { Context = context, Exception = ex }).ConfigureAwait(false); + await this._contextMenuErrored.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = context, Exception = ex + }).ConfigureAwait(false); } }); @@ -1284,7 +1286,7 @@ internal async Task RunCommandAsync(BaseContext context, MethodInfo method, IEnu break; default: - throw new Exception($"An unknown {nameof(ApplicationCommandModuleLifespanAttribute)} scope was specified on command {context.CommandName}"); + throw new($"An unknown {nameof(ApplicationCommandModuleLifespanAttribute)} scope was specified on command {context.CommandName}"); } ApplicationCommandsModule module = null; @@ -1307,6 +1309,7 @@ internal async Task RunCommandAsync(BaseContext context, MethodInfo method, IEnu await (module?.AfterSlashExecutionAsync(slashContext) ?? Task.CompletedTask).ConfigureAwait(false); } } + // Context menus if (context is ContextMenuContext contextMenuContext) { @@ -1394,11 +1397,13 @@ internal static object CreateInstance(Type t, IServiceProvider services) /// The options. private async Task> ResolveInteractionCommandParameters(InteractionCreateEventArgs e, InteractionContext context, MethodInfo method, IEnumerable options) { - var args = new List { context }; + var args = new List + { + context + }; var parameters = method.GetParameters().Skip(1); foreach (var parameter in parameters) - { //Accounts for optional arguments without values given if (parameter.IsOptional && (options == null || (!options?.Any(x => x.Name == parameter.GetCustomAttribute().Name.ToLower()) ?? true))) args.Add(parameter.DefaultValue); @@ -1429,19 +1434,22 @@ private async Task> ResolveInteractionCommandParameters(Interaction { //Checks through resolved if (e.Interaction.Data.Resolved.Attachments != null && - e.Interaction.Data.Resolved.Attachments.TryGetValue((ulong)option.Value, out var attachment)) + e.Interaction.Data.Resolved.Attachments.TryGetValue((ulong)option.Value, out var attachment)) args.Add(attachment); else - args.Add(new DiscordAttachment() { Id = (ulong)option.Value, Discord = this.Client.ApiClient.Discord }); + args.Add(new DiscordAttachment() + { + Id = (ulong)option.Value, Discord = this.Client.ApiClient.Discord + }); } else if (parameter.ParameterType == typeof(DiscordUser)) { //Checks through resolved if (e.Interaction.Data.Resolved.Members != null && - e.Interaction.Data.Resolved.Members.TryGetValue((ulong)option.Value, out var member)) + e.Interaction.Data.Resolved.Members.TryGetValue((ulong)option.Value, out var member)) args.Add(member); else if (e.Interaction.Data.Resolved.Users != null && - e.Interaction.Data.Resolved.Users.TryGetValue((ulong)option.Value, out var user)) + e.Interaction.Data.Resolved.Users.TryGetValue((ulong)option.Value, out var user)) args.Add(user); else args.Add(await this.Client.GetUserAsync((ulong)option.Value).ConfigureAwait(false)); @@ -1450,7 +1458,7 @@ private async Task> ResolveInteractionCommandParameters(Interaction { //Checks through resolved if (e.Interaction.Data.Resolved.Channels != null && - e.Interaction.Data.Resolved.Channels.TryGetValue((ulong)option.Value, out var channel)) + e.Interaction.Data.Resolved.Channels.TryGetValue((ulong)option.Value, out var channel)) args.Add(channel); else args.Add(e.Interaction.Guild.GetChannel((ulong)option.Value)); @@ -1459,7 +1467,7 @@ private async Task> ResolveInteractionCommandParameters(Interaction { //Checks through resolved if (e.Interaction.Data.Resolved.Roles != null && - e.Interaction.Data.Resolved.Roles.TryGetValue((ulong)option.Value, out var role)) + e.Interaction.Data.Resolved.Roles.TryGetValue((ulong)option.Value, out var role)) args.Add(role); else args.Add(e.Interaction.Guild.GetRole((ulong)option.Value)); @@ -1481,7 +1489,6 @@ private async Task> ResolveInteractionCommandParameters(Interaction else throw new ArgumentException($"Error resolving interaction."); } - } return args; } @@ -1503,9 +1510,7 @@ private async Task RunPreexecutionChecksAsync(MethodInfo method, BaseContext con { attributes.AddRange(method.DeclaringType.DeclaringType.GetCustomAttributes()); if (method.DeclaringType.DeclaringType.DeclaringType != null) - { attributes.AddRange(method.DeclaringType.DeclaringType.DeclaringType.GetCustomAttributes()); - } } var dict = new Dictionary(); @@ -1518,8 +1523,12 @@ private async Task RunPreexecutionChecksAsync(MethodInfo method, BaseContext con //Checks if any failed, and throws an exception if (dict.Any(x => x.Value == false)) - throw new SlashExecutionChecksFailedException { FailedChecks = dict.Where(x => x.Value == false).Select(x => x.Key).ToList() }; + throw new SlashExecutionChecksFailedException + { + FailedChecks = dict.Where(x => x.Value == false).Select(x => x.Key).ToList() + }; } + if (context is ContextMenuContext cMctx) { var attributes = new List(); @@ -1529,9 +1538,7 @@ private async Task RunPreexecutionChecksAsync(MethodInfo method, BaseContext con { attributes.AddRange(method.DeclaringType.DeclaringType.GetCustomAttributes()); if (method.DeclaringType.DeclaringType.DeclaringType != null) - { attributes.AddRange(method.DeclaringType.DeclaringType.DeclaringType.GetCustomAttributes()); - } } var dict = new Dictionary(); @@ -1544,7 +1551,10 @@ private async Task RunPreexecutionChecksAsync(MethodInfo method, BaseContext con //Checks if any failed, and throws an exception if (dict.Any(x => x.Value == false)) - throw new ContextMenuExecutionChecksFailedException { FailedChecks = dict.Where(x => x.Value == false).Select(x => x.Key).ToList() }; + throw new ContextMenuExecutionChecksFailedException + { + FailedChecks = dict.Where(x => x.Value == false).Select(x => x.Key).ToList() + }; } } @@ -1580,9 +1590,7 @@ private static async Task> GetChoice var result = await ((Task>)method.Invoke(instance, null)).ConfigureAwait(false); if (result.Any()) - { choices.AddRange(result); - } } } @@ -1597,9 +1605,7 @@ private static List GetChoiceAttributesFr { var choices = new List(); foreach (Enum enumValue in Enum.GetValues(enumParam)) - { - choices.Add(new DiscordApplicationCommandOptionChoice(enumValue.GetName(), enumValue.ToString())); - } + choices.Add(new(enumValue.GetName(), enumValue.ToString())); return choices; } @@ -1612,24 +1618,24 @@ private static ApplicationCommandOptionType GetParameterType(Type type) var parameterType = type == typeof(string) ? ApplicationCommandOptionType.String : type == typeof(long) || type == typeof(long?) || type == typeof(int) || type == typeof(int?) - ? ApplicationCommandOptionType.Integer - : type == typeof(bool) || type == typeof(bool?) - ? ApplicationCommandOptionType.Boolean - : type == typeof(double) || type == typeof(double?) - ? ApplicationCommandOptionType.Number - : type == typeof(DiscordAttachment) - ? ApplicationCommandOptionType.Attachment - : type == typeof(DiscordChannel) - ? ApplicationCommandOptionType.Channel - : type == typeof(DiscordUser) - ? ApplicationCommandOptionType.User - : type == typeof(DiscordRole) - ? ApplicationCommandOptionType.Role - : type == typeof(SnowflakeObject) - ? ApplicationCommandOptionType.Mentionable - : type.IsEnum - ? ApplicationCommandOptionType.String - : throw new ArgumentException("Cannot convert type! Argument types must be string, int, long, bool, double, DiscordChannel, DiscordUser, DiscordRole, SnowflakeObject, DiscordAttachment or an Enum."); + ? ApplicationCommandOptionType.Integer + : type == typeof(bool) || type == typeof(bool?) + ? ApplicationCommandOptionType.Boolean + : type == typeof(double) || type == typeof(double?) + ? ApplicationCommandOptionType.Number + : type == typeof(DiscordAttachment) + ? ApplicationCommandOptionType.Attachment + : type == typeof(DiscordChannel) + ? ApplicationCommandOptionType.Channel + : type == typeof(DiscordUser) + ? ApplicationCommandOptionType.User + : type == typeof(DiscordRole) + ? ApplicationCommandOptionType.Role + : type == typeof(SnowflakeObject) + ? ApplicationCommandOptionType.Mentionable + : type.IsEnum + ? ApplicationCommandOptionType.String + : throw new ArgumentException("Cannot convert type! Argument types must be string, int, long, bool, double, DiscordChannel, DiscordUser, DiscordRole, SnowflakeObject, DiscordAttachment or an Enum."); return parameterType; } @@ -1690,17 +1696,13 @@ internal static async Task> ParseParameter var choices = GetChoiceAttributesFromParameter(parameter.GetCustomAttributes()); //From enums if (parameter.ParameterType.IsEnum) - { choices = GetChoiceAttributesFromEnumParameter(parameter.ParameterType); - } //From choice provider var choiceProviders = parameter.GetCustomAttributes(); if (choiceProviders.Any()) - { choices = await GetChoiceAttributesFromProvider(choiceProviders, guildId).ConfigureAwait(false); - } - options.Add(new DiscordApplicationCommandOption(optionAttribute.Name, optionAttribute.Description, parameterType, !parameter.IsOptional, choices, null, channelTypes, optionAttribute.Autocomplete, minimumValue, maximumValue, minimumLength: minimumLength, maximumLength: maximumLength)); + options.Add(new(optionAttribute.Name, optionAttribute.Description, parameterType, !parameter.IsOptional, choices, null, channelTypes, optionAttribute.Autocomplete, minimumValue, maximumValue, minimumLength: minimumLength, maximumLength: maximumLength)); } return options; @@ -1741,6 +1743,7 @@ public event AsyncEventHandler this._slashError.Register(value); remove => this._slashError.Unregister(value); } + private AsyncEvent _slashError; /// @@ -1751,6 +1754,7 @@ public event AsyncEventHandler this._slashExecuted.Register(value); remove => this._slashExecuted.Unregister(value); } + private AsyncEvent _slashExecuted; /// @@ -1761,6 +1765,7 @@ public event AsyncEventHandler this._contextMenuErrored.Register(value); remove => this._contextMenuErrored.Unregister(value); } + private AsyncEvent _contextMenuErrored; /// @@ -1771,6 +1776,7 @@ public event AsyncEventHandler this._contextMenuExecuted.Register(value); remove => this._contextMenuExecuted.Unregister(value); } + private AsyncEvent _contextMenuExecuted; } @@ -1907,6 +1913,7 @@ internal class ContextMenuCommand } #region Default Help + /// /// Represents the default help module. /// @@ -1941,9 +1948,7 @@ public async Task> Prov } foreach (var sc in slashCommands.Take(25)) - { - options.Add(new DiscordApplicationCommandAutocompleteChoice(sc.Name, sc.Name.Trim())); - } + options.Add(new(sc.Name, sc.Name.Trim())); return options.AsEnumerable(); } } @@ -1972,20 +1977,17 @@ public async Task> Prov } var command = slashCommands.FirstOrDefault(ac => - ac.Name.Equals(context.Options[0].Value.ToString().Trim(),StringComparison.OrdinalIgnoreCase)); + ac.Name.Equals(context.Options[0].Value.ToString().Trim(), StringComparison.OrdinalIgnoreCase)); if (command is null || command.Options is null) - { - options.Add(new DiscordApplicationCommandAutocompleteChoice("no_options_for_this_command", "no_options_for_this_command")); - } + options.Add(new("no_options_for_this_command", "no_options_for_this_command")); else { var opt = command.Options.Where(c => c.Type is ApplicationCommandOptionType.SubCommandGroup or ApplicationCommandOptionType.SubCommand - && c.Name.StartsWith(context.Options[1].Value.ToString(), StringComparison.InvariantCultureIgnoreCase)).ToList(); + && c.Name.StartsWith(context.Options[1].Value.ToString(), StringComparison.InvariantCultureIgnoreCase)).ToList(); foreach (var option in opt.Take(25)) - { - options.Add(new DiscordApplicationCommandAutocompleteChoice(option.Name, option.Name.Trim())); - } + options.Add(new(option.Name, option.Name.Trim())); } + return options.AsEnumerable(); } } @@ -2017,41 +2019,44 @@ public async Task> Prov ac.Name.Equals(context.Options[0].Value.ToString().Trim(), StringComparison.OrdinalIgnoreCase)); if (command.Options is null) { - options.Add(new DiscordApplicationCommandAutocompleteChoice("no_options_for_this_command", "no_options_for_this_command")); + options.Add(new("no_options_for_this_command", "no_options_for_this_command")); return options.AsEnumerable(); } + var foundCommand = command.Options.FirstOrDefault(op => op.Name.Equals(context.Options[1].Value.ToString().Trim(), StringComparison.OrdinalIgnoreCase)); if (foundCommand is null || foundCommand.Options is null) - { - options.Add(new DiscordApplicationCommandAutocompleteChoice("no_options_for_this_command", "no_options_for_this_command")); - } + options.Add(new("no_options_for_this_command", "no_options_for_this_command")); else { var opt = foundCommand.Options.Where(x => x.Type == ApplicationCommandOptionType.SubCommand && - x.Name.StartsWith(context.Options[2].Value.ToString(), StringComparison.OrdinalIgnoreCase)).ToList(); + x.Name.StartsWith(context.Options[2].Value.ToString(), StringComparison.OrdinalIgnoreCase)).ToList(); foreach (var option in opt.Take(25)) - { - options.Add(new DiscordApplicationCommandAutocompleteChoice(option.Name, option.Name.Trim())); - } + options.Add(new(option.Name, option.Name.Trim())); } + return options.AsEnumerable(); } } [SlashCommand("help", "Displays command help")] - internal async Task DefaultHelpAsync(InteractionContext ctx, - [Autocomplete(typeof(DefaultHelpAutoCompleteProvider))] - [Option("option_one", "top level command to provide help for", true)] string commandName, - [Autocomplete(typeof(DefaultHelpAutoCompleteLevelOneProvider))] - [Option("option_two", "subgroup or command to provide help for", true)] string commandOneName = null, - [Autocomplete(typeof(DefaultHelpAutoCompleteLevelTwoProvider))] - [Option("option_three", "command to provide help for", true)] string commandTwoName = null) + internal async Task DefaultHelpAsync( + InteractionContext ctx, + [Autocomplete(typeof(DefaultHelpAutoCompleteProvider)), Option("option_one", "top level command to provide help for", true)] + + string commandName, + [Autocomplete(typeof(DefaultHelpAutoCompleteLevelOneProvider)), Option("option_two", "subgroup or command to provide help for", true)] + + string commandOneName = null, + [Autocomplete(typeof(DefaultHelpAutoCompleteLevelTwoProvider)), Option("option_three", "command to provide help for", true)] + + string commandTwoName = null + ) { List applicationCommands = null; var globalCommandsTask = ctx.Client.GetGlobalApplicationCommandsAsync(); if (ctx.Guild != null) { - var guildCommandsTask= ctx.Client.GetGuildApplicationCommandsAsync(ctx.Guild.Id); + var guildCommandsTask = ctx.Client.GetGuildApplicationCommandsAsync(ctx.Guild.Id); await Task.WhenAll(globalCommandsTask, guildCommandsTask).ConfigureAwait(false); applicationCommands = globalCommandsTask.Result.Concat(guildCommandsTask.Result) .Where(ac => !ac.Name.Equals("help", StringComparison.OrdinalIgnoreCase)) @@ -2077,17 +2082,17 @@ await ctx.EditResponseAsync(new DiscordWebhookBuilder() .WithContent($"There are no slash commands").AsEphemeral()).ConfigureAwait(false); return; } + if (commandTwoName is not null && !commandTwoName.Equals("no_options_for_this_command")) { var commandsWithSubCommands = applicationCommands.FindAll(ac => ac.Options is not null && ac.Options.Any(op => op.Type == ApplicationCommandOptionType.SubCommandGroup)); - var subCommandParent = commandsWithSubCommands.FirstOrDefault(cm => cm.Name.Equals(commandName,StringComparison.OrdinalIgnoreCase)); + var subCommandParent = commandsWithSubCommands.FirstOrDefault(cm => cm.Name.Equals(commandName, StringComparison.OrdinalIgnoreCase)); var cmdParent = commandsWithSubCommands.FirstOrDefault(cm => cm.Options.Any(op => op.Name.Equals(commandOneName))).Options - .FirstOrDefault(opt => opt.Name.Equals(commandOneName,StringComparison.OrdinalIgnoreCase)); - var cmd = cmdParent.Options.FirstOrDefault(op => op.Name.Equals(commandTwoName,StringComparison.OrdinalIgnoreCase)); + .FirstOrDefault(opt => opt.Name.Equals(commandOneName, StringComparison.OrdinalIgnoreCase)); + var cmd = cmdParent.Options.FirstOrDefault(op => op.Name.Equals(commandTwoName, StringComparison.OrdinalIgnoreCase)); var discordEmbed = new DiscordEmbedBuilder { - Title = "Help", - Description = $"{subCommandParent.Mention.Replace(subCommandParent.Name, $"{subCommandParent.Name} {cmdParent.Name} {cmd.Name}")}: {cmd.Description ?? "No description provided."}" + Title = "Help", Description = $"{subCommandParent.Mention.Replace(subCommandParent.Name, $"{subCommandParent.Name} {cmdParent.Name} {cmd.Name}")}: {cmd.Description ?? "No description provided."}" }; if (cmd.Options is not null) { @@ -2098,8 +2103,9 @@ await ctx.EditResponseAsync(new DiscordWebhookBuilder() sb.Append('`').Append(option.Name).Append("`: ").Append(option.Description ?? "No description provided.").Append('\n'); sb.Append('\n'); - discordEmbed.AddField(new DiscordEmbedField("Arguments", sb.ToString().Trim())); + discordEmbed.AddField(new("Arguments", sb.ToString().Trim())); } + if (ApplicationCommandsExtension.Configuration.AutoDefer) await ctx.EditResponseAsync(new DiscordWebhookBuilder() .AddEmbed(discordEmbed)).ConfigureAwait(false); @@ -2110,12 +2116,11 @@ await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, else if (commandOneName is not null && commandTwoName is null && !commandOneName.Equals("no_options_for_this_command")) { var commandsWithOptions = applicationCommands.FindAll(ac => ac.Options is not null && ac.Options.All(op => op.Type == ApplicationCommandOptionType.SubCommand)); - var subCommandParent = commandsWithOptions.FirstOrDefault(cm => cm.Name.Equals(commandName,StringComparison.OrdinalIgnoreCase)); - var subCommand = subCommandParent.Options.FirstOrDefault(op => op.Name.Equals(commandOneName,StringComparison.OrdinalIgnoreCase)); + var subCommandParent = commandsWithOptions.FirstOrDefault(cm => cm.Name.Equals(commandName, StringComparison.OrdinalIgnoreCase)); + var subCommand = subCommandParent.Options.FirstOrDefault(op => op.Name.Equals(commandOneName, StringComparison.OrdinalIgnoreCase)); var discordEmbed = new DiscordEmbedBuilder { - Title = "Help", - Description = $"{subCommandParent.Mention.Replace(subCommandParent.Name, $"{subCommandParent.Name} {subCommand.Name}")}: {subCommand.Description ?? "No description provided."}" + Title = "Help", Description = $"{subCommandParent.Mention.Replace(subCommandParent.Name, $"{subCommandParent.Name} {subCommand.Name}")}: {subCommand.Description ?? "No description provided."}" }; if (subCommand.Options is not null) { @@ -2126,7 +2131,7 @@ await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, sb.Append('`').Append(option.Name).Append("`: ").Append(option.Description ?? "No description provided.").Append('\n'); sb.Append('\n'); - discordEmbed.AddField(new DiscordEmbedField("Arguments", sb.ToString().Trim())); + discordEmbed.AddField(new("Arguments", sb.ToString().Trim())); } if (ApplicationCommandsExtension.Configuration.AutoDefer) @@ -2148,11 +2153,11 @@ await ctx.EditResponseAsync(new DiscordWebhookBuilder() .WithContent($"No command called {commandName} in guild {ctx.Guild.Name}").AsEphemeral()).ConfigureAwait(false); return; } + var discordEmbed = new DiscordEmbedBuilder { - Title = "Help", - Description = $"{command.Mention}: {command.Description ?? "No description provided."}" - }.AddField(new DiscordEmbedField("Command is NSFW", command.IsNsfw.ToString())); + Title = "Help", Description = $"{command.Mention}: {command.Description ?? "No description provided."}" + }.AddField(new("Command is NSFW", command.IsNsfw.ToString())); if (command.Options is not null) { var commandOptions = command.Options.ToList(); @@ -2162,8 +2167,9 @@ await ctx.EditResponseAsync(new DiscordWebhookBuilder() sb.Append('`').Append(option.Name).Append("`: ").Append(option.Description ?? "No description provided.").Append('\n'); sb.Append('\n'); - discordEmbed.AddField(new DiscordEmbedField("Arguments", sb.ToString().Trim())); + discordEmbed.AddField(new("Arguments", sb.ToString().Trim())); } + if (ApplicationCommandsExtension.Configuration.AutoDefer) await ctx.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(discordEmbed)).ConfigureAwait(false); else @@ -2172,4 +2178,5 @@ await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, } } } + #endregion diff --git a/DisCatSharp.ApplicationCommands/ApplicationCommandsUtilities.cs b/DisCatSharp.ApplicationCommands/ApplicationCommandsUtilities.cs index 48bc175e1c..51e25b7be3 100644 --- a/DisCatSharp.ApplicationCommands/ApplicationCommandsUtilities.cs +++ b/DisCatSharp.ApplicationCommands/ApplicationCommandsUtilities.cs @@ -83,6 +83,7 @@ internal static bool IsCommandCandidate(this MethodInfo method, out ParameterInf ApplicationCommandsExtension.Logger.LogDebug("Not existent"); return false; } + if (ApplicationCommandsExtension.DebugEnabled) ApplicationCommandsExtension.Logger.LogDebug("Checking method {name}", method.Name); @@ -96,7 +97,7 @@ internal static bool IsCommandCandidate(this MethodInfo method, out ParameterInf // check if appropriate return and arguments parameters = method.GetParameters(); - if (!parameters.Any() || (parameters.First().ParameterType != typeof(ContextMenuContext) && parameters.First().ParameterType != typeof(InteractionContext)) || method.ReturnType != typeof(Task)) + if (!parameters.Any() || parameters.First().ParameterType != typeof(ContextMenuContext) && parameters.First().ParameterType != typeof(InteractionContext) || method.ReturnType != typeof(Task)) { if (ApplicationCommandsExtension.DebugEnabled) ApplicationCommandsExtension.Logger.LogDebug("Missing first parameter with type ContextMenuContext or InteractionContext"); diff --git a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuAttribute.cs index 36e5839de6..5632a4306f 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuAttribute.cs @@ -69,7 +69,6 @@ public ContextMenuAttribute(ApplicationCommandType type, string name, bool isNsf this.IntegrationTypes = integrationTypes?.ToList(); } - /// /// Marks this method as a context menu. /// @@ -93,7 +92,6 @@ public ContextMenuAttribute(ApplicationCommandType type, string name, long defau this.IntegrationTypes = integrationTypes?.ToList(); } - /// /// Marks this method as context menu. /// diff --git a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs index 4a0dc8b167..c8371902fd 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs @@ -45,7 +45,7 @@ public ContextMenuCooldownAttribute(int maxUses, double resetAfter, CooldownBuck this.MaxUses = maxUses; this.Reset = TimeSpan.FromSeconds(resetAfter); this.BucketType = bucketType; - this.Buckets = new ConcurrentDictionary(); + this.Buckets = new(); } /// @@ -68,7 +68,11 @@ public ContextMenuCooldownBucket GetBucket(BaseContext ctx) public TimeSpan GetRemainingCooldown(BaseContext ctx) { var bucket = this.GetBucket(ctx); - return bucket == null ? TimeSpan.Zero : bucket.RemainingUses > 0 ? TimeSpan.Zero : bucket.ResetsAt - DateTimeOffset.UtcNow; + return bucket == null + ? TimeSpan.Zero + : bucket.RemainingUses > 0 + ? TimeSpan.Zero + : bucket.ResetsAt - DateTimeOffset.UtcNow; } /// @@ -108,7 +112,7 @@ public override async Task ExecuteChecksAsync(BaseContext ctx) var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld); if (!this.Buckets.TryGetValue(bid, out var bucket)) { - bucket = new ContextMenuCooldownBucket(this.MaxUses, this.Reset, usr, chn, gld); + bucket = new(this.MaxUses, this.Reset, usr, chn, gld); this.Buckets.AddOrUpdate(bid, bucket, (k, v) => bucket); } @@ -123,8 +127,7 @@ public sealed class ContextMenuCooldownBucket : CooldownBucket { internal ContextMenuCooldownBucket(int maxUses, TimeSpan resetAfter, ulong userId = 0, ulong channelId = 0, ulong guildId = 0) : base(maxUses, resetAfter, userId, channelId, guildId) - { - } + { } /// /// Returns a string representation of this command cooldown bucket. diff --git a/DisCatSharp.ApplicationCommands/Attributes/RequirePermissionsAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/RequirePermissionsAttribute.cs index 087bacf1cf..ad300e6e16 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/RequirePermissionsAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/RequirePermissionsAttribute.cs @@ -44,11 +44,13 @@ public override async Task ExecuteChecksAsync(BaseContext ctx) var usr = ctx.Member; if (usr == null) return false; + var pusr = ctx.Channel.PermissionsFor(usr); var bot = await ctx.Guild.GetMemberAsync(ctx.Client.CurrentUser.Id).ConfigureAwait(false); if (bot == null) return false; + var pbot = ctx.Channel.PermissionsFor(bot); var usrok = ctx.Guild.OwnerId == usr.Id; diff --git a/DisCatSharp.ApplicationCommands/Attributes/RequirePremiumAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/RequirePremiumAttribute.cs index 013e1e8f48..d9e5979d24 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/RequirePremiumAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/RequirePremiumAttribute.cs @@ -54,7 +54,7 @@ public override async Task ExecuteChecksAsync(BaseContext ctx) /// /// Defines that usage of this application command is restricted to users with a test entitlement. /// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false),RequiresFeature(Features.MonetizedApplication)] +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false), RequiresFeature(Features.MonetizedApplication)] public sealed class ApplicationCommandRequirePremiumTestAttribute : ApplicationCommandCheckBaseAttribute { /// diff --git a/DisCatSharp.ApplicationCommands/Attributes/RequireUserPermissionsAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/RequireUserPermissionsAttribute.cs index ce957e1896..21a9817639 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/RequireUserPermissionsAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/RequireUserPermissionsAttribute.cs @@ -52,6 +52,8 @@ public override Task ExecuteChecksAsync(BaseContext ctx) return (pusr & Permissions.Administrator) != 0 ? Task.FromResult(true) - : (pusr & this.Permissions) == this.Permissions ? Task.FromResult(true) : Task.FromResult(false); + : (pusr & this.Permissions) == this.Permissions + ? Task.FromResult(true) + : Task.FromResult(false); } } diff --git a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/ChoiceProviderAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/ChoiceProviderAttribute.cs index ef8ef64450..6188635fec 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/ChoiceProviderAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/ChoiceProviderAttribute.cs @@ -9,7 +9,6 @@ namespace DisCatSharp.ApplicationCommands.Attributes; [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] public class ChoiceProviderAttribute : Attribute { - /// /// The type of the provider. /// diff --git a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/MinimumMaximumAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/MinimumMaximumAttribute.cs index a2930874c0..654c53abb1 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/MinimumMaximumAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/MinimumMaximumAttribute.cs @@ -74,7 +74,6 @@ public MaximumValueAttribute(double value) } } - /// /// Sets a minimum value for this slash command option. Only valid for parameters. /// @@ -93,6 +92,7 @@ public MinimumLengthAttribute(int value) { if (value > 600) throw new ArgumentException("Minimum cannot be more than 6000."); + this.Value = value; } } @@ -115,6 +115,7 @@ public MaximumLengthAttribute(int value) { if (value == 0 || value > 600) throw new ArgumentException("Maximum length cannot be less than 1 and cannot be more than 6000."); + this.Value = value; } } diff --git a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs index 90d97af6bc..64ec59a68f 100644 --- a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs +++ b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs @@ -45,7 +45,7 @@ public SlashCommandCooldownAttribute(int maxUses, double resetAfter, CooldownBuc this.MaxUses = maxUses; this.Reset = TimeSpan.FromSeconds(resetAfter); this.BucketType = bucketType; - this.Buckets = new ConcurrentDictionary(); + this.Buckets = new(); } /// @@ -68,7 +68,11 @@ public SlashCommandCooldownBucket GetBucket(BaseContext ctx) public TimeSpan GetRemainingCooldown(BaseContext ctx) { var bucket = this.GetBucket(ctx); - return bucket == null ? TimeSpan.Zero : bucket.RemainingUses > 0 ? TimeSpan.Zero : bucket.ResetsAt - DateTimeOffset.UtcNow; + return bucket == null + ? TimeSpan.Zero + : bucket.RemainingUses > 0 + ? TimeSpan.Zero + : bucket.ResetsAt - DateTimeOffset.UtcNow; } /// @@ -108,7 +112,7 @@ public override async Task ExecuteChecksAsync(BaseContext ctx) var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld); if (!this.Buckets.TryGetValue(bid, out var bucket)) { - bucket = new SlashCommandCooldownBucket(this.MaxUses, this.Reset, usr, chn, gld); + bucket = new(this.MaxUses, this.Reset, usr, chn, gld); this.Buckets.AddOrUpdate(bid, bucket, (k, v) => bucket); } @@ -129,7 +133,5 @@ public sealed class SlashCommandCooldownBucket : CooldownBucket internal SlashCommandCooldownBucket(int maxUses, TimeSpan resetAfter, ulong userId = 0, ulong channelId = 0, ulong guildId = 0) : base(maxUses, resetAfter, userId, channelId, guildId) - { - - } + { } } diff --git a/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs b/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs index f8310b6cf5..d784c2aa36 100644 --- a/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs +++ b/DisCatSharp.ApplicationCommands/Checks/ApplicationCommandEqualityChecks.cs @@ -24,7 +24,9 @@ internal static class ApplicationCommandEqualityChecks /// Whether the equal check is performed for a guild command. internal static bool IsEqualTo( this DiscordApplicationCommand? ac1, - DiscordApplicationCommand? targetApplicationCommand, DiscordClient client, bool isGuild + DiscordApplicationCommand? targetApplicationCommand, + DiscordClient client, + bool isGuild ) { if (targetApplicationCommand is null || ac1 is null) @@ -83,8 +85,12 @@ internal static bool IsEqualTo( /// Whether localization is enabled. /// Whether the equal check is performed for a guild command. internal static bool SoftEqual( - this DiscordApplicationCommand source, DiscordApplicationCommand target, - ApplicationCommandType type, BaseDiscordClient client, bool localizationEnabled = false, bool guild = false + this DiscordApplicationCommand source, + DiscordApplicationCommand target, + ApplicationCommandType type, + BaseDiscordClient client, + bool localizationEnabled = false, + bool guild = false ) { bool? sDmPerm = source.DmPermission ?? true; @@ -182,8 +188,12 @@ internal static bool AreDictionariesEqual(this Dictionary source /// The source dm permission. /// The target dm permission. internal static bool DeepEqual( - DiscordApplicationCommand source, DiscordApplicationCommand target, BaseDiscordClient client, - bool localizationEnabled = false, bool? sDmPerm = null, bool? tDmPerm = null + DiscordApplicationCommand source, + DiscordApplicationCommand target, + BaseDiscordClient client, + bool localizationEnabled = false, + bool? sDmPerm = null, + bool? tDmPerm = null ) { var name = source.Name; @@ -218,13 +228,14 @@ internal static bool DeepEqual( /// Whether localization is enabled. private static (bool Equal, string? Reason) DeepEqualOptions( IReadOnlyList? sourceOptions, - IReadOnlyList? targetOptions, bool localizationEnabled + IReadOnlyList? targetOptions, + bool localizationEnabled ) { if (sourceOptions == null && targetOptions == null) return (true, null); - if ((sourceOptions != null && targetOptions == null) || (sourceOptions == null && targetOptions != null)) + if (sourceOptions != null && targetOptions == null || sourceOptions == null && targetOptions != null) return (false, "source or target option null, but not both"); if (sourceOptions!.Count != targetOptions!.Count) @@ -251,8 +262,8 @@ private static (bool Equal, string? Reason) DeepEqualOptions( sourceOption.RawDescriptionLocalizations.AreDictionariesEqual(targetOption .RawDescriptionLocalizations); - if ((sourceOption.Choices is null && targetOption.Choices is not null) || - (sourceOption.Choices is not null && targetOption.Choices is null)) + if (sourceOption.Choices is null && targetOption.Choices is not null || + sourceOption.Choices is not null && targetOption.Choices is null) return (false, "source or target choices null, but not both - " + sourceOption.Name); if (sourceOption.Choices is not null && targetOption.Choices is not null) @@ -263,10 +274,10 @@ private static (bool Equal, string? Reason) DeepEqualOptions( return (false, "choice mismatch - " + sourceOption.Name); } - if ((sourceOption.ChannelTypes is null && targetOption.ChannelTypes is not null) || - (sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is null) || - (sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is not null && - !sourceOption.ChannelTypes.OrderBy(x => x).All(targetOption.ChannelTypes.OrderBy(x => x).Contains))) + if (sourceOption.ChannelTypes is null && targetOption.ChannelTypes is not null || + sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is null || + sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is not null && + !sourceOption.ChannelTypes.OrderBy(x => x).All(targetOption.ChannelTypes.OrderBy(x => x).Contains)) return (false, "channel type mismatch - " + sourceOption.Name); var rec = DeepEqualOptions(sourceOption.Options, targetOption.Options, localizationEnabled); diff --git a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs index 6ce9af899c..857e0ea149 100644 --- a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs +++ b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs @@ -221,5 +221,5 @@ public Task GetFollowupMessageAsync(ulong followupMessageId) /// /// The original interaction response. public Task GetOriginalResponseAsync() - => this.Interaction.GetOriginalResponseAsync(); + => this.Interaction.GetOriginalResponseAsync(); } diff --git a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj index 2b807d37a3..379386aada 100644 --- a/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj +++ b/DisCatSharp.ApplicationCommands/DisCatSharp.ApplicationCommands.csproj @@ -1,44 +1,45 @@ + - - - - - - - - - DisCatSharp.ApplicationCommands - DisCatSharp.ApplicationCommands - - - - DisCatSharp.ApplicationCommands - -DisCatSharp Application Commands Extension - -Use it on top of your DisCatSharp powered bot and unleash the power of application commands in discord. - -Documentation: https://docs.dcs.aitsys.dev/articles/modules/application_commands/intro.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Application Commands,Context Menu Commands - annotations - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - + + + + + + + + + DisCatSharp.ApplicationCommands + DisCatSharp.ApplicationCommands + + + + DisCatSharp.ApplicationCommands + + DisCatSharp Application Commands Extension + + Use it on top of your DisCatSharp powered bot and unleash the power of application commands in discord. + + Documentation: https://docs.dcs.aitsys.dev/articles/modules/application_commands/intro.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Application Commands,Context Menu Commands + annotations + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/DisCatSharp.ApplicationCommands/Entities/ChoiceTranslator.cs b/DisCatSharp.ApplicationCommands/Entities/ChoiceTranslator.cs index d1a898aa55..b948b100b6 100644 --- a/DisCatSharp.ApplicationCommands/Entities/ChoiceTranslator.cs +++ b/DisCatSharp.ApplicationCommands/Entities/ChoiceTranslator.cs @@ -22,6 +22,7 @@ internal class ChoiceTranslator /// [JsonProperty("name_translations")] internal Dictionary NameTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization NameTranslations => new(this.NameTranslationsDictionary); diff --git a/DisCatSharp.ApplicationCommands/Entities/CommandTranslator.cs b/DisCatSharp.ApplicationCommands/Entities/CommandTranslator.cs index 70efcf9820..7684cc901c 100644 --- a/DisCatSharp.ApplicationCommands/Entities/CommandTranslator.cs +++ b/DisCatSharp.ApplicationCommands/Entities/CommandTranslator.cs @@ -36,6 +36,7 @@ internal class CommandTranslator /// [JsonProperty("name_translations")] internal Dictionary NameTranslationDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization NameTranslations => new(this.NameTranslationDictionary); @@ -45,6 +46,7 @@ public DiscordApplicationCommandLocalization NameTranslations /// [JsonProperty("description_translations")] internal Dictionary DescriptionTranslationDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization DescriptionTranslations => new(this.DescriptionTranslationDictionary); diff --git a/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs b/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs index 65796d388b..06c915f423 100644 --- a/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs +++ b/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs @@ -101,6 +101,7 @@ internal async Task DecrementUseAsync() Interlocked.Decrement(ref this.RemainingUsesInternal); success = true; } + Console.WriteLine($"[DecrementUseAsync]: Remaining: {this.RemainingUses}/{this.MaxUses} Resets: {this.ResetsAt} Now: {DateTimeOffset.UtcNow} Vars[u,c,g]: {this.UserId} {this.ChannelId} {this.GuildId} Id: {this.BucketId}"); // ...otherwise just fail this.UsageSemaphore.Release(); @@ -119,7 +120,7 @@ internal async Task DecrementUseAsync() /// /// to compare to. /// Whether the is equal to this . - public bool Equals(CooldownBucket other) => other is not null && (ReferenceEquals(this, other) || (this.UserId == other.UserId && this.ChannelId == other.ChannelId && this.GuildId == other.GuildId)); + public bool Equals(CooldownBucket other) => other is not null && (ReferenceEquals(this, other) || this.UserId == other.UserId && this.ChannelId == other.ChannelId && this.GuildId == other.GuildId); /// /// Gets the hash code for this . @@ -138,7 +139,7 @@ internal async Task DecrementUseAsync() var null1 = bucket1 is null; var null2 = bucket2 is null; - return (null1 && null2) || (null1 == null2 && null1.Equals(null2)); + return null1 && null2 || null1 == null2 && null1.Equals(null2); } /// @@ -159,6 +160,4 @@ internal async Task DecrementUseAsync() /// Generated bucket ID. public static string MakeId(ulong userId = 0, ulong channelId = 0, ulong guildId = 0) => $"{userId.ToString(CultureInfo.InvariantCulture)}:{channelId.ToString(CultureInfo.InvariantCulture)}:{guildId.ToString(CultureInfo.InvariantCulture)}"; - - } diff --git a/DisCatSharp.ApplicationCommands/Entities/GroupTranslator.cs b/DisCatSharp.ApplicationCommands/Entities/GroupTranslator.cs index 4b634ca9d3..617483cbb8 100644 --- a/DisCatSharp.ApplicationCommands/Entities/GroupTranslator.cs +++ b/DisCatSharp.ApplicationCommands/Entities/GroupTranslator.cs @@ -36,6 +36,7 @@ internal class GroupTranslator /// [JsonProperty("name_translations")] internal Dictionary NameTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization NameTranslations => new(this.NameTranslationsDictionary); @@ -45,6 +46,7 @@ public DiscordApplicationCommandLocalization NameTranslations /// [JsonProperty("description_translations")] internal Dictionary DescriptionTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization DescriptionTranslations => new(this.DescriptionTranslationsDictionary); diff --git a/DisCatSharp.ApplicationCommands/Entities/OptionTranslator.cs b/DisCatSharp.ApplicationCommands/Entities/OptionTranslator.cs index 67f1cb39dd..907824724d 100644 --- a/DisCatSharp.ApplicationCommands/Entities/OptionTranslator.cs +++ b/DisCatSharp.ApplicationCommands/Entities/OptionTranslator.cs @@ -28,6 +28,7 @@ internal class OptionTranslator /// [JsonProperty("name_translations")] internal Dictionary NameTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization NameTranslations => new(this.NameTranslationsDictionary); @@ -37,6 +38,7 @@ public DiscordApplicationCommandLocalization NameTranslations /// [JsonProperty("description_translations")] internal Dictionary DescriptionTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization DescriptionTranslations => new(this.DescriptionTranslationsDictionary); diff --git a/DisCatSharp.ApplicationCommands/Entities/RegisteredDiscordApplicationCommand.cs b/DisCatSharp.ApplicationCommands/Entities/RegisteredDiscordApplicationCommand.cs index 17091f5a9f..e8df2effb9 100644 --- a/DisCatSharp.ApplicationCommands/Entities/RegisteredDiscordApplicationCommand.cs +++ b/DisCatSharp.ApplicationCommands/Entities/RegisteredDiscordApplicationCommand.cs @@ -43,8 +43,6 @@ internal RegisteredDiscordApplicationCommand(DiscordApplicationCommand parent) this.UnknownProperties = parent.UnknownProperties; this.Version = parent.Version; - - try { if (ApplicationCommandsExtension.CommandMethods.Any(x => x.CommandId == this.Id)) @@ -78,14 +76,12 @@ internal RegisteredDiscordApplicationCommand(DiscordApplicationCommand parent) /// public MethodInfo? CommandMethod { get; internal set; } - /// /// The type that contains the sub commands of this command. /// if command is not a group command or reflection failed. /// public Type? CommandType { get; internal set; } - /// /// The type this command is contained in. /// if reflection failed. diff --git a/DisCatSharp.ApplicationCommands/Entities/SubGroupTranslator.cs b/DisCatSharp.ApplicationCommands/Entities/SubGroupTranslator.cs index c8a0217827..cdf445713b 100644 --- a/DisCatSharp.ApplicationCommands/Entities/SubGroupTranslator.cs +++ b/DisCatSharp.ApplicationCommands/Entities/SubGroupTranslator.cs @@ -28,6 +28,7 @@ internal class SubGroupTranslator /// [JsonProperty("name_translations")] internal Dictionary NameTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization NameTranslations => new(this.NameTranslationsDictionary); @@ -37,6 +38,7 @@ public DiscordApplicationCommandLocalization NameTranslations /// [JsonProperty("description_translations")] internal Dictionary DescriptionTranslationsDictionary { get; set; } + [JsonIgnore] public DiscordApplicationCommandLocalization DescriptionTranslations => new(this.DescriptionTranslationsDictionary); diff --git a/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandFinalType.cs b/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandFinalType.cs index 7d74f50bea..d7ddaef748 100644 --- a/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandFinalType.cs +++ b/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandFinalType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.ApplicationCommands.Enums; internal enum ApplicationCommandFinalType diff --git a/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandModuleLifespan.cs b/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandModuleLifespan.cs index 8120f80099..b00d3f4628 100644 --- a/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandModuleLifespan.cs +++ b/DisCatSharp.ApplicationCommands/Enums/ApplicationCommandModuleLifespan.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.ApplicationCommands.Enums; /// diff --git a/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs b/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs index 38956db7ca..fb0a269dd4 100644 --- a/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs +++ b/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.ApplicationCommands.Enums; /// @@ -6,7 +5,6 @@ namespace DisCatSharp.ApplicationCommands.Enums; /// public enum CooldownBucketType : int { - /// /// Denotes that the command will have its cooldown applied globally. /// diff --git a/DisCatSharp.ApplicationCommands/ExtensionMethods.cs b/DisCatSharp.ApplicationCommands/ExtensionMethods.cs index 64a9718007..f78720d5e9 100644 --- a/DisCatSharp.ApplicationCommands/ExtensionMethods.cs +++ b/DisCatSharp.ApplicationCommands/ExtensionMethods.cs @@ -20,8 +20,10 @@ public static class ExtensionMethods /// Client to enable application commands for. /// Configuration to use. /// Created . - public static ApplicationCommandsExtension UseApplicationCommands(this DiscordClient client, - ApplicationCommandsConfiguration config = null) + public static ApplicationCommandsExtension UseApplicationCommands( + this DiscordClient client, + ApplicationCommandsConfiguration config = null + ) { if (client.GetExtension() != null) throw new InvalidOperationException("Application commands are already enabled for that client."); @@ -75,6 +77,7 @@ public static void RegisterGlobalCommands(this IReadOnlyDictionary(this IReadOnlyDictionary(guildId, translationSetup); - } /// @@ -104,6 +106,7 @@ public static void RegisterGuildCommands(this IReadOnlyDictionary(this T e) where T : IConvertible var values = Enum.GetValues(type); foreach (int val in values) - { if (val == e.ToInt32(CultureInfo.InvariantCulture)) { var memInfo = type.GetMember(type.GetEnumName(val)); return memInfo[0] .GetCustomAttributes(typeof(ChoiceNameAttribute), false) - .FirstOrDefault() is ChoiceNameAttribute nameAttribute ? nameAttribute.Name : type.GetEnumName(val); + .FirstOrDefault() is ChoiceNameAttribute nameAttribute + ? nameAttribute.Name + : type.GetEnumName(val); } - } } + return null; } } diff --git a/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs b/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs index 3094fdd3b9..439f129016 100644 --- a/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs +++ b/DisCatSharp.ApplicationCommands/Workers/ApplicationCommandWorker.cs @@ -27,18 +27,17 @@ internal class CommandWorker /// Too much. internal static Task< ( - List applicationCommands, - List> commandTypeSources, - List contextMenuCommands, - bool withLocalization + List applicationCommands, + List> commandTypeSources, + List contextMenuCommands, + bool withLocalization ) - > ParseContextMenuCommands(Type type, IEnumerable methods, List translator = null) + > ParseContextMenuCommands(Type type, IEnumerable methods, List translator = null) { List commands = new(); List> commandTypeSources = new(); List contextMenuCommands = new(); - foreach (var contextMethod in methods) { var contextAttribute = contextMethod.GetCustomAttribute(); @@ -49,7 +48,7 @@ bool withLocalization if (commandTranslation != null) nameLocalizations = commandTranslation.NameTranslations; - var command = new DiscordApplicationCommand(contextAttribute.Name, null, null, contextAttribute.Type, nameLocalizations, null, contextAttribute.DefaultMemberPermissions, contextAttribute.DmPermission ?? true, isNsfw: contextAttribute.IsNsfw, allowedContexts: contextAttribute.AllowedContexts, integrationTypes: contextAttribute.IntegrationTypes); + var command = new DiscordApplicationCommand(contextAttribute.Name, null, null, contextAttribute.Type, nameLocalizations, null, contextAttribute.DefaultMemberPermissions, contextAttribute.DmPermission ?? true, contextAttribute.IsNsfw, contextAttribute.AllowedContexts, contextAttribute.IntegrationTypes); var parameters = contextMethod.GetParameters(); if (parameters.Length == 0 || parameters == null || !ReferenceEquals(parameters.FirstOrDefault()?.ParameterType, typeof(ContextMenuContext))) @@ -57,10 +56,13 @@ bool withLocalization if (parameters.Length > 1) throw new ArgumentException($"The context menu command '{contextAttribute.Name}' cannot have parameters!"); - contextMenuCommands.Add(new ContextMenuCommand { Method = contextMethod, Name = contextAttribute.Name }); + contextMenuCommands.Add(new() + { + Method = contextMethod, Name = contextAttribute.Name + }); commands.Add(command); - commandTypeSources.Add(new KeyValuePair(type, type)); + commandTypeSources.Add(new(type, type)); } return Task.FromResult((commands, commandTypeSources, contextMenuCommands, translator != null)); @@ -76,19 +78,18 @@ bool withLocalization /// Too much. internal static async Task< ( - List applicationCommands, - List> commandTypeSources, - List commandMethods, - bool withLocalization + List applicationCommands, + List> commandTypeSources, + List commandMethods, + bool withLocalization ) - > ParseBasicSlashCommandsAsync(Type type, IEnumerable methods, ulong? guildId = null, List translator = null) + > ParseBasicSlashCommandsAsync(Type type, IEnumerable methods, ulong? guildId = null, List translator = null) { List commands = new(); List> commandTypeSources = new(); List commandMethods = new(); foreach (var method in methods) - { try { var commandAttribute = method.GetCustomAttribute(); @@ -96,9 +97,13 @@ bool withLocalization var parameters = method.GetParameters(); if (parameters.Length == 0 || parameters == null || !ReferenceEquals(parameters.FirstOrDefault()?.ParameterType, typeof(InteractionContext))) throw new ArgumentException($"The first argument of the command '{commandAttribute.Name}' has to be an InteractionContext!"); + var options = await ApplicationCommandsExtension.ParseParametersAsync(parameters.Skip(1), commandAttribute.Name, guildId).ConfigureAwait(false); - commandMethods.Add(new CommandMethod { Method = method, Name = commandAttribute.Name }); + commandMethods.Add(new() + { + Method = method, Name = commandAttribute.Name + }); DiscordApplicationCommandLocalization nameLocalizations = null; DiscordApplicationCommandLocalization descriptionLocalizations = null; @@ -108,9 +113,8 @@ bool withLocalization if (commandTranslation != null && commandTranslation.Options != null) { - localizedOptions = new List(options.Count); + localizedOptions = new(options.Count); foreach (var option in options) - { try { var choices = option.Choices != null ? new List(option.Choices.Count) : null; @@ -118,14 +122,14 @@ bool withLocalization foreach (var choice in option.Choices) try { - choices.Add(new DiscordApplicationCommandOptionChoice(choice.Name, choice.Value, commandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); + choices.Add(new(choice.Name, choice.Value, commandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); } catch (Exception ex) { throw new AggregateException($"Failed to register choice '{choice.Name}' in command '{commandAttribute.Name}'", ex); } - localizedOptions.Add(new DiscordApplicationCommandOption(option.Name, option.Description, option.Type, option.Required, + localizedOptions.Add(new(option.Name, option.Description, option.Type, option.Required, choices, option.Options, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue, commandTranslation.Options.Single(o => o.Name == option.Name).NameTranslations, commandTranslation.Options.Single(o => o.Name == option.Name).DescriptionTranslations, option.MinimumLength, option.MaximumLength @@ -135,21 +139,20 @@ bool withLocalization { throw new AggregateException($"Failed to register option '{option.Name}' in command '{commandAttribute.Name}'", ex); } - } nameLocalizations = commandTranslation.NameTranslations; descriptionLocalizations = commandTranslation.DescriptionTranslations; } - var payload = new DiscordApplicationCommand(commandAttribute.Name, commandAttribute.Description, (localizedOptions != null && localizedOptions.Any() ? localizedOptions : null) ?? (options != null && options.Any() ? options : null), ApplicationCommandType.ChatInput, nameLocalizations, descriptionLocalizations, commandAttribute.DefaultMemberPermissions, commandAttribute.DmPermission ?? true, isNsfw: commandAttribute.IsNsfw, allowedContexts: commandAttribute.AllowedContexts, integrationTypes: commandAttribute.IntegrationTypes); + var payload = new DiscordApplicationCommand(commandAttribute.Name, commandAttribute.Description, (localizedOptions != null && localizedOptions.Any() ? localizedOptions : null) ?? (options != null && options.Any() ? options : null), ApplicationCommandType.ChatInput, nameLocalizations, descriptionLocalizations, commandAttribute.DefaultMemberPermissions, commandAttribute.DmPermission ?? true, + commandAttribute.IsNsfw, commandAttribute.AllowedContexts, commandAttribute.IntegrationTypes); commands.Add(payload); - commandTypeSources.Add(new KeyValuePair(type, type)); + commandTypeSources.Add(new(type, type)); } catch (Exception ex) { throw new AggregateException($"Failed to register command with method name '{method.Name}'", ex); } - } return (commands, commandTypeSources, commandMethods, translator != null); } @@ -170,14 +173,14 @@ internal class NestedCommandWorker /// Too much. internal static async Task< ( - List applicationCommands, - List> commandTypeSources, - List singletonModules, - List groupCommands, - List subGroupCommands, - bool withLocalization + List applicationCommands, + List> commandTypeSources, + List singletonModules, + List groupCommands, + List subGroupCommands, + bool withLocalization ) - > ParseSlashGroupsAsync(Type type, List types, ulong? guildId = null, List translator = null) + > ParseSlashGroupsAsync(Type type, List types, ulong? guildId = null, List translator = null) { List commands = new(); List> commandTypeSources = new(); @@ -207,7 +210,8 @@ bool withLocalization } //Initializes the command - var payload = new DiscordApplicationCommand(groupAttribute.Name, groupAttribute.Description, nameLocalizations: nameLocalizations, descriptionLocalizations: descriptionLocalizations, defaultMemberPermissions: groupAttribute.DefaultMemberPermissions, dmPermission: groupAttribute.DmPermission ?? true, isNsfw: groupAttribute.IsNsfw, allowedContexts: groupAttribute.AllowedContexts, integrationTypes: groupAttribute.IntegrationTypes); + var payload = new DiscordApplicationCommand(groupAttribute.Name, groupAttribute.Description, nameLocalizations: nameLocalizations, descriptionLocalizations: descriptionLocalizations, defaultMemberPermissions: groupAttribute.DefaultMemberPermissions, dmPermission: groupAttribute.DmPermission ?? true, isNsfw: groupAttribute.IsNsfw, allowedContexts: groupAttribute.AllowedContexts, + integrationTypes: groupAttribute.IntegrationTypes); commandTypeSources.Add(new(type, type)); var commandMethods = new List>(); @@ -231,19 +235,18 @@ bool withLocalization if (commandTranslation?.Commands != null) { - var subCommandTranslation = commandTranslation.Commands.Single(sc => sc.Name == commandAttribute.Name); if (subCommandTranslation.Options != null) { - localizedOptions = new List(options.Count); + localizedOptions = new(options.Count); foreach (var option in options) { var choices = option.Choices != null ? new List(option.Choices.Count) : null; if (option.Choices != null) foreach (var choice in option.Choices) - choices.Add(new DiscordApplicationCommandOptionChoice(choice.Name, choice.Value, subCommandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); + choices.Add(new(choice.Name, choice.Value, subCommandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); - localizedOptions.Add(new DiscordApplicationCommandOption(option.Name, option.Description, option.Type, option.Required, + localizedOptions.Add(new(option.Name, option.Description, option.Type, option.Required, choices, option.Options, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue, subCommandTranslation.Options.Single(o => o.Name == option.Name).NameTranslations, subCommandTranslation.Options.Single(o => o.Name == option.Name).DescriptionTranslations, option.MinimumLength, option.MaximumLength @@ -255,18 +258,26 @@ bool withLocalization subDescriptionLocalizations = subCommandTranslation.DescriptionTranslations; } - //Creates the subcommand and adds it to the main command var subpayload = new DiscordApplicationCommandOption(commandAttribute.Name, commandAttribute.Description, ApplicationCommandOptionType.SubCommand, false, null, localizedOptions ?? options, nameLocalizations: subNameLocalizations, descriptionLocalizations: subDescriptionLocalizations); - payload = new(payload.Name, payload.Description, payload.Options?.Append(subpayload) ?? new[] { subpayload }, nameLocalizations: payload.NameLocalizations, descriptionLocalizations: payload.DescriptionLocalizations, defaultMemberPermissions: payload.DefaultMemberPermissions, dmPermission: payload.DmPermission ?? true, isNsfw: payload.IsNsfw, allowedContexts: payload.AllowedContexts, integrationTypes: payload.IntegrationTypes); + payload = new(payload.Name, payload.Description, payload.Options?.Append(subpayload) ?? new[] + { + subpayload + }, nameLocalizations: payload.NameLocalizations, descriptionLocalizations: payload.DescriptionLocalizations, defaultMemberPermissions: payload.DefaultMemberPermissions, dmPermission: payload.DmPermission ?? true, isNsfw: payload.IsNsfw, allowedContexts: payload.AllowedContexts, integrationTypes: payload.IntegrationTypes); commandTypeSources.Add(new(subclassInfo, type)); //Adds it to the method lists - commandMethods.Add(new KeyValuePair(commandAttribute.Name, submethod)); - groupCommands.Add(new GroupCommand { Name = groupAttribute.Name, Methods = commandMethods }); + commandMethods.Add(new(commandAttribute.Name, submethod)); + groupCommands.Add(new() + { + Name = groupAttribute.Name, Methods = commandMethods + }); } - var command = new SubGroupCommand { Name = groupAttribute.Name }; + var command = new SubGroupCommand + { + Name = groupAttribute.Name + }; //Handles subgroups foreach (var subclass in subclasses) { @@ -277,7 +288,6 @@ bool withLocalization var currentMethods = new List>(); - DiscordApplicationCommandLocalization subNameLocalizations = null; DiscordApplicationCommandLocalization subDescriptionLocalizations = null; @@ -286,7 +296,6 @@ bool withLocalization var commandTranslation = translator.Single(c => c.Name == payload.Name); if (commandTranslation != null && commandTranslation.SubGroups != null) { - var subCommandTranslation = commandTranslation.SubGroups.Single(sc => sc.Name == subgroupAttribute.Name); if (subCommandTranslation != null) @@ -320,15 +329,15 @@ bool withLocalization if (subSubCommandTranslation != null && subSubCommandTranslation.Options != null) { - localizedOptions = new List(suboptions.Count); + localizedOptions = new(suboptions.Count); foreach (var option in suboptions) { var choices = option.Choices != null ? new List(option.Choices.Count) : null; if (option.Choices != null) foreach (var choice in option.Choices) - choices.Add(new DiscordApplicationCommandOptionChoice(choice.Name, choice.Value, subSubCommandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); + choices.Add(new(choice.Name, choice.Value, subSubCommandTranslation.Options.Single(o => o.Name == option.Name).Choices.Single(c => c.Name == choice.Name).NameTranslations)); - localizedOptions.Add(new DiscordApplicationCommandOption(option.Name, option.Description, option.Type, option.Required, + localizedOptions.Add(new(option.Name, option.Description, option.Type, option.Required, choices, option.Options, option.ChannelTypes, option.AutoComplete, option.MinimumValue, option.MaximumValue, subSubCommandTranslation.Options.Single(o => o.Name == option.Name).NameTranslations, subSubCommandTranslation.Options.Single(o => o.Name == option.Name).DescriptionTranslations, option.MinimumLength, option.MaximumLength @@ -341,20 +350,27 @@ bool withLocalization var subsubpayload = new DiscordApplicationCommandOption(commatt.Name, commatt.Description, ApplicationCommandOptionType.SubCommand, false, null, (localizedOptions != null && localizedOptions.Any() ? localizedOptions : null) ?? (suboptions != null && suboptions.Any() ? suboptions : null), nameLocalizations: subSubNameLocalizations, descriptionLocalizations: subSubDescriptionLocalizations); options.Add(subsubpayload); - commandMethods.Add(new KeyValuePair(commatt.Name, subsubmethod)); - currentMethods.Add(new KeyValuePair(commatt.Name, subsubmethod)); + commandMethods.Add(new(commatt.Name, subsubmethod)); + currentMethods.Add(new(commatt.Name, subsubmethod)); } //Adds the group to the command and method lists var subpayload = new DiscordApplicationCommandOption(subgroupAttribute.Name, subgroupAttribute.Description, ApplicationCommandOptionType.SubCommandGroup, false, null, options, nameLocalizations: subNameLocalizations, descriptionLocalizations: subDescriptionLocalizations); - command.SubCommands.Add(new() { Name = subgroupAttribute.Name, Methods = currentMethods }); - payload = new(payload.Name, payload.Description, payload.Options?.Append(subpayload) ?? new[] { subpayload }, nameLocalizations: payload.NameLocalizations, descriptionLocalizations: payload.DescriptionLocalizations, defaultMemberPermissions: payload.DefaultMemberPermissions, dmPermission: payload.DmPermission ?? true, isNsfw: payload.IsNsfw, allowedContexts: payload.AllowedContexts, integrationTypes: payload.IntegrationTypes); + command.SubCommands.Add(new() + { + Name = subgroupAttribute.Name, Methods = currentMethods + }); + payload = new(payload.Name, payload.Description, payload.Options?.Append(subpayload) ?? new[] + { + subpayload + }, nameLocalizations: payload.NameLocalizations, descriptionLocalizations: payload.DescriptionLocalizations, defaultMemberPermissions: payload.DefaultMemberPermissions, dmPermission: payload.DmPermission ?? true, isNsfw: payload.IsNsfw, allowedContexts: payload.AllowedContexts, integrationTypes: payload.IntegrationTypes); commandTypeSources.Add(new(subclass, type)); //Accounts for lifespans for the sub group if (subclass.GetCustomAttribute() != null && subclass.GetCustomAttribute().Lifespan == ApplicationCommandModuleLifespan.Singleton) singletonModules.Add(ApplicationCommandsExtension.CreateInstance(subclass, ApplicationCommandsExtension.Configuration?.ServiceProvider)); } + if (command.SubCommands.Any()) subGroupCommands.Add(command); commands.Add(payload); diff --git a/DisCatSharp.ApplicationCommands/Workers/RegistrationWorker.cs b/DisCatSharp.ApplicationCommands/Workers/RegistrationWorker.cs index 5929735fe7..1c1b390225 100644 --- a/DisCatSharp.ApplicationCommands/Workers/RegistrationWorker.cs +++ b/DisCatSharp.ApplicationCommands/Workers/RegistrationWorker.cs @@ -47,7 +47,7 @@ internal static async Task> RegisterGlobalComman action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); action.DefaultMemberPermissions = command.DefaultMemberPermissions; action.DmPermission = command.DmPermission ?? true; @@ -80,12 +80,12 @@ internal static async Task> RegisterGlobalComman action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); action.DefaultMemberPermissions = command.DefaultMemberPermissions; action.DmPermission = command.DmPermission ?? true; action.IsNsfw = command.IsNsfw; - action.AllowedContexts = command.AllowedContexts; + action.AllowedContexts = command.AllowedContexts; }).ConfigureAwait(false); commands.Add(discordBackendCommand); @@ -107,7 +107,7 @@ internal static async Task> RegisterGlobalComman action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); action.DefaultMemberPermissions = command.DefaultMemberPermissions; action.DmPermission = command.DmPermission ?? true; @@ -131,6 +131,7 @@ internal static async Task> RegisterGlobalComman cmd.Id = overwrite.Key; overwriteList.Add(cmd); } + var discordBackendCommands = await client.BulkOverwriteGlobalApplicationCommandsAsync(overwriteList).ConfigureAwait(false); commands.AddRange(discordBackendCommands); } @@ -198,7 +199,7 @@ internal static async Task> RegisterGuildCommand action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); action.DefaultMemberPermissions = command.DefaultMemberPermissions; action.DmPermission = command.DmPermission ?? true; @@ -231,7 +232,7 @@ internal static async Task> RegisterGuildCommand action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); action.DefaultMemberPermissions = command.DefaultMemberPermissions; action.DmPermission = command.DmPermission ?? true; @@ -258,7 +259,7 @@ internal static async Task> RegisterGuildCommand action.NameLocalizations = command.NameLocalizations; action.Description = command.Description; action.DescriptionLocalizations = command.DescriptionLocalizations; - if(command.Options != null && command.Options.Any()) + if (command.Options != null && command.Options.Any()) action.Options = Optional.Some(command.Options); if (command.DefaultMemberPermissions.HasValue) action.DefaultMemberPermissions = command.DefaultMemberPermissions.Value; @@ -284,6 +285,7 @@ internal static async Task> RegisterGuildCommand cmd.Id = overwrite.Key; overwriteList.Add(cmd); } + var discordBackendCommands = await client.BulkOverwriteGuildApplicationCommandsAsync(guildId, overwriteList).ConfigureAwait(false); commands.AddRange(discordBackendCommands); } @@ -327,9 +329,8 @@ internal static async Task> RegisterGuildCommand /// A list of command ids. private static List BuildGuildDeleteList(DiscordClient client, ulong guildId, List updateList) { - if (ApplicationCommandsExtension.GuildDiscordCommands == null || !ApplicationCommandsExtension.GuildDiscordCommands.Any() - || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) + || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) ) return null; @@ -358,9 +359,8 @@ private static List BuildGuildDeleteList(DiscordClient client, ulong guil /// private static List BuildGuildCreateList(DiscordClient client, ulong guildId, List updateList) { - if (ApplicationCommandsExtension.GuildDiscordCommands == null || !ApplicationCommandsExtension.GuildDiscordCommands.Any() - || updateList == null || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) + || updateList == null || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) ) return updateList; @@ -384,14 +384,13 @@ private static List BuildGuildCreateList(DiscordClien /// The command list. /// A dictionary of command id and command. private static ( - Dictionary changedCommands, - List unchangedCommands + Dictionary changedCommands, + List unchangedCommands ) BuildGuildOverwriteList(DiscordClient client, ulong guildId, List updateList) { - if (ApplicationCommandsExtension.GuildDiscordCommands == null || !ApplicationCommandsExtension.GuildDiscordCommands.Any() - || ApplicationCommandsExtension.GuildDiscordCommands.All(l => l.Key != guildId) || updateList == null - || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) + || ApplicationCommandsExtension.GuildDiscordCommands.All(l => l.Key != guildId) || updateList == null + || !ApplicationCommandsExtension.GuildDiscordCommands.TryGetFirstValueByKey(guildId, out var discord) ) return (null, null); @@ -483,8 +482,8 @@ private static List BuildGlobalCreateList(DiscordClie /// The command list. /// A dictionary of command ids and commands. private static ( - Dictionary changedCommands, - List unchangedCommands + Dictionary changedCommands, + List unchangedCommands ) BuildGlobalOverwriteList(DiscordClient client, List updateList) { if (ApplicationCommandsExtension.GlobalDiscordCommands == null || !ApplicationCommandsExtension.GlobalDiscordCommands.Any() || updateList == null) diff --git a/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs b/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs index 700ec7c19b..a364d7ead3 100644 --- a/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs @@ -43,7 +43,7 @@ public CooldownAttribute(int maxUses, double resetAfter, CooldownBucketType buck this.MaxUses = maxUses; this.Reset = TimeSpan.FromSeconds(resetAfter); this.BucketType = bucketType; - this._buckets = new ConcurrentDictionary(); + this._buckets = new(); } /// @@ -66,7 +66,11 @@ public CommandCooldownBucket GetBucket(CommandContext ctx) public TimeSpan GetRemainingCooldown(CommandContext ctx) { var bucket = this.GetBucket(ctx); - return bucket == null ? TimeSpan.Zero : bucket.RemainingUses > 0 ? TimeSpan.Zero : bucket.ResetsAt - DateTimeOffset.UtcNow; + return bucket == null + ? TimeSpan.Zero + : bucket.RemainingUses > 0 + ? TimeSpan.Zero + : bucket.ResetsAt - DateTimeOffset.UtcNow; } /// @@ -110,7 +114,7 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld); if (!this._buckets.TryGetValue(bid, out var bucket)) { - bucket = new CommandCooldownBucket(this.MaxUses, this.Reset, usr, chn, gld); + bucket = new(this.MaxUses, this.Reset, usr, chn, gld); this._buckets.AddOrUpdate(bid, bucket, (k, v) => bucket); } @@ -215,7 +219,7 @@ internal CommandCooldownBucket(int maxUses, TimeSpan resetAfter, ulong userId = this.ChannelId = channelId; this.GuildId = guildId; this.BucketId = MakeId(userId, channelId, guildId); - this._usageSemaphore = new SemaphoreSlim(1, 1); + this._usageSemaphore = new(1, 1); } /// @@ -267,7 +271,7 @@ internal async Task DecrementUseAsync() /// /// to compare to. /// Whether the is equal to this . - public bool Equals(CommandCooldownBucket other) => other is not null && (ReferenceEquals(this, other) || (this.UserId == other.UserId && this.ChannelId == other.ChannelId && this.GuildId == other.GuildId)); + public bool Equals(CommandCooldownBucket other) => other is not null && (ReferenceEquals(this, other) || this.UserId == other.UserId && this.ChannelId == other.ChannelId && this.GuildId == other.GuildId); /// /// Gets the hash code for this . @@ -286,7 +290,7 @@ internal async Task DecrementUseAsync() var null1 = bucket1 is null; var null2 = bucket2 is null; - return (null1 && null2) || (null1 == null2 && null1.Equals(null2)); + return null1 && null2 || null1 == null2 && null1.Equals(null2); } /// diff --git a/DisCatSharp.CommandsNext/Attributes/RequireBoostingAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireBoostingAttribute.cs index 09455ebcba..5a973b1699 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireBoostingAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireBoostingAttribute.cs @@ -54,8 +54,6 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help return member != null && member.PremiumSince.HasValue ? await Task.FromResult(member.PremiumSince.Value.UtcDateTime.Date < DateTime.UtcNow.Date.AddDays(-this.Since)).ConfigureAwait(false) : await Task.FromResult(false).ConfigureAwait(false); } else - { return ctx.Member != null && ctx.Member.PremiumSince.HasValue ? await Task.FromResult(ctx.Member.PremiumSince.Value.UtcDateTime.Date < DateTime.UtcNow.Date.AddDays(-this.Since)).ConfigureAwait(false) : await Task.FromResult(false).ConfigureAwait(false); - } } } diff --git a/DisCatSharp.CommandsNext/Attributes/RequireBotPermissionsAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireBotPermissionsAttribute.cs index 86ccad62a2..5eb25b54a7 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireBotPermissionsAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireBotPermissionsAttribute.cs @@ -51,9 +51,7 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help var channel = ctx.Channel; if (ctx.Channel.GuildId == null) - { channel = await ctx.Client.GetChannelAsync(ctx.Channel.Id, true).ConfigureAwait(false); - } var pbot = channel.PermissionsFor(bot); return (pbot & Permissions.Administrator) != 0 || (pbot & this.Permissions) == this.Permissions; diff --git a/DisCatSharp.CommandsNext/Attributes/RequireDirectMessageAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireDirectMessageAttribute.cs index 42a5dbfbb9..afc7653882 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireDirectMessageAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireDirectMessageAttribute.cs @@ -8,7 +8,6 @@ namespace DisCatSharp.CommandsNext.Attributes; /// /// Defines that a command is only usable within a direct message channel. /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false)] public sealed class RequireDirectMessageAttribute : CheckBaseAttribute { diff --git a/DisCatSharp.CommandsNext/Attributes/RequireGuildOwnerAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireGuildOwnerAttribute.cs index d23c98774f..3dc28080cc 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireGuildOwnerAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireGuildOwnerAttribute.cs @@ -24,8 +24,6 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help return owner; } else - { return false; - } } } diff --git a/DisCatSharp.CommandsNext/Attributes/RequireOwnerOrIdAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireOwnerOrIdAttribute.cs index eecb79da75..f1f3f95f29 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireOwnerOrIdAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireOwnerOrIdAttribute.cs @@ -41,6 +41,5 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help var allowed = this.UserIds.Contains(ctx.User.Id); return owner || allowed; - } } diff --git a/DisCatSharp.CommandsNext/Attributes/RequirePermissionsAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequirePermissionsAttribute.cs index d386a58ef8..6162662401 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequirePermissionsAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequirePermissionsAttribute.cs @@ -44,18 +44,18 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help var channel = ctx.Channel; if (ctx.Channel.GuildId == null) - { channel = await ctx.Client.GetChannelAsync(ctx.Channel.Id, true).ConfigureAwait(false); - } var usr = ctx.Member; if (usr == null) return false; + var pusr = channel.PermissionsFor(usr); var bot = await ctx.Guild.GetMemberAsync(ctx.Client.CurrentUser.Id).ConfigureAwait(false); if (bot == null) return false; + var pbot = channel.PermissionsFor(bot); var usrok = ctx.Guild.OwnerId == usr.Id; diff --git a/DisCatSharp.CommandsNext/Attributes/RequirePrefixesAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequirePrefixesAttribute.cs index 800134bca8..b87d2fbff3 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequirePrefixesAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequirePrefixesAttribute.cs @@ -39,5 +39,5 @@ public RequirePrefixesAttribute(params string[] prefixes) /// The command context. /// If true, help - returns true. public override Task ExecuteCheckAsync(CommandContext ctx, bool help) - => Task.FromResult((help && this.ShowInHelp) || this.Prefixes.Contains(ctx.Prefix, ctx.CommandsNext.GetStringComparer())); + => Task.FromResult(help && this.ShowInHelp || this.Prefixes.Contains(ctx.Prefix, ctx.CommandsNext.GetStringComparer())); } diff --git a/DisCatSharp.CommandsNext/Attributes/RequireRolesAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireRolesAttribute.cs index bb5e2c0441..2d15877003 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireRolesAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireRolesAttribute.cs @@ -53,7 +53,7 @@ public override Task ExecuteCheckAsync(CommandContext ctx, bool help) RoleCheckMode.All => Task.FromResult(this.RoleNames.Count == inc), RoleCheckMode.SpecifiedOnly => Task.FromResult(rnc == inc), RoleCheckMode.None => Task.FromResult(inc == 0), - _ => Task.FromResult(inc > 0), + _ => Task.FromResult(inc > 0) }; } } diff --git a/DisCatSharp.CommandsNext/Attributes/RequireUserPermissionsAttribute.cs b/DisCatSharp.CommandsNext/Attributes/RequireUserPermissionsAttribute.cs index 8ce5eca6f0..ed746133e7 100644 --- a/DisCatSharp.CommandsNext/Attributes/RequireUserPermissionsAttribute.cs +++ b/DisCatSharp.CommandsNext/Attributes/RequireUserPermissionsAttribute.cs @@ -25,7 +25,6 @@ public sealed class RequireUserPermissionsAttribute : CheckBaseAttribute /// Defines that usage of this command is restricted to members with specified permissions. /// /// Permissions required to execute this command. - /// Sets this check's behaviour in DMs. True means the check will always pass in DMs, whereas false means that it will always fail. public RequireUserPermissionsAttribute(Permissions permissions, bool ignoreDms = true) { diff --git a/DisCatSharp.CommandsNext/CommandsNextExtension.cs b/DisCatSharp.CommandsNext/CommandsNextExtension.cs index 1537e483a0..90c7f14ac7 100644 --- a/DisCatSharp.CommandsNext/CommandsNextExtension.cs +++ b/DisCatSharp.CommandsNext/CommandsNextExtension.cs @@ -43,6 +43,7 @@ public class CommandsNextExtension : BaseExtension /// Gets the user friendly type names. /// private readonly Dictionary _userFriendlyTypeNames; + /// /// Gets the argument converters. /// @@ -60,13 +61,13 @@ public IServiceProvider Services /// The cfg. internal CommandsNextExtension(CommandsNextConfiguration cfg) { - this._config = new CommandsNextConfiguration(cfg); - this._topLevelCommands = new Dictionary(); - this._registeredCommandsLazy = new Lazy>(() => new ReadOnlyDictionary(this._topLevelCommands)); - this._helpFormatter = new HelpFormatterFactory(); + this._config = new(cfg); + this._topLevelCommands = new(); + this._registeredCommandsLazy = new(() => new ReadOnlyDictionary(this._topLevelCommands)); + this._helpFormatter = new(); this._helpFormatter.SetFormatterType(); - this.ArgumentConverters = new Dictionary + this.ArgumentConverters = new() { [typeof(string)] = new StringConverter(), [typeof(bool)] = new BoolConverter(), @@ -95,10 +96,10 @@ internal CommandsNextExtension(CommandsNextConfiguration cfg) [typeof(DiscordThreadChannel)] = new DiscordThreadChannelConverter(), [typeof(DiscordInvite)] = new DiscordInviteConverter(), [typeof(DiscordColor)] = new DiscordColorConverter(), - [typeof(DiscordScheduledEvent)] = new DiscordScheduledEventConverter(), + [typeof(DiscordScheduledEvent)] = new DiscordScheduledEventConverter() }; - this._userFriendlyTypeNames = new Dictionary() + this._userFriendlyTypeNames = new() { [typeof(string)] = "string", [typeof(bool)] = "boolean", @@ -158,7 +159,8 @@ internal CommandsNextExtension(CommandsNextConfiguration cfg) /// Type of the formatter to use. public void SetHelpFormatter() where T : BaseHelpFormatter => this._helpFormatter.SetFormatterType(); - #region DiscordClient Registration +#region DiscordClient Registration + /// /// DO NOT USE THIS MANUALLY. /// @@ -171,8 +173,8 @@ protected internal override void Setup(DiscordClient client) this.Client = client; - this._executed = new AsyncEvent("COMMAND_EXECUTED", TimeSpan.Zero, this.Client.EventErrorHandler); - this._error = new AsyncEvent("COMMAND_ERRORED", TimeSpan.Zero, this.Client.EventErrorHandler); + this._executed = new("COMMAND_EXECUTED", TimeSpan.Zero, this.Client.EventErrorHandler); + this._error = new("COMMAND_ERRORED", TimeSpan.Zero, this.Client.EventErrorHandler); if (this._config.UseDefaultCommandHandler) this.Client.MessageCreated += this.HandleCommandsAsync; @@ -195,11 +197,12 @@ protected internal override void Setup(DiscordClient client) foreach (var xc in tcmds) this.AddToCommandDictionary(xc.Build(null)); } - } - #endregion - #region Command Handling +#endregion + +#region Command Handling + /// /// Handles the commands async. /// @@ -239,7 +242,10 @@ private async Task HandleCommandsAsync(DiscordClient sender, MessageCreateEventA var ctx = this.CreateContext(e.Message, pfx, cmd, args); if (cmd == null) { - await this._error.InvokeAsync(this, new CommandErrorEventArgs(this.Client.ServiceProvider) { Context = ctx, Exception = new CommandNotFoundException(fname) }).ConfigureAwait(false); + await this._error.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = ctx, Exception = new CommandNotFoundException(fname) + }).ConfigureAwait(false); return; } @@ -295,9 +301,7 @@ public Command FindCommand(string commandString, out string rawArguments) cmd = cm2.Children.FirstOrDefault(x => x.Name.ToLowerInvariant() == next || x.Aliases?.Any(xx => xx.ToLowerInvariant() == next) == true); } else - { cmd = cm2.Children.FirstOrDefault(x => x.Name == next || x.Aliases?.Contains(next) == true); - } if (cmd == null) { @@ -336,7 +340,7 @@ public CommandContext CreateContext(DiscordMessage msg, string prefix, Command c if (cmd != null && (cmd.Module is TransientCommandModule || cmd.Module == null)) { var scope = ctx.Services.CreateScope(); - ctx.ServiceScopeContext = new CommandContext.ServiceContext(ctx.Services, scope); + ctx.ServiceScopeContext = new(ctx.Services, scope); ctx.Services = scope.ServiceProvider; } @@ -358,13 +362,22 @@ public async Task ExecuteCommandAsync(CommandContext ctx) var res = await cmd.ExecuteAsync(ctx).ConfigureAwait(false); if (res.IsSuccessful) - await this._executed.InvokeAsync(this, new CommandExecutionEventArgs(this.Client.ServiceProvider) { Context = res.Context }).ConfigureAwait(false); + await this._executed.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = res.Context + }).ConfigureAwait(false); else - await this._error.InvokeAsync(this, new CommandErrorEventArgs(this.Client.ServiceProvider) { Context = res.Context, Exception = res.Exception }).ConfigureAwait(false); + await this._error.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = res.Context, Exception = res.Exception + }).ConfigureAwait(false); } catch (Exception ex) { - await this._error.InvokeAsync(this, new CommandErrorEventArgs(this.Client.ServiceProvider) { Context = ctx, Exception = ex }).ConfigureAwait(false); + await this._error.InvokeAsync(this, new(this.Client.ServiceProvider) + { + Context = ctx, Exception = ex + }).ConfigureAwait(false); } finally { @@ -388,9 +401,11 @@ private async Task RunAllChecksAsync(Command cmd, CommandContext ctx) if (fchecks.Any()) throw new ChecksFailedException(cmd, ctx, fchecks); } - #endregion - #region Command Registration +#endregion + +#region Command Registration + /// /// Gets a dictionary of registered top-level commands. /// @@ -401,6 +416,7 @@ public IReadOnlyDictionary RegisteredCommands /// Gets or sets the top level commands. /// private readonly Dictionary _topLevelCommands; + private readonly Lazy> _registeredCommandsLazy; /// @@ -478,7 +494,6 @@ private void RegisterCommands(Type t, CommandGroupBuilder currentParent, IEnumer var moduleChecks = new List(); foreach (var xa in moduleAttributes) - { switch (xa) { case GroupAttribute g: @@ -506,7 +521,7 @@ private void RegisterCommands(Type t, CommandGroupBuilder currentParent, IEnumer groupBuilder.WithExecutionCheck(chk); foreach (var mi in ti.DeclaredMethods.Where(x => x.IsCommandCandidate(out _) && x.GetCustomAttribute() != null)) - groupBuilder.WithOverload(new CommandOverloadBuilder(mi)); + groupBuilder.WithOverload(new(mi)); break; case AliasesAttribute a: @@ -532,7 +547,6 @@ private void RegisterCommands(Type t, CommandGroupBuilder currentParent, IEnumer groupBuilder.WithCustomAttribute(xa); break; } - } if (!isModule) { @@ -578,14 +592,13 @@ private void RegisterCommands(Type t, CommandGroupBuilder currentParent, IEnumer groupBuilder.WithChild(commandBuilder); } - commandBuilder.WithOverload(new CommandOverloadBuilder(m)); + commandBuilder.WithOverload(new(m)); if (!isModule && moduleChecks.Any()) foreach (var chk in moduleChecks) commandBuilder.WithExecutionCheck(chk); foreach (var xa in attrs) - { switch (xa) { case AliasesAttribute a: @@ -609,7 +622,6 @@ private void RegisterCommands(Type t, CommandGroupBuilder currentParent, IEnumer commandBuilder.WithCustomAttribute(xa); break; } - } if (!isModule && moduleHidden) commandBuilder.WithHiddenStatus(true); @@ -676,7 +688,7 @@ private void AddToCommandDictionary(Command cmd) if (cmd.Parent != null) return; - if (this._topLevelCommands.ContainsKey(cmd.Name) || (cmd.Aliases != null && cmd.Aliases.Any(xs => this._topLevelCommands.ContainsKey(xs)))) + if (this._topLevelCommands.ContainsKey(cmd.Name) || cmd.Aliases != null && cmd.Aliases.Any(xs => this._topLevelCommands.ContainsKey(xs))) throw new DuplicateCommandException(cmd.QualifiedName); this._topLevelCommands[cmd.Name] = cmd; @@ -684,9 +696,11 @@ private void AddToCommandDictionary(Command cmd) foreach (var xs in cmd.Aliases) this._topLevelCommands[xs] = cmd; } - #endregion - #region Default Help +#endregion + +#region Default Help + /// /// Represents the default help module. /// @@ -718,8 +732,8 @@ public async Task DefaultHelpAsync(CommandContext ctx, [Description("Command to } cmd = ctx.Config.CaseSensitive - ? searchIn.FirstOrDefault(xc => xc.Name == c || (xc.Aliases != null && xc.Aliases.Contains(c))) - : searchIn.FirstOrDefault(xc => xc.Name.ToLowerInvariant() == c.ToLowerInvariant() || (xc.Aliases != null && xc.Aliases.Select(xs => xs.ToLowerInvariant()).Contains(c.ToLowerInvariant()))); + ? searchIn.FirstOrDefault(xc => xc.Name == c || xc.Aliases != null && xc.Aliases.Contains(c)) + : searchIn.FirstOrDefault(xc => xc.Name.ToLowerInvariant() == c.ToLowerInvariant() || xc.Aliases != null && xc.Aliases.Select(xs => xs.ToLowerInvariant()).Contains(c.ToLowerInvariant())); if (cmd == null) break; @@ -786,12 +800,13 @@ public async Task DefaultHelpAsync(CommandContext ctx, [Description("Command to await ctx.RespondAsync(builder).ConfigureAwait(false); else await ctx.Member.SendMessageAsync(builder).ConfigureAwait(false); - } } - #endregion - #region Sudo +#endregion + +#region Sudo + /// /// Creates a fake command context to execute commands with. /// @@ -819,10 +834,10 @@ public CommandContext CreateFakeContext(DiscordUser actor, DiscordChannel channe Pinned = false, MentionEveryone = messageContents.Contains("@everyone"), IsTts = false, - AttachmentsInternal = new List(), - EmbedsInternal = new List(), + AttachmentsInternal = new(), + EmbedsInternal = new(), TimestampRaw = now.ToString("yyyy-MM-ddTHH:mm:sszzz"), - ReactionsInternal = new List() + ReactionsInternal = new() }; var mentionedUsers = new List(); @@ -838,9 +853,7 @@ public CommandContext CreateFakeContext(DiscordUser actor, DiscordChannel channe mentionedChannels = Utilities.GetChannelMentions(msg).Select(xid => msg.Channel.Guild.GetChannel(xid)).ToList(); } else - { mentionedUsers = Utilities.GetUserMentions(msg).Select(this.Client.GetCachedOrEmptyUserInternal).ToList(); - } } msg.MentionedUsersInternal = mentionedUsers; @@ -862,15 +875,17 @@ public CommandContext CreateFakeContext(DiscordUser actor, DiscordChannel channe if (cmd != null && (cmd.Module is TransientCommandModule || cmd.Module == null)) { var scope = ctx.Services.CreateScope(); - ctx.ServiceScopeContext = new CommandContext.ServiceContext(ctx.Services, scope); + ctx.ServiceScopeContext = new(ctx.Services, scope); ctx.Services = scope.ServiceProvider; } return ctx; } - #endregion - #region Type Conversion +#endregion + +#region Type Conversion + /// /// Converts a string to specified type. /// @@ -903,7 +918,10 @@ public async Task ConvertArgument(string value, CommandContext ctx, Type var m = this._convertGeneric.MakeGenericMethod(type); try { - return await (m.Invoke(this, new object[] { value, ctx }) as Task).ConfigureAwait(false); + return await (m.Invoke(this, new object[] + { + value, ctx + }) as Task).ConfigureAwait(false); } catch (TargetInvocationException ex) { @@ -996,13 +1014,15 @@ public string GetUserFriendlyTypeName(Type t) var ti = t.GetTypeInfo(); if (!ti.IsGenericTypeDefinition || t.GetGenericTypeDefinition() != typeof(Nullable<>)) return t.Name; + var tn = ti.GenericTypeArguments[0]; return this._userFriendlyTypeNames.TryGetValue(tn, out var name) ? name : tn.Name; - } - #endregion - #region Helpers +#endregion + +#region Helpers + /// /// Allows easier interoperability with reflection by turning the returned by /// into a task containing , using the provided generic type information. @@ -1019,9 +1039,11 @@ internal IEqualityComparer GetStringComparer() => this._config.CaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; - #endregion - #region Events +#endregion + +#region Events + /// /// Triggered whenever a command executes successfully. /// @@ -1030,6 +1052,7 @@ public event AsyncEventHandler add => this._executed.Register(value); remove => this._executed.Unregister(value); } + private AsyncEvent _executed; /// @@ -1040,6 +1063,7 @@ public event AsyncEventHandler Com add => this._error.Register(value); remove => this._error.Unregister(value); } + private AsyncEvent _error; /// @@ -1055,5 +1079,6 @@ private Task OnCommandExecuted(CommandExecutionEventArgs e) /// The command error event arguments. private Task OnCommandErrored(CommandErrorEventArgs e) => this._error.InvokeAsync(this, e); - #endregion + +#endregion } diff --git a/DisCatSharp.CommandsNext/CommandsNextUtilities.cs b/DisCatSharp.CommandsNext/CommandsNextUtilities.cs index 1d91a88b6e..a1a6fa99cc 100644 --- a/DisCatSharp.CommandsNext/CommandsNextUtilities.cs +++ b/DisCatSharp.CommandsNext/CommandsNextUtilities.cs @@ -36,7 +36,11 @@ public static class CommandsNextUtilities public static int GetStringPrefixLength(this DiscordMessage msg, string str, StringComparison comparisonType = StringComparison.Ordinal) { var content = msg.Content; - return str.Length >= content.Length ? -1 : !content.StartsWith(str, comparisonType) ? -1 : str.Length; + return str.Length >= content.Length + ? -1 + : !content.StartsWith(str, comparisonType) + ? -1 + : str.Length; } /// @@ -85,6 +89,7 @@ internal static string ExtractNextArgument(this string str, ref int startPos) for (; i < str.Length; i++) if (!char.IsWhiteSpace(str[i])) break; + startPos = i; var endPosition = -1; @@ -99,7 +104,7 @@ internal static string ExtractNextArgument(this string str, ref int startPos) if (!inEscape && !inBacktick && !inTripleBacktick) { inEscape = true; - if (str.IndexOf("\\`", i) == i || str.IndexOf("\\\"", i) == i || str.IndexOf("\\\\", i) == i || (str.Length >= i && char.IsWhiteSpace(str[i + 1]))) + if (str.IndexOf("\\`", i) == i || str.IndexOf("\\\"", i) == i || str.IndexOf("\\\\", i) == i || str.Length >= i && char.IsWhiteSpace(str[i + 1])) removeIndices.Add(i - startPosition); i++; } @@ -234,13 +239,13 @@ internal static async Task BindArguments(CommandContext c } if (argValue == null && !arg.IsOptional && !arg.IsCatchAll) - return new ArgumentBindingResult(new ArgumentException("Not enough arguments supplied to the command.")); + return new(new ArgumentException("Not enough arguments supplied to the command.")); else if (argValue == null) rawArgumentList.Add(null); } if (!ignoreSurplus && foundAt < argString.Length) - return new ArgumentBindingResult(new ArgumentException("Too many arguments were supplied to this command.")); + return new(new ArgumentException("Too many arguments were supplied to this command.")); for (var i = 0; i < overload.Arguments.Count; i++) { @@ -257,8 +262,9 @@ internal static async Task BindArguments(CommandContext c } catch (Exception ex) { - return new ArgumentBindingResult(ex); + return new(ex); } + i++; } @@ -266,19 +272,17 @@ internal static async Task BindArguments(CommandContext c break; } else - { try { args[i + 2] = rawArgumentList[i] != null ? await ctx.CommandsNext.ConvertArgument(rawArgumentList[i], ctx, arg.Type).ConfigureAwait(false) : arg.DefaultValue; } catch (Exception ex) { - return new ArgumentBindingResult(ex); + return new(ex); } - } } - return new ArgumentBindingResult(args, rawArgumentList); + return new(args, rawArgumentList); } /// diff --git a/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs b/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs index f9bde0d8e1..d0115fb0d1 100644 --- a/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs +++ b/DisCatSharp.CommandsNext/Converters/ArgumentBindingResult.cs @@ -12,14 +12,17 @@ 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. /// diff --git a/DisCatSharp.CommandsNext/Converters/DefaultHelpFormatter.cs b/DisCatSharp.CommandsNext/Converters/DefaultHelpFormatter.cs index a399301c2c..537a580cef 100644 --- a/DisCatSharp.CommandsNext/Converters/DefaultHelpFormatter.cs +++ b/DisCatSharp.CommandsNext/Converters/DefaultHelpFormatter.cs @@ -49,7 +49,7 @@ public override BaseHelpFormatter WithCommand(Command command) this.EmbedBuilder.WithDescription($"{this.EmbedBuilder.Description}\n\nThis group can be executed as a standalone command."); if (command.Aliases?.Any() == true) - this.EmbedBuilder.AddField(new DiscordEmbedField("Aliases", string.Join(", ", command.Aliases.Select(Formatter.InlineCode)))); + this.EmbedBuilder.AddField(new("Aliases", string.Join(", ", command.Aliases.Select(Formatter.InlineCode)))); if (command.Overloads?.Any() == true) { @@ -70,7 +70,7 @@ public override BaseHelpFormatter WithCommand(Command command) sb.Append('\n'); } - this.EmbedBuilder.AddField(new DiscordEmbedField("Arguments", sb.ToString().Trim())); + this.EmbedBuilder.AddField(new("Arguments", sb.ToString().Trim())); } return this; @@ -83,7 +83,7 @@ public override BaseHelpFormatter WithCommand(Command command) /// This help formatter. public override BaseHelpFormatter WithSubcommands(IEnumerable subcommands) { - this.EmbedBuilder.AddField(new DiscordEmbedField(this._command != null ? "Subcommands" : "Commands", string.Join(", ", subcommands.Select(x => Formatter.InlineCode(x.Name))))); + this.EmbedBuilder.AddField(new(this._command != null ? "Subcommands" : "Commands", string.Join(", ", subcommands.Select(x => Formatter.InlineCode(x.Name))))); return this; } @@ -97,6 +97,6 @@ public override CommandHelpMessage Build() if (this._command == null) this.EmbedBuilder.WithDescription("Listing all top-level commands and groups. Specify a command to see more information."); - return new CommandHelpMessage(embed: this.EmbedBuilder.Build()); + return new(embed: this.EmbedBuilder.Build()); } } diff --git a/DisCatSharp.CommandsNext/Converters/EntityConverters.cs b/DisCatSharp.CommandsNext/Converters/EntityConverters.cs index 1edb31fb7c..848dfbf17c 100644 --- a/DisCatSharp.CommandsNext/Converters/EntityConverters.cs +++ b/DisCatSharp.CommandsNext/Converters/EntityConverters.cs @@ -43,7 +43,7 @@ async Task> IArgumentConverter.ConvertAsync(s var us = ctx.Client.Guilds.Values .SelectMany(xkvp => xkvp.Members.Values) - .Where(xm => (cs ? xm.Username : xm.Username.ToLowerInvariant()) == un && ((dv != null && xm.Discriminator == dv) || dv == null)); + .Where(xm => (cs ? xm.Username : xm.Username.ToLowerInvariant()) == un && (dv != null && xm.Discriminator == dv || dv == null)); var usr = us.FirstOrDefault(); return Optional.FromNullable(usr); @@ -91,8 +91,8 @@ async Task> IArgumentConverter.ConvertAsy var dv = di != -1 ? value[(di + 1)..] : null; var us = ctx.Guild.Members.Values - .Where(xm => ((cs ? xm.Username : xm.Username.ToLowerInvariant()) == un && ((dv != null && xm.Discriminator == dv) || dv == null)) - || (cs ? xm.Nickname : xm.Nickname?.ToLowerInvariant()) == value); + .Where(xm => (cs ? xm.Username : xm.Username.ToLowerInvariant()) == un && (dv != null && xm.Discriminator == dv || dv == null) + || (cs ? xm.Nickname : xm.Nickname?.ToLowerInvariant()) == value); return Optional.FromNullable(us.FirstOrDefault()); } @@ -216,11 +216,9 @@ public class DiscordGuildConverter : IArgumentConverter Task> IArgumentConverter.ConvertAsync(string value, CommandContext ctx) { if (ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var gid)) - { return ctx.Client.Guilds.TryGetValue(gid, out var result) ? Task.FromResult(Optional.Some(result)) : Task.FromResult(Optional.None); - } var cs = ctx.Config.CaseSensitive; if (!cs) @@ -231,7 +229,6 @@ Task> IArgumentConverter.ConvertAsync(strin } } - /// /// Represents a discord invite converter. /// @@ -248,7 +245,9 @@ async Task> IArgumentConverter.ConvertAsy if (m.Success) { ulong? eventId = ulong.TryParse(m.Groups["event"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, - out var eid) ? eid : null; + out var eid) + ? eid + : null; var result = await ctx.Client.GetInviteByCodeAsync(m.Groups["code"].Value, scheduledEventId: eventId).ConfigureAwait(false); return Optional.FromNullable(result); } @@ -279,8 +278,8 @@ async Task> IArgumentConverter.ConvertA { var uripath = DiscordRegEx.MessageLink.Match(uri.AbsoluteUri); if (!uripath.Success - || !ulong.TryParse(uripath.Groups["channel"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var cid) - || !ulong.TryParse(uripath.Groups["message"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out mid)) + || !ulong.TryParse(uripath.Groups["channel"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var cid) + || !ulong.TryParse(uripath.Groups["message"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out mid)) return Optional.None; var chn = await ctx.Client.GetChannelAsync(cid).ConfigureAwait(false); @@ -322,10 +321,10 @@ async Task> IArgumentConverter> IArgumentConverter.ConvertAsync(strin return !ulong.TryParse(sid, NumberStyles.Integer, CultureInfo.InvariantCulture, out var id) ? Task.FromResult(Optional.None) : DiscordEmoji.TryFromGuildEmote(ctx.Client, id, out emoji) - ? Task.FromResult(Optional.Some(emoji)) - : Task.FromResult(Optional.Some(new DiscordEmoji - { - Discord = ctx.Client, - Id = id, - Name = name, - IsAnimated = anim, - RequiresColons = true, - IsManaged = false - })); + ? Task.FromResult(Optional.Some(emoji)) + : Task.FromResult(Optional.Some(new DiscordEmoji + { + Discord = ctx.Client, + Id = id, + Name = name, + IsAnimated = anim, + RequiresColons = true, + IsManaged = false + })); } return Task.FromResult(Optional.None); diff --git a/DisCatSharp.CommandsNext/Converters/EnumConverter.cs b/DisCatSharp.CommandsNext/Converters/EnumConverter.cs index 32f2fc084c..df7a298a26 100644 --- a/DisCatSharp.CommandsNext/Converters/EnumConverter.cs +++ b/DisCatSharp.CommandsNext/Converters/EnumConverter.cs @@ -23,7 +23,7 @@ Task> IArgumentConverter.ConvertAsync(string value, CommandContex return !ti.IsEnum ? throw new InvalidOperationException("Cannot convert non-enum value to an enum.") : Enum.TryParse(value, !ctx.Config.CaseSensitive, out T ev) - ? Task.FromResult(Optional.Some(ev)) - : Task.FromResult(Optional.None); + ? Task.FromResult(Optional.Some(ev)) + : Task.FromResult(Optional.None); } } diff --git a/DisCatSharp.CommandsNext/Converters/HelpFormatterFactory.cs b/DisCatSharp.CommandsNext/Converters/HelpFormatterFactory.cs index 3cb093ee3f..855d83e8d6 100644 --- a/DisCatSharp.CommandsNext/Converters/HelpFormatterFactory.cs +++ b/DisCatSharp.CommandsNext/Converters/HelpFormatterFactory.cs @@ -20,11 +20,17 @@ public HelpFormatterFactory() { } /// /// Sets the formatter type. /// - public void SetFormatterType() where T : BaseHelpFormatter => this._factory = ActivatorUtilities.CreateFactory(typeof(T), new[] { typeof(CommandContext) }); + public void SetFormatterType() where T : BaseHelpFormatter => this._factory = ActivatorUtilities.CreateFactory(typeof(T), new[] + { + typeof(CommandContext) + }); /// /// Creates the help formatter. /// /// The command context. - public BaseHelpFormatter Create(CommandContext ctx) => this._factory(ctx.Services, new object[] { ctx }) as BaseHelpFormatter; + public BaseHelpFormatter Create(CommandContext ctx) => this._factory(ctx.Services, new object[] + { + ctx + }) as BaseHelpFormatter; } diff --git a/DisCatSharp.CommandsNext/Converters/TimeConverters.cs b/DisCatSharp.CommandsNext/Converters/TimeConverters.cs index 3639c465ee..07015949b8 100644 --- a/DisCatSharp.CommandsNext/Converters/TimeConverters.cs +++ b/DisCatSharp.CommandsNext/Converters/TimeConverters.cs @@ -77,7 +77,10 @@ Task> IArgumentConverter.ConvertAsync(string value, if (TimeSpan.TryParse(value, CultureInfo.InvariantCulture, out var result)) return Task.FromResult(Optional.Some(result)); - var gps = new string[] { "days", "hours", "minutes", "seconds" }; + var gps = new string[] + { + "days", "hours", "minutes", "seconds" + }; var mtc = s_timeSpanRegex.Match(value); if (!mtc.Success) return Task.FromResult(Optional.None); @@ -113,7 +116,8 @@ Task> IArgumentConverter.ConvertAsync(string value, break; } } - result = new TimeSpan(d, h, m, s); + + result = new(d, h, m, s); return Task.FromResult(Optional.Some(result)); } } diff --git a/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj b/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj index 2196b55e6f..b7ca446d52 100644 --- a/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj +++ b/DisCatSharp.CommandsNext/DisCatSharp.CommandsNext.csproj @@ -1,45 +1,46 @@ + - - - - - - - - - DisCatSharp.CommandsNext - DisCatSharp.CommandsNext - - - - DisCatSharp.CommandsNext - -DisCatSharp Commands Next Extension - -Allow your users to use text commands in your bot. - -Note: Requires the Message Content Intent enabled for your discord application. -Documentation: https://docs.dcs.aitsys.dev/articles/modules/commandsnext/intro.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Text Commands - annotations - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + + + + DisCatSharp.CommandsNext + DisCatSharp.CommandsNext + + + + DisCatSharp.CommandsNext + + DisCatSharp Commands Next Extension + + Allow your users to use text commands in your bot. + + Note: Requires the Message Content Intent enabled for your discord application. + Documentation: https://docs.dcs.aitsys.dev/articles/modules/commandsnext/intro.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Text Commands + annotations + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/DisCatSharp.CommandsNext/Entities/Builders/CommandBuilder.cs b/DisCatSharp.CommandsNext/Entities/Builders/CommandBuilder.cs index 9d78663d16..93dea1add1 100644 --- a/DisCatSharp.CommandsNext/Entities/Builders/CommandBuilder.cs +++ b/DisCatSharp.CommandsNext/Entities/Builders/CommandBuilder.cs @@ -92,19 +92,19 @@ public CommandBuilder() /// Module on which this command is to be defined. public CommandBuilder(ICommandModule module) { - this._aliasList = new List(); + this._aliasList = new(); this.Aliases = new ReadOnlyCollection(this._aliasList); - this._executionCheckList = new List(); + this._executionCheckList = new(); this.ExecutionChecks = new ReadOnlyCollection(this._executionCheckList); - this._overloadArgumentSets = new HashSet(); - this._overloadList = new List(); + this._overloadArgumentSets = new(); + this._overloadList = new(); this.Overloads = new ReadOnlyCollection(this._overloadList); this.Module = module; - this._customAttributeList = new List(); + this._customAttributeList = new(); this.CustomAttributes = new ReadOnlyCollection(this._customAttributeList); } diff --git a/DisCatSharp.CommandsNext/Entities/Builders/CommandGroupBuilder.cs b/DisCatSharp.CommandsNext/Entities/Builders/CommandGroupBuilder.cs index 148b9b611a..ca857cbd5d 100644 --- a/DisCatSharp.CommandsNext/Entities/Builders/CommandGroupBuilder.cs +++ b/DisCatSharp.CommandsNext/Entities/Builders/CommandGroupBuilder.cs @@ -35,7 +35,7 @@ public CommandGroupBuilder() public CommandGroupBuilder(ICommandModule module) : base(module) { - this._childrenList = new List(); + this._childrenList = new(); this.Children = new ReadOnlyCollection(this._childrenList); } diff --git a/DisCatSharp.CommandsNext/Entities/Builders/CommandModuleBuilder.cs b/DisCatSharp.CommandsNext/Entities/Builders/CommandModuleBuilder.cs index 46ed92dad8..9673367614 100644 --- a/DisCatSharp.CommandsNext/Entities/Builders/CommandModuleBuilder.cs +++ b/DisCatSharp.CommandsNext/Entities/Builders/CommandModuleBuilder.cs @@ -60,6 +60,6 @@ internal ICommandModule Build(IServiceProvider services) => { ModuleLifespan.Singleton => new SingletonCommandModule(this.Type, services), ModuleLifespan.Transient => new TransientCommandModule(this.Type), - _ => throw new NotSupportedException("Module lifespans other than transient and singleton are not supported."), + _ => throw new NotSupportedException("Module lifespans other than transient and singleton are not supported.") }; } diff --git a/DisCatSharp.CommandsNext/Entities/Builders/CommandOverloadBuilder.cs b/DisCatSharp.CommandsNext/Entities/Builders/CommandOverloadBuilder.cs index 2918bff8f5..b2ab7d7be1 100644 --- a/DisCatSharp.CommandsNext/Entities/Builders/CommandOverloadBuilder.cs +++ b/DisCatSharp.CommandsNext/Entities/Builders/CommandOverloadBuilder.cs @@ -87,17 +87,13 @@ private CommandOverloadBuilder(MethodInfo method, object target) setb.Append(arg.ParameterType).Append(';'); var ca = new CommandArgument { - Name = arg.Name, - Type = arg.ParameterType, - IsOptional = arg.IsOptional, - DefaultValue = arg.IsOptional ? arg.DefaultValue : null + Name = arg.Name, Type = arg.ParameterType, IsOptional = arg.IsOptional, DefaultValue = arg.IsOptional ? arg.DefaultValue : null }; var attrsCustom = new List(); var attrs = arg.GetCustomAttributes(); var isParams = false; foreach (var xa in attrs) - { switch (xa) { case DescriptionAttribute d: @@ -119,7 +115,6 @@ private CommandOverloadBuilder(MethodInfo method, object target) attrsCustom.Add(xa); break; } - } if (i > 2 && !ca.IsOptional && !ca.IsCatchAll && args[i - 3].IsOptional) throw new InvalidOverloadException("Non-optional argument cannot appear after an optional one", method, arg); @@ -160,10 +155,7 @@ internal CommandOverload Build() { var ovl = new CommandOverload() { - Arguments = this.Arguments, - Priority = this.Priority, - Callable = this.Callable, - InvocationTarget = this._invocationTarget + Arguments = this.Arguments, Priority = this.Priority, Callable = this.Callable, InvocationTarget = this._invocationTarget }; return ovl; diff --git a/DisCatSharp.CommandsNext/Entities/Command.cs b/DisCatSharp.CommandsNext/Entities/Command.cs index 00671a60e0..b4fd12ce93 100644 --- a/DisCatSharp.CommandsNext/Entities/Command.cs +++ b/DisCatSharp.CommandsNext/Entities/Command.cs @@ -98,10 +98,9 @@ public virtual async Task ExecuteAsync(CommandContext ctx) var ret = (Task)ovl.Callable.DynamicInvoke(args.Converted); await ret.ConfigureAwait(false); executed = true; - res = new CommandResult + res = new() { - IsSuccessful = true, - Context = ctx + IsSuccessful = true, Context = ctx }; if (mdl is BaseCommandModule bcmAfter) @@ -114,11 +113,9 @@ public virtual async Task ExecuteAsync(CommandContext ctx) } catch (Exception ex) { - res = new CommandResult + res = new() { - IsSuccessful = false, - Exception = ex, - Context = ctx + IsSuccessful = false, Exception = ex, Context = ctx }; } @@ -190,7 +187,7 @@ public override bool Equals(object obj) return true; return obj is Command cmd -&& cmd.QualifiedName == this.QualifiedName; + && cmd.QualifiedName == this.QualifiedName; } /// diff --git a/DisCatSharp.CommandsNext/Entities/CommandGroup.cs b/DisCatSharp.CommandsNext/Entities/CommandGroup.cs index b5c45a3b54..9df86e8706 100644 --- a/DisCatSharp.CommandsNext/Entities/CommandGroup.cs +++ b/DisCatSharp.CommandsNext/Entities/CommandGroup.cs @@ -40,8 +40,8 @@ public override async Task ExecuteAsync(CommandContext ctx) if (cn != null) { var cmd = ctx.Config.CaseSensitive - ? this.Children.FirstOrDefault(xc => xc.Name == cn || (xc.Aliases != null && xc.Aliases.Contains(cn))) - : this.Children.FirstOrDefault(xc => xc.Name.ToLowerInvariant() == cn.ToLowerInvariant() || (xc.Aliases != null && xc.Aliases.Select(xs => xs.ToLowerInvariant()).Contains(cn.ToLowerInvariant()))); + ? this.Children.FirstOrDefault(xc => xc.Name == cn || xc.Aliases != null && xc.Aliases.Contains(cn)) + : this.Children.FirstOrDefault(xc => xc.Name.ToLowerInvariant() == cn.ToLowerInvariant() || xc.Aliases != null && xc.Aliases.Select(xs => xs.ToLowerInvariant()).Contains(cn.ToLowerInvariant())); if (cmd != null) { // pass the execution on @@ -59,22 +59,18 @@ public override async Task ExecuteAsync(CommandContext ctx) var fchecks = await cmd.RunChecksAsync(xctx, false).ConfigureAwait(false); return fchecks.Any() - ? new CommandResult + ? new() { - IsSuccessful = false, - Exception = new ChecksFailedException(cmd, xctx, fchecks), - Context = xctx + IsSuccessful = false, Exception = new ChecksFailedException(cmd, xctx, fchecks), Context = xctx } : await cmd.ExecuteAsync(xctx).ConfigureAwait(false); } } return !this.IsExecutableWithoutSubcommands - ? new CommandResult + ? new() { - IsSuccessful = false, - Exception = new InvalidOperationException("No matching subcommands were found, and this group is not executable."), - Context = ctx + IsSuccessful = false, Exception = new InvalidOperationException("No matching subcommands were found, and this group is not executable."), Context = ctx } : await base.ExecuteAsync(ctx).ConfigureAwait(false); } diff --git a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs index 7478846cbd..1d4fa6bb04 100644 --- a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs +++ b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs @@ -99,7 +99,7 @@ public DiscordMember Member /// 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()); + this._lazyMember = new(() => this.Guild != null && this.Guild.Members.TryGetValue(this.User.Id, out var member) ? member : this.Guild?.GetMemberAsync(this.User.Id).ConfigureAwait(false).GetAwaiter().GetResult()); } /// @@ -156,10 +156,12 @@ public Task TriggerTypingAsync() /// Gets the provider. /// public IServiceProvider Provider { get; } + /// /// Gets the scope. /// public IServiceScope Scope { get; } + /// /// Gets a value indicating whether is initialized. /// diff --git a/DisCatSharp.CommandsNext/ExtensionMethods.cs b/DisCatSharp.CommandsNext/ExtensionMethods.cs index 1e9bcac1b5..43a873c267 100644 --- a/DisCatSharp.CommandsNext/ExtensionMethods.cs +++ b/DisCatSharp.CommandsNext/ExtensionMethods.cs @@ -73,7 +73,6 @@ public static async Task> UseCom public static CommandsNextExtension GetCommandsNext(this DiscordClient client) => client.GetExtension(); - /// /// Gets the active CommandsNext modules for all shards in this client. /// @@ -85,9 +84,7 @@ public static async Task> GetCom var extensions = new Dictionary(); foreach (var shard in client.ShardClients.Select(xkvp => xkvp.Value)) - { extensions.Add(shard.ShardId, shard.GetExtension()); - } return new ReadOnlyDictionary(extensions); } @@ -102,6 +99,7 @@ public static void RegisterCommands(this IReadOnlyDictionary /// Registers all commands from a given command class. /// @@ -112,6 +110,7 @@ public static void RegisterCommands(this IReadOnlyDictionary(); } + /// /// Registers all commands from a given command class. /// @@ -122,6 +121,7 @@ public static void RegisterCommands(this IReadOnlyDictionary /// Builds and registers all supplied commands. /// diff --git a/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs b/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs index 0cdffabec4..9653a929c3 100644 --- a/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs +++ b/DisCatSharp.Common/Attributes/DateTimeFormatAttribute.cs @@ -1,4 +1,5 @@ using System; + // ReSharper disable InconsistentNaming namespace DisCatSharp.Common.Serialization; diff --git a/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs b/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs index 331fa07a7f..e64b327604 100644 --- a/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs +++ b/DisCatSharp.Common/Attributes/IncludeNullAttribute.cs @@ -6,7 +6,6 @@ namespace DisCatSharp.Common.Serialization; /// Specifies that if the value of the field or property is null, it should be included in the serialized data. /// This alters the default behaviour of ignoring nulls. /// -[Obsolete("Use [DataMember] with EmitDefaultValue = true.")] -[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] +[Obsolete("Use [DataMember] with EmitDefaultValue = true."), AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public sealed class IncludeNullAttribute : SerializationAttribute { } diff --git a/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs b/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs index c1cc041338..71817a5ff4 100644 --- a/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs +++ b/DisCatSharp.Common/Attributes/SerializedNameAttribute.cs @@ -5,8 +5,7 @@ namespace DisCatSharp.Common.Serialization; /// /// Declares name of a property in serialized data. This is used for mapping serialized data to object properties and fields. /// -[Obsolete("Use [DataMember] with set Name instead.")] -[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] +[Obsolete("Use [DataMember] with set Name instead."), AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public sealed class SerializedNameAttribute : SerializationAttribute { /// diff --git a/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs b/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs index 9f29478a9b..c25e71591f 100644 --- a/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs +++ b/DisCatSharp.Common/Attributes/TimeSpanFormatAttribute.cs @@ -1,4 +1,5 @@ using System; + // ReSharper disable InconsistentNaming namespace DisCatSharp.Common.Serialization; diff --git a/DisCatSharp.Common/DisCatSharp.Common.csproj b/DisCatSharp.Common/DisCatSharp.Common.csproj index 3c730aa47d..60169d2f29 100644 --- a/DisCatSharp.Common/DisCatSharp.Common.csproj +++ b/DisCatSharp.Common/DisCatSharp.Common.csproj @@ -1,56 +1,57 @@ + - - - - - - - - DisCatSharp.Common - DisCatSharp.Common - True - True - True - Portable - - - - DisCatSharp.Common - -DisCatSharp Common Extension - -Common tools for DisCatSharp, like regexes and converters! - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Common Tools - annotations - - - - False - - - - 1701;1702;DV2001 - - - - 1701;1702;DV2001 - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - + + + + + + + + DisCatSharp.Common + DisCatSharp.Common + True + True + True + Portable + + + + DisCatSharp.Common + + DisCatSharp Common Extension + + Common tools for DisCatSharp, like regexes and converters! + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Common Tools + annotations + + + + False + + + + 1701;1702;DV2001 + + + + 1701;1702;DV2001 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs b/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs index e00188a4aa..4087dac105 100644 --- a/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs +++ b/DisCatSharp.Common/Types/CharSpanLookupDictionary.cs @@ -18,10 +18,12 @@ public sealed class CharSpanLookupDictionary : /// Gets the collection of all keys present in this dictionary. /// public IEnumerable Keys => this.GetKeysInternal(); + /// /// Gets the keys. /// ICollection IDictionary.Keys => this.GetKeysInternal(); + /// /// Gets the keys. /// @@ -31,10 +33,12 @@ public sealed class CharSpanLookupDictionary : /// Gets the collection of all values present in this dictionary. /// public IEnumerable Values => this.GetValuesInternal(); + /// /// Gets the values. /// ICollection IDictionary.Values => this.GetValuesInternal(); + /// /// Gets the values. /// @@ -112,7 +116,7 @@ public TValue this[ReadOnlySpan key] unsafe { fixed (char* chars = &key.GetPinnableReference()) - this.TryInsertInternal(new string(chars, 0, key.Length), value, true); + this.TryInsertInternal(new(chars, 0, key.Length), value, true); } } } @@ -156,7 +160,7 @@ object IDictionary.this[object key] /// public CharSpanLookupDictionary() { - this._internalBuckets = new Dictionary(); + this._internalBuckets = new(); } /// @@ -165,7 +169,7 @@ public CharSpanLookupDictionary() /// Initial capacity of the dictionary. public CharSpanLookupDictionary(int initialCapacity) { - this._internalBuckets = new Dictionary(initialCapacity); + this._internalBuckets = new(initialCapacity); } /// @@ -184,7 +188,7 @@ public CharSpanLookupDictionary(IDictionary values) /// /// Dictionary containing items to populate this dictionary with. public CharSpanLookupDictionary(IReadOnlyDictionary values) - : this(values.Count) + : this(values.Count) { foreach (var (k, v) in values) this.Add(k, v); @@ -222,7 +226,7 @@ public void Add(ReadOnlySpan key, TValue value) unsafe { fixed (char* chars = &key.GetPinnableReference()) - if (!this.TryInsertInternal(new string(chars, 0, key.Length), value, false)) + if (!this.TryInsertInternal(new(chars, 0, key.Length), value, false)) throw new ArgumentException("Given key is already present in the dictionary.", nameof(key)); } } @@ -247,7 +251,7 @@ public bool TryAdd(ReadOnlySpan key, TValue value) unsafe { fixed (char* chars = &key.GetPinnableReference()) - return this.TryInsertInternal(new string(chars, 0, key.Length), value, false); + return this.TryInsertInternal(new(chars, 0, key.Length), value, false); } } @@ -428,7 +432,7 @@ void ICollection>.CopyTo(KeyValuePair(kdv.Key, kdv.Value); + array[i++] = new(kdv.Key, kdv.Value); kdv = kdv.Next; } } @@ -484,7 +488,7 @@ private bool TryInsertInternal(string key, TValue value, bool replace) var hash = key.CalculateKnuthHash(); if (!this._internalBuckets.ContainsKey(hash)) { - this._internalBuckets.Add(hash, new KeyedValue(key, hash, value)); + this._internalBuckets.Add(hash, new(key, hash, value)); this.Count++; return true; } @@ -506,7 +510,7 @@ private bool TryInsertInternal(string key, TValue value, bool replace) kdv = kdv.Next; } - kdvLast.Next = new KeyedValue(key, hash, value); + kdvLast.Next = new(key, hash, value); this.Count++; return true; } @@ -526,13 +530,11 @@ private bool TryRetrieveInternal(ReadOnlySpan key, out TValue value) return false; while (kdv != null) - { if (key.SequenceEqual(kdv.Key.AsSpan())) { value = kdv.Value; return true; } - } return false; } @@ -561,11 +563,8 @@ private bool TryRemoveInternal(ReadOnlySpan key, out TValue value) return true; } else if (kdv.Next == null) - { // Only bucket under this hash and key does not match, cannot remove - return false; - } else if (key.SequenceEqual(kdv.Key.AsSpan())) { // First key in the bucket matches, pop it and set its child as current bucket @@ -668,10 +667,12 @@ private class KeyedValue /// Gets the key hash. /// public ulong KeyHash { get; } + /// /// Gets the key. /// public string Key { get; } + /// /// Gets or sets the value. /// @@ -707,18 +708,22 @@ private class Enumerator : /// Gets the current. /// public KeyValuePair Current { get; private set; } + /// /// Gets the current. /// object IEnumerator.Current => this.Current; + /// /// Gets the key. /// object IDictionaryEnumerator.Key => this.Current.Key; + /// /// Gets the value. /// object IDictionaryEnumerator.Value => this.Current.Value; + /// /// Gets the entry. /// @@ -762,13 +767,13 @@ public bool MoveNext() return false; kdv = this._internalEnumerator.Current.Value; - this.Current = new KeyValuePair(kdv.Key, kdv.Value); + this.Current = new(kdv.Key, kdv.Value); this._currentValue = kdv.Next; return true; } - this.Current = new KeyValuePair(kdv.Key, kdv.Value); + this.Current = new(kdv.Key, kdv.Value); this._currentValue = kdv.Next; return true; } diff --git a/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs b/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs index 0314a0959f..1258f30f01 100644 --- a/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs +++ b/DisCatSharp.Common/Types/CharSpanLookupReadOnlyDictionary.cs @@ -91,6 +91,7 @@ public CharSpanLookupReadOnlyDictionary(IEnumerable { if (values == null!) throw new ArgumentNullException(nameof(values)); + this._internalBuckets = PrepareItems(values, out var count); this.Count = count; } @@ -163,13 +164,11 @@ private bool TryRetrieveInternal(ReadOnlySpan key, out TValue value) return false; while (kdv != null) - { if (key.SequenceEqual(kdv.Key.AsSpan())) { value = kdv.Value; return true; } - } return false; } @@ -254,7 +253,7 @@ private static IReadOnlyDictionary PrepareItems(IEnumerable PrepareItems(IEnumerable public ulong KeyHash { get; } + /// /// Gets the key. /// public string Key { get; } + /// /// Gets or sets the value. /// @@ -323,6 +324,7 @@ private class Enumerator : IEnumerator> /// Gets the current. /// public KeyValuePair Current { get; private set; } + /// /// Gets the current. /// @@ -366,13 +368,13 @@ public bool MoveNext() return false; kdv = this._internalEnumerator.Current.Value; - this.Current = new KeyValuePair(kdv.Key, kdv.Value); + this.Current = new(kdv.Key, kdv.Value); this._currentValue = kdv.Next; return true; } - this.Current = new KeyValuePair(kdv.Key, kdv.Value); + this.Current = new(kdv.Key, kdv.Value); this._currentValue = kdv.Next; return true; } diff --git a/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs b/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs index 201b256a89..2ed9e6e13f 100644 --- a/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs +++ b/DisCatSharp.Common/Types/ContinuousMemoryBuffer.cs @@ -139,7 +139,7 @@ public bool Read(Span destination, ulong source, out int itemsWritten) throw new ArgumentOutOfRangeException(nameof(source), "Cannot copy data from beyond the buffer."); var start = (int)source; - var sbuff = this._buff[start..this._pos ].Span; + var sbuff = this._buff[start..this._pos].Span; var dbuff = MemoryMarshal.AsBytes(destination); if (sbuff.Length > dbuff.Length) sbuff = sbuff[..dbuff.Length]; diff --git a/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs b/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs index 13d9945286..ef9ea5035b 100644 --- a/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs +++ b/DisCatSharp.Common/Types/Serialization/ComplexDecomposer.cs @@ -13,18 +13,22 @@ public sealed class ComplexDecomposer : IDecomposer /// Gets the t complex. /// private static Type s_complex { get; } = typeof(Complex); + /// /// Gets the t double array. /// private static Type s_doubleArray { get; } = typeof(double[]); + /// /// Gets the t double enumerable. /// private static Type s_doubleEnumerable { get; } = typeof(IEnumerable); + /// /// Gets the t object array. /// private static Type s_objectArray { get; } = typeof(object[]); + /// /// Gets the t object enumerable. /// @@ -37,9 +41,9 @@ public bool CanDecompose(Type t) /// public bool CanRecompose(Type t) => t == s_doubleArray - || t == s_objectArray - || s_doubleEnumerable.IsAssignableFrom(t) - || s_objectEnumerable.IsAssignableFrom(t); + || t == s_objectArray + || s_doubleEnumerable.IsAssignableFrom(t) + || s_objectEnumerable.IsAssignableFrom(t); /// public bool TryDecompose(object obj, Type tobj, out object decomposed, out Type tdecomposed) @@ -50,7 +54,10 @@ public bool TryDecompose(object obj, Type tobj, out object decomposed, out Type if (tobj != s_complex || obj is not Complex c) return false; - decomposed = new[] { c.Real, c.Imaginary }; + decomposed = new[] + { + c.Real, c.Imaginary + }; return true; } diff --git a/DisCatSharp.Common/Utilities/AsyncEvent/AsyncEvent.cs b/DisCatSharp.Common/Utilities/AsyncEvent/AsyncEvent.cs index 8c4d5c937c..16723a0fa0 100644 --- a/DisCatSharp.Common/Utilities/AsyncEvent/AsyncEvent.cs +++ b/DisCatSharp.Common/Utilities/AsyncEvent/AsyncEvent.cs @@ -106,12 +106,11 @@ public async Task InvokeAsync(TSender sender, TArgs e, AsyncEventExceptionMode e // Collect exceptions List exceptions = null; if ((exceptionMode & AsyncEventExceptionMode.ThrowAll) != 0) - exceptions = new List(handlers.Length * 2 /* timeout + regular */); + exceptions = new(handlers.Length * 2 /* timeout + regular */); // If we have a timeout configured, start the timeout task var timeout = this.MaximumExecutionTime > TimeSpan.Zero ? Task.Delay(this.MaximumExecutionTime) : null; foreach (var handler in handlers) - { try { // Start the handler execution @@ -120,7 +119,6 @@ public async Task InvokeAsync(TSender sender, TArgs e, AsyncEventExceptionMode e { // If timeout is configured, wait for any task to finish // If the timeout task finishes first, the handler is causing a timeout - var result = await Task.WhenAny(timeout, handlerTask).ConfigureAwait(false); if (result == timeout) { @@ -138,10 +136,8 @@ public async Task InvokeAsync(TSender sender, TArgs e, AsyncEventExceptionMode e } } else if (handlerTask != null) - { // No timeout is configured, or timeout already expired, proceed as usual await handlerTask.ConfigureAwait(false); - } if (e.Handled) break; @@ -156,7 +152,6 @@ public async Task InvokeAsync(TSender sender, TArgs e, AsyncEventExceptionMode e if ((exceptionMode & AsyncEventExceptionMode.ThrowFatal) == AsyncEventExceptionMode.ThrowFatal) exceptions.Add(ex); } - } if ((exceptionMode & AsyncEventExceptionMode.ThrowAll) != 0 && exceptions.Count > 0) throw new AggregateException("Exceptions were thrown during execution of the event's handlers.", exceptions); diff --git a/DisCatSharp.Common/Utilities/AsyncExecutor.cs b/DisCatSharp.Common/Utilities/AsyncExecutor.cs index 06f8d3084b..abada79a6b 100644 --- a/DisCatSharp.Common/Utilities/AsyncExecutor.cs +++ b/DisCatSharp.Common/Utilities/AsyncExecutor.cs @@ -22,7 +22,7 @@ public AsyncExecutor() public void Execute(Task task) { // create state object - var taskState = new StateRef(new AutoResetEvent(false)); + var taskState = new StateRef(new(false)); // queue a task and wait for it to finish executing task.ContinueWith(TaskCompletionHandler, taskState); @@ -47,9 +47,7 @@ void TaskCompletionHandler(Task t, object state) stateRef.Exception = t.Exception; } else if (t.IsCanceled) - { stateRef.Exception = new TaskCanceledException(t); - } // signal that the execution is done stateRef.Lock.Set(); @@ -65,7 +63,7 @@ void TaskCompletionHandler(Task t, object state) public T Execute(Task task) { // create state object - var taskState = new StateRef(new AutoResetEvent(false)); + var taskState = new StateRef(new(false)); // queue a task and wait for it to finish executing task.ContinueWith(TaskCompletionHandler, taskState); @@ -80,7 +78,7 @@ public T Execute(Task task) return taskState.Result; // throw exception if no result - throw new Exception("Task returned no result."); + throw new("Task returned no result."); // completion method void TaskCompletionHandler(Task t, object state) @@ -97,9 +95,7 @@ void TaskCompletionHandler(Task t, object state) stateRef.Exception = t.Exception; } else if (t.IsCanceled) - { stateRef.Exception = new TaskCanceledException(t); - } // return the result from the task, if any if (t.IsCompleted && !t.IsFaulted) diff --git a/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs b/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs index b955604c57..396b1c7506 100644 --- a/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs +++ b/DisCatSharp.Common/Utilities/AsyncManualResetEvent.cs @@ -21,7 +21,7 @@ public sealed class AsyncManualResetEvent /// Initial state of this event. public AsyncManualResetEvent(bool initialState) { - this._resetTcs = new TaskCompletionSource(); + this._resetTcs = new(); if (initialState) this._resetTcs.TrySetResult(initialState); } @@ -51,7 +51,7 @@ public void Reset() while (true) { var tcs = this._resetTcs; - if (!tcs.Task.IsCompleted || Interlocked.CompareExchange(ref this._resetTcs, new TaskCompletionSource(), tcs) == tcs) + if (!tcs.Task.IsCompleted || Interlocked.CompareExchange(ref this._resetTcs, new(), tcs) == tcs) return; } } diff --git a/DisCatSharp.Common/Utilities/Extensions.cs b/DisCatSharp.Common/Utilities/Extensions.cs index 18c28e7ac1..8c7b133284 100644 --- a/DisCatSharp.Common/Utilities/Extensions.cs +++ b/DisCatSharp.Common/Utilities/Extensions.cs @@ -305,7 +305,7 @@ public static bool IsInRange(this double num, double min, double max, bool inclu /// Whether the character is in basic alphanumeric character range. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsBasicAlphanumeric(this char c) - => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + => c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'; /// /// Returns whether supplied character is in the 0-9 range. @@ -323,7 +323,7 @@ public static bool IsBasicDigit(this char c) /// Whether the character is in basic letter character range. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsBasicLetter(this char c) - => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + => c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; /// /// Tests whether given string ends with given character. @@ -452,7 +452,6 @@ internal static bool TryFirstTwo(this IEnumerable enumerable, out (T first if (!enumerator.MoveNext()) return false; - values = (first, enumerator.Current); return true; } @@ -481,13 +480,11 @@ private static ulong Knuth(ReadOnlySpan chars) internal static bool RemoveFirst(this IList list, Predicate predicate) { for (var i = 0; i < list.Count; i++) - { if (predicate(list[i])) { list.RemoveAt(i); return true; } - } return false; } @@ -501,8 +498,6 @@ internal static bool RemoveFirst(this IList list, Predicate predicate) internal static void Populate(this T[] arr, T value) { for (var i = 0; i < arr.Length; i++) - { arr[i] = value; - } } } diff --git a/DisCatSharp.Common/Utilities/RuntimeInformation.cs b/DisCatSharp.Common/Utilities/RuntimeInformation.cs index d40138f6a9..765a1e2ef0 100644 --- a/DisCatSharp.Common/Utilities/RuntimeInformation.cs +++ b/DisCatSharp.Common/Utilities/RuntimeInformation.cs @@ -22,7 +22,10 @@ public static class RuntimeInformation static RuntimeInformation() { var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - var mscorlib = loadedAssemblies.Select(x => new { Assembly = x, AssemblyName = x.GetName() }) + var mscorlib = loadedAssemblies.Select(x => new + { + Assembly = x, AssemblyName = x.GetName() + }) .FirstOrDefault(x => x.AssemblyName.Name == "mscorlib" || x.AssemblyName.Name == "System.Private.CoreLib"); var location = mscorlib.Assembly.Location; diff --git a/DisCatSharp.Configuration.Tests/ConfigurationExtensionTests.cs b/DisCatSharp.Configuration.Tests/ConfigurationExtensionTests.cs index 99ec6fb2fa..9e44095bfd 100644 --- a/DisCatSharp.Configuration.Tests/ConfigurationExtensionTests.cs +++ b/DisCatSharp.Configuration.Tests/ConfigurationExtensionTests.cs @@ -14,26 +14,41 @@ namespace DisCatSharp.Configuration.Tests; public class ConfigurationExtensionTests { - #region Test Classes - class SampleClass +#region Test Classes + + private class SampleClass { public int Amount { get; set; } public string? Email { get; set; } } - class ClassWithArray + private class ClassWithArray { - public int[] Values { get; set; } = { 1, 2, 3, 4, 5 }; - public string[] Strings { get; set; } = { "1", "2", "3", "4", "5" }; + public int[] Values { get; set; } = + { + 1, 2, 3, 4, 5 + }; + + public string[] Strings { get; set; } = + { + "1", "2", "3", "4", "5" + }; } - class ClassWithEnumerable + private class ClassWithEnumerable { - public IEnumerable Values { get; set; } = new[] { 1, 2, 3, 4, 5 }; - public IEnumerable Strings { get; set; } = new[] { "1", "2", "3", "4", "5" }; + public IEnumerable Values { get; set; } = new[] + { + 1, 2, 3, 4, 5 + }; + + public IEnumerable Strings { get; set; } = new[] + { + "1", "2", "3", "4", "5" + }; } - class ClassWithList + private class ClassWithList { public List Strings { get; set; } = new() { @@ -54,17 +69,19 @@ class ClassWithList }; } - class SampleClass2 + private class SampleClass2 { public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(7); public string Name { get; set; } = "Sample"; public string ConstructorValue { get; } + public SampleClass2(string value) { this.ConstructorValue = value; } } - #endregion + +#endregion private IConfiguration EnumerableTestConfiguration() => new ConfigurationBuilder() @@ -86,8 +103,8 @@ private IConfiguration HasSectionNoSuffixConfiguration() => .Build(); private IConfiguration DiscordIntentsConfig() => new ConfigurationBuilder() - .AddJsonFile("intents-discord.json") - .Build(); + .AddJsonFile("intents-discord.json") + .Build(); private IConfiguration DiscordHaphazardConfig() => new ConfigurationBuilder() .AddJsonFile("haphazard-discord.json") @@ -97,44 +114,63 @@ private IConfiguration HasSectionNoSuffixConfiguration() => private IConfiguration SampleConfig() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - { "Sample:Amount", "200" }, - { "Sample:Email", "test@gmail.com" } + { + "Sample:Amount", "200" + }, + { + "Sample:Email", "test@gmail.com" + } }) .Build(); private IConfiguration SampleClass2Configuration_Default() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - {"Random:Stuff", "Meow"}, - {"SampleClass2:Name", "Purfection"} + { + "Random:Stuff", "Meow" + }, + { + "SampleClass2:Name", "Purfection" + } }) .Build(); private IConfiguration SampleClass2Configuration_Change() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - { "SampleClass:Timeout", "01:30:00" }, { "SampleClass:NotValid", "Something" } + { + "SampleClass:Timeout", "01:30:00" + }, + { + "SampleClass:NotValid", "Something" + } }) .Build(); private IConfiguration SampleClass2EnumerableTest() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - { "SampleClass:EnumerableTest", "[\"10\",\"20\",\"30\"]" } + { + "SampleClass:EnumerableTest", "[\"10\",\"20\",\"30\"]" + } }) .Build(); private IConfiguration SampleClass2ArrayTest() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - { "SampleClass:ArrayTest", "[\"10\",\"20\",\"30\"]" } + { + "SampleClass:ArrayTest", "[\"10\",\"20\",\"30\"]" + } }) .Build(); private IConfiguration SampleClass2ListTest() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - { "SampleClass:ListTest", "[\"10\",\"20\",\"30\"]" } + { + "SampleClass:ListTest", "[\"10\",\"20\",\"30\"]" + } }) .Build(); #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. @@ -147,7 +183,7 @@ public void TestExtractDiscordConfig_Intents() var config = source.ExtractConfig("Discord"); var expected = DiscordIntents.GuildEmojisAndStickers | DiscordIntents.GuildMembers | - DiscordIntents.GuildInvites | DiscordIntents.GuildMessageReactions; + DiscordIntents.GuildInvites | DiscordIntents.GuildMessageReactions; Assert.Equal(expected, config.Intents); } @@ -159,7 +195,7 @@ public void TestExtractDiscordConfig_Haphazard() var config = source.ExtractConfig("Discord"); var expectedIntents = DiscordIntents.GuildEmojisAndStickers | DiscordIntents.GuildMembers | - DiscordIntents.Guilds; + DiscordIntents.Guilds; Assert.Equal(expectedIntents, config.Intents); Assert.True(config.MobileStatus); @@ -206,7 +242,7 @@ public void TestSection() public void TestExtractConfig_V2_Default() { var source = this.SampleClass2Configuration_Default(); - var config = (SampleClass2) source.ExtractConfig("SampleClass", () => new SampleClass2("Test"), null); + var config = (SampleClass2)source.ExtractConfig("SampleClass", () => new SampleClass2("Test"), null); Assert.Equal(TimeSpan.FromMinutes(7), config.Timeout); Assert.Equal("Test", config.ConstructorValue); Assert.Equal("Sample", config.Name); @@ -216,7 +252,7 @@ public void TestExtractConfig_V2_Default() public void TestExtractConfig_V2_Change() { var source = this.SampleClass2Configuration_Change(); - var config = (SampleClass2) source.ExtractConfig("SampleClass", () => new SampleClass2("Test123"), null); + var config = (SampleClass2)source.ExtractConfig("SampleClass", () => new SampleClass2("Test123"), null); var span = new TimeSpan(0, 1, 30, 0); Assert.Equal(span, config.Timeout); Assert.Equal("Test123", config.ConstructorValue); @@ -314,4 +350,3 @@ public void TestHasSectionNoSuffix() #pragma warning restore 8625 } } - diff --git a/DisCatSharp.Configuration.Tests/default-discord.json b/DisCatSharp.Configuration.Tests/default-discord.json index 127aa83e5a..22b6d82a9a 100644 --- a/DisCatSharp.Configuration.Tests/default-discord.json +++ b/DisCatSharp.Configuration.Tests/default-discord.json @@ -1,23 +1,23 @@ { - "DisCatSharp": { - "Discord": { - "Token": "1234567890", - "TokenType": "Bot", - "MinimumLogLevel": "Information", - "UseRelativeRateLimit": true, - "LogTimestampFormat": "yyyy-MM-dd HH:mm:ss zzz", - "LargeThreshold": 250, - "AutoReconnect": true, - "ShardId": 123123, - "GatewayCompressionLevel": "Stream", - "MessageCacheSize": 1024, - "HttpTimeout": "00:00:20", - "ReconnectIndefinitely": false, - "AlwaysCacheMembers": true, - "MobileStatus": false, - "UseCanary": false, - "AutoRefreshChannelCache": false, - "Intents": "AllUnprivileged" - } - } + "DisCatSharp": { + "Discord": { + "Token": "1234567890", + "TokenType": "Bot", + "MinimumLogLevel": "Information", + "UseRelativeRateLimit": true, + "LogTimestampFormat": "yyyy-MM-dd HH:mm:ss zzz", + "LargeThreshold": 250, + "AutoReconnect": true, + "ShardId": 123123, + "GatewayCompressionLevel": "Stream", + "MessageCacheSize": 1024, + "HttpTimeout": "00:00:20", + "ReconnectIndefinitely": false, + "AlwaysCacheMembers": true, + "MobileStatus": false, + "UseCanary": false, + "AutoRefreshChannelCache": false, + "Intents": "AllUnprivileged" + } + } } diff --git a/DisCatSharp.Configuration.Tests/enumerable-test.json b/DisCatSharp.Configuration.Tests/enumerable-test.json index 459fc9cd56..1da8151574 100644 --- a/DisCatSharp.Configuration.Tests/enumerable-test.json +++ b/DisCatSharp.Configuration.Tests/enumerable-test.json @@ -1,37 +1,37 @@ { - "ClassWithArray": { - "Values": [ - 10,11,12 - ], + "ClassWithArray": { + "Values": [ + 10, 11, 12 + ], - "Strings": [ - "One", - "Two", - "Three" - ] - }, + "Strings": [ + "One", + "Two", + "Three" + ] + }, - "ClassWithEnumerable": { - "Values": [ - 10,11,12 - ], + "ClassWithEnumerable": { + "Values": [ + 10, 11, 12 + ], - "Strings": [ - "One", - "Two", - "Three" - ] - }, + "Strings": [ + "One", + "Two", + "Three" + ] + }, - "ClassWithList": { - "Values": [ - 10,11,12 - ], + "ClassWithList": { + "Values": [ + 10, 11, 12 + ], - "Strings": [ - "One", - "Two", - "Three" - ] - } + "Strings": [ + "One", + "Two", + "Three" + ] + } } diff --git a/DisCatSharp.Configuration.Tests/haphazard-discord.json b/DisCatSharp.Configuration.Tests/haphazard-discord.json index 428af39e7f..9a7dd5e7cd 100644 --- a/DisCatSharp.Configuration.Tests/haphazard-discord.json +++ b/DisCatSharp.Configuration.Tests/haphazard-discord.json @@ -1,10 +1,10 @@ { - "DisCatSharp": { - "Discord": { - "Intents": "GuildEmojisAndStickers,GuildMembers,Guilds", - "MobileStatus": true, - "LargeThreshold": 1000, - "HttpTimeout": "10:00:00" - } - } + "DisCatSharp": { + "Discord": { + "Intents": "GuildEmojisAndStickers,GuildMembers,Guilds", + "MobileStatus": true, + "LargeThreshold": 1000, + "HttpTimeout": "10:00:00" + } + } } diff --git a/DisCatSharp.Configuration.Tests/intents-discord.json b/DisCatSharp.Configuration.Tests/intents-discord.json index 520d54744c..64467ce2ec 100644 --- a/DisCatSharp.Configuration.Tests/intents-discord.json +++ b/DisCatSharp.Configuration.Tests/intents-discord.json @@ -1,7 +1,7 @@ { - "DisCatSharp": { - "Discord": { - "Intents": "GuildEmojisAndStickers,GuildMembers,GuildInvites,GuildMessageReactions" - } - } + "DisCatSharp": { + "Discord": { + "Intents": "GuildEmojisAndStickers,GuildMembers,GuildInvites,GuildMessageReactions" + } + } } diff --git a/DisCatSharp.Configuration.Tests/section-no-suffix.json b/DisCatSharp.Configuration.Tests/section-no-suffix.json index 1d5ad0682d..89ad99f21f 100644 --- a/DisCatSharp.Configuration.Tests/section-no-suffix.json +++ b/DisCatSharp.Configuration.Tests/section-no-suffix.json @@ -1,5 +1,5 @@ { - "Discord": { - "Values": [1,2,3,4,5] - } + "Discord": { + "Values": [1, 2, 3, 4, 5] + } } diff --git a/DisCatSharp.Configuration.Tests/section-with-suffix.json b/DisCatSharp.Configuration.Tests/section-with-suffix.json index 1489e82952..571f6a00df 100644 --- a/DisCatSharp.Configuration.Tests/section-with-suffix.json +++ b/DisCatSharp.Configuration.Tests/section-with-suffix.json @@ -1,5 +1,5 @@ { - "DiscordConfiguration": { - "Values": [1,2,3,4,5] - } + "DiscordConfiguration": { + "Values": [1, 2, 3, 4, 5] + } } diff --git a/DisCatSharp.Configuration/ConfigurationExtensions.cs b/DisCatSharp.Configuration/ConfigurationExtensions.cs index 98c8424478..3d98551930 100644 --- a/DisCatSharp.Configuration/ConfigurationExtensions.cs +++ b/DisCatSharp.Configuration/ConfigurationExtensions.cs @@ -18,16 +18,17 @@ internal static class ConfigurationExtensions /// The factory error message. /// private const string FACTORY_ERROR_MESSAGE = "Require a function which provides a default entity to work with"; + /// /// The default root lib. /// public const string DEFAULT_ROOT_LIB = "DisCatSharp"; + /// /// The config suffix. /// private const string CONFIG_SUFFIX = "Configuration"; - /// /// Easily piece together paths that will work within /// @@ -143,8 +144,12 @@ public static object ExtractConfig(this ConfigSection section, Func fact /// (Optional) Used when section is nested within another. Default value is /// Hydrated instance of an entity which contains user-defined values (if any) /// When is null - public static object ExtractConfig(this IConfiguration config, string sectionName, Func factory, - string? rootSectionName = DEFAULT_ROOT_LIB) + public static object ExtractConfig( + this IConfiguration config, + string sectionName, + Func factory, + string? rootSectionName = DEFAULT_ROOT_LIB + ) { if (factory == null) throw new ArgumentNullException(nameof(factory), FACTORY_ERROR_MESSAGE); @@ -152,7 +157,7 @@ public static object ExtractConfig(this IConfiguration config, string sectionNam // create default instance var instance = factory(); - HydrateInstance(ref instance, new ConfigSection(ref config, sectionName, rootSectionName)); + HydrateInstance(ref instance, new(ref config, sectionName, rootSectionName)); return instance; } @@ -173,7 +178,7 @@ public static TConfig ExtractConfig(this IConfiguration config, IServic // Default values should hopefully be provided from the constructor var configInstance = ActivatorUtilities.CreateInstance(serviceProvider, typeof(TConfig)); - HydrateInstance(ref configInstance, new ConfigSection(ref config, sectionName, rootSectionName)); + HydrateInstance(ref configInstance, new(ref config, sectionName, rootSectionName)); return (TConfig)configInstance; } @@ -193,7 +198,7 @@ public static TConfig ExtractConfig(this IConfiguration config, string // Default values should hopefully be provided from the constructor object configInstance = new TConfig(); - HydrateInstance(ref configInstance, new ConfigSection(ref config, sectionName, rootSectionName)); + HydrateInstance(ref configInstance, new(ref config, sectionName, rootSectionName)); return (TConfig)configInstance; } @@ -274,8 +279,11 @@ public static bool HasSection(this IConfiguration config, params string[] values /// /// /// Instance of - public static DiscordClient BuildClient(this IConfiguration config, IServiceProvider serviceProvider, - string botSectionName = DEFAULT_ROOT_LIB) + public static DiscordClient BuildClient( + this IConfiguration config, + IServiceProvider serviceProvider, + string botSectionName = DEFAULT_ROOT_LIB + ) { var section = config.HasSection(botSectionName, "Discord") ? "Discord" @@ -284,7 +292,7 @@ public static DiscordClient BuildClient(this IConfiguration config, IServiceProv : null; return string.IsNullOrEmpty(section) - ? new DiscordClient(new DiscordConfiguration(serviceProvider)) + ? new(new(serviceProvider)) : new DiscordClient(config.ExtractConfig(serviceProvider, section, botSectionName)); } } diff --git a/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj b/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj index 0b6106aafb..b0a29b1326 100644 --- a/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj +++ b/DisCatSharp.Configuration/DisCatSharp.Configuration.csproj @@ -1,40 +1,41 @@ + - - - - - - + + + + + + - - DisCatSharp.Configuration - DisCatSharp.Configuration - True - + + DisCatSharp.Configuration + DisCatSharp.Configuration + True + - - DisCatSharp.Configuration - Configuration for the DisCatSharp Hosting Extension. - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Hosting,Web,Configuration - annotations - + + DisCatSharp.Configuration + Configuration for the DisCatSharp Hosting Extension. + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Hosting,Web,Configuration + annotations + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + - - - + + + diff --git a/DisCatSharp.EventHandlers.Tests/BasicEventHandlerTests.cs b/DisCatSharp.EventHandlers.Tests/BasicEventHandlerTests.cs index 44097ee6c9..cae1061754 100644 --- a/DisCatSharp.EventHandlers.Tests/BasicEventHandlerTests.cs +++ b/DisCatSharp.EventHandlers.Tests/BasicEventHandlerTests.cs @@ -1,4 +1,3 @@ - #nullable enable using System; using System.Reflection; @@ -14,7 +13,8 @@ namespace DisCatSharp.EventHandlers.Tests; public class BasicEventHandlerTests { [EventHandler] - private class HandlerA { } + private class HandlerA + { } [EventHandler] private class HandlerB @@ -54,7 +54,10 @@ private abstract class BadHandlerB private static Task ThisEventDoesNotExist() => Task.CompletedTask; } - private readonly DiscordClient _client = new(new() { Token = "1" }); + private readonly DiscordClient _client = new(new() + { + Token = "1" + }); [Fact] public void TestUtility() @@ -113,12 +116,13 @@ public void TestInvalidHandlers() private bool IsEventRegistered(string name) { // This is super hacky, but I think it should be good enough. - if (name.Length == 0) { throw new ArgumentException("name mustn't be empty"); } + if (name.Length == 0) + throw new ArgumentException("name mustn't be empty"); + name = "_" + char.ToLower(name[0]) + name[1..]; var asyncEvent = typeof(DiscordClient).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(this._client); dynamic handlers = asyncEvent?.GetType().GetField("_handlers", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(asyncEvent) - ?? throw new ArgumentException($"Unknown event \"{name}\""); + ?? throw new ArgumentException($"Unknown event \"{name}\""); return handlers.Length != 0; } - } diff --git a/DisCatSharp.EventHandlers.Tests/EventsEnumIntegrityTests.cs b/DisCatSharp.EventHandlers.Tests/EventsEnumIntegrityTests.cs index 640c71db43..647b1e318b 100644 --- a/DisCatSharp.EventHandlers.Tests/EventsEnumIntegrityTests.cs +++ b/DisCatSharp.EventHandlers.Tests/EventsEnumIntegrityTests.cs @@ -1,4 +1,3 @@ - #nullable enable using System.Linq; @@ -11,21 +10,17 @@ namespace DisCatSharp.EventHandlers.Tests; public class EventsEnumIntegrityTests { [Fact] - void TestEnumToEvent() + private void TestEnumToEvent() { foreach (var value in typeof(DiscordEvent).GetEnumValues()) - { Assert.NotNull(typeof(DiscordClient).GetEvent(value.ToString()!)); - } } [Fact] - void TestEventToEnum() + private void TestEventToEnum() { var enumNames = typeof(DiscordEvent).GetEnumNames().ToHashSet(); foreach (var evtn in typeof(DiscordClient).GetEvents()) - { Assert.Contains(evtn.Name, enumNames); - } } } diff --git a/DisCatSharp.EventHandlers.Tests/ServiceProviderTests.cs b/DisCatSharp.EventHandlers.Tests/ServiceProviderTests.cs index 95b35e4b7d..e8a5d0f8fa 100644 --- a/DisCatSharp.EventHandlers.Tests/ServiceProviderTests.cs +++ b/DisCatSharp.EventHandlers.Tests/ServiceProviderTests.cs @@ -1,4 +1,3 @@ - #nullable enable using System; @@ -10,7 +9,8 @@ namespace DisCatSharp.EventHandlers.Tests; public class ServiceProviderTests { - private class Resource { } + private class Resource + { } private class Handler { @@ -20,13 +20,15 @@ public Handler(Resource res) { } [Fact] public void Test() { - var poorClient = new DiscordClient(new() { Token = "1" }); + var poorClient = new DiscordClient(new() + { + Token = "1" + }); Assert.ThrowsAny(() => poorClient.RegisterEventHandler()); var richClient = new DiscordClient(new() { - Token = "2", - ServiceProvider = new ServiceCollection().AddSingleton().BuildServiceProvider(), + Token = "2", ServiceProvider = new ServiceCollection().AddSingleton().BuildServiceProvider() }); richClient.RegisterEventHandler(); // May not throw. } diff --git a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj index 9d702a75e0..78e8a60759 100644 --- a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj +++ b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj @@ -1,40 +1,41 @@ + - - - - - - - - - DisCatSharp.Experimental - DisCatSharp.Experimental - - - - DisCatSharp.Experimental - - DisCatSharp.Experimental - - Experimental changes for DisCatSharp. - - DisCatSharp,Experimental,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7 - annotations - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + + + + + + DisCatSharp.Experimental + DisCatSharp.Experimental + + + + DisCatSharp.Experimental + + DisCatSharp.Experimental + + Experimental changes for DisCatSharp. + + DisCatSharp,Experimental,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7 + annotations + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + - - - + + + diff --git a/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj b/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj index 2a2ce9c1de..c5d4c9f8c0 100644 --- a/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj +++ b/DisCatSharp.Hosting.DependencyInjection/DisCatSharp.Hosting.DependencyInjection.csproj @@ -1,32 +1,33 @@ + - - - - - - + + + + + + - - DisCatSharp.Hosting.DependencyInjection - Dependency Injection for the DisCatSharp Hosting Extension. - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Hosting,Web,Dependency Injection - annotations - + + DisCatSharp.Hosting.DependencyInjection + Dependency Injection for the DisCatSharp Hosting Extension. + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Hosting,Web,Dependency Injection + annotations + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + - - - + + + diff --git a/DisCatSharp.Hosting.DependencyInjection/ServiceCollectionExtensions.cs b/DisCatSharp.Hosting.DependencyInjection/ServiceCollectionExtensions.cs index 3e23e5aa9a..3917071213 100644 --- a/DisCatSharp.Hosting.DependencyInjection/ServiceCollectionExtensions.cs +++ b/DisCatSharp.Hosting.DependencyInjection/ServiceCollectionExtensions.cs @@ -76,7 +76,8 @@ public static IServiceCollection AddDiscordHostedService(t /// Your custom bot /// Reference to for chaining purposes public static IServiceCollection AddDiscordHostedShardService( - this IServiceCollection services) + this IServiceCollection services + ) where TInterface : class, IDiscordHostedShardService where TService : class, TInterface, IDiscordHostedShardService { diff --git a/DisCatSharp.Hosting.Tests/BotTwo.json b/DisCatSharp.Hosting.Tests/BotTwo.json index 01bda1edb0..849d1b355b 100644 --- a/DisCatSharp.Hosting.Tests/BotTwo.json +++ b/DisCatSharp.Hosting.Tests/BotTwo.json @@ -1,8 +1,8 @@ { - "BotTwo": { - "Discord": { - "Token": "1234567890", - "Intents": "Guilds" - } - } + "BotTwo": { + "Discord": { + "Token": "1234567890", + "Intents": "Guilds" + } + } } diff --git a/DisCatSharp.Hosting.Tests/ExtensionTests.cs b/DisCatSharp.Hosting.Tests/ExtensionTests.cs index 36458554d2..32833a04c2 100644 --- a/DisCatSharp.Hosting.Tests/ExtensionTests.cs +++ b/DisCatSharp.Hosting.Tests/ExtensionTests.cs @@ -13,7 +13,8 @@ namespace DisCatSharp.Hosting.Tests; public class HostExtensionTests { - #region Reference to external assemblies - required to ensure they're loaded +#region Reference to external assemblies - required to ensure they're loaded + #pragma warning disable 414 private InteractivityConfiguration? _interactivityConfig = null; @@ -21,37 +22,76 @@ public class HostExtensionTests private DiscordConfiguration? _discordConfig = null; #pragma warning restore 414 - #endregion + +#endregion private Dictionary DefaultDiscord() => new() { - { "DisCatSharp:Discord:Token", "1234567890" }, - { "DisCatSharp:Discord:TokenType", "Bot" }, - { "DisCatSharp:Discord:MinimumLogLevel", "Information" }, - { "DisCatSharp:Discord:UseRelativeRateLimit", "true" }, - { "DisCatSharp:Discord:LogTimestampFormat", "yyyy-MM-dd HH:mm:ss zzz" }, - { "DisCatSharp:Discord:LargeThreshold", "250" }, - { "DisCatSharp:Discord:AutoReconnect", "true" }, - { "DisCatSharp:Discord:ShardId", "123123" }, - { "DisCatSharp:Discord:GatewayCompressionLevel", "Stream" }, - { "DisCatSharp:Discord:MessageCacheSize", "1024" }, - { "DisCatSharp:Discord:HttpTimeout", "00:00:20" }, - { "DisCatSharp:Discord:ReconnectIndefinitely", "false" }, - { "DisCatSharp:Discord:AlwaysCacheMembers", "true" }, - { "DisCatSharp:Discord:DiscordIntents", "AllUnprivileged" }, - { "DisCatSharp:Discord:MobileStatus", "false" }, - { "DisCatSharp:Discord:UseCanary", "false" }, - { "DisCatSharp:Discord:AutoRefreshChannelCache", "false" }, - { "DisCatSharp:Discord:Intents", "AllUnprivileged" } + { + "DisCatSharp:Discord:Token", "1234567890" + }, + { + "DisCatSharp:Discord:TokenType", "Bot" + }, + { + "DisCatSharp:Discord:MinimumLogLevel", "Information" + }, + { + "DisCatSharp:Discord:UseRelativeRateLimit", "true" + }, + { + "DisCatSharp:Discord:LogTimestampFormat", "yyyy-MM-dd HH:mm:ss zzz" + }, + { + "DisCatSharp:Discord:LargeThreshold", "250" + }, + { + "DisCatSharp:Discord:AutoReconnect", "true" + }, + { + "DisCatSharp:Discord:ShardId", "123123" + }, + { + "DisCatSharp:Discord:GatewayCompressionLevel", "Stream" + }, + { + "DisCatSharp:Discord:MessageCacheSize", "1024" + }, + { + "DisCatSharp:Discord:HttpTimeout", "00:00:20" + }, + { + "DisCatSharp:Discord:ReconnectIndefinitely", "false" + }, + { + "DisCatSharp:Discord:AlwaysCacheMembers", "true" + }, + { + "DisCatSharp:Discord:DiscordIntents", "AllUnprivileged" + }, + { + "DisCatSharp:Discord:MobileStatus", "false" + }, + { + "DisCatSharp:Discord:UseCanary", "false" + }, + { + "DisCatSharp:Discord:AutoRefreshChannelCache", "false" + }, + { + "DisCatSharp:Discord:Intents", "AllUnprivileged" + } }; #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. public IConfiguration DiscordInteractivityConfiguration() => new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary(this.DefaultDiscord()) { - {"DisCatSharp:Using", "[\"DisCatSharp.Interactivity\"]"} // this should be enough to automatically add the extension - }) + { + "DisCatSharp:Using", "[\"DisCatSharp.Interactivity\"]" + } // this should be enough to automatically add the extension + }) .Build(); public IConfiguration DiscordOnlyConfiguration() => new ConfigurationBuilder() @@ -90,12 +130,10 @@ public void DiscoverExtensions_InteractivityAndLavaLink() Assert.Equal(typeof(InteractivityConfiguration), first.Value.ConfigType); Assert.Equal(typeof(InteractivityExtension), first.Value.ImplementationType); - Assert.Equal("InteractivityExtension", first.Key, ignoreCase: true); + Assert.Equal("InteractivityExtension", first.Key, true); Assert.Equal(typeof(LavalinkConfiguration), last.Value.ConfigType); Assert.Equal(typeof(LavalinkExtension), last.Value.ImplementationType); - Assert.Equal("LavalinkExtension", last.Key, ignoreCase: true); + Assert.Equal("LavalinkExtension", last.Key, true); } } - - diff --git a/DisCatSharp.Hosting.Tests/GlobalSuppressions.cs b/DisCatSharp.Hosting.Tests/GlobalSuppressions.cs index 70a147d893..400488dd62 100644 --- a/DisCatSharp.Hosting.Tests/GlobalSuppressions.cs +++ b/DisCatSharp.Hosting.Tests/GlobalSuppressions.cs @@ -16,8 +16,12 @@ [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Hosting.Tests.HostTests.Create(System.String)~Microsoft.Extensions.Hosting.IHostBuilder")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Hosting.Tests.HostTests.Create``2(System.String)~Microsoft.Extensions.Hosting.IHostBuilder")] [assembly: SuppressMessage("DocumentationHeader", "ConstructorDocumentationHeader:The constructor must have a documentation header.", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Hosting.Tests.Bot.#ctor(Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger{DisCatSharp.Hosting.Tests.Bot},System.IServiceProvider,Microsoft.Extensions.Hosting.IHostApplicationLifetime)")] -[assembly: SuppressMessage("DocumentationHeader", "ConstructorDocumentationHeader:The constructor must have a documentation header.", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Hosting.Tests.BotTwoService.#ctor(Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger{DisCatSharp.Hosting.Tests.BotTwoService},System.IServiceProvider,Microsoft.Extensions.Hosting.IHostApplicationLifetime)")] -[assembly: SuppressMessage("DocumentationHeader", "ConstructorDocumentationHeader:The constructor must have a documentation header.", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Hosting.Tests.MyCustomBot.#ctor(Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger{DisCatSharp.Hosting.Tests.MyCustomBot},System.IServiceProvider,Microsoft.Extensions.Hosting.IHostApplicationLifetime)")] +[assembly: + SuppressMessage("DocumentationHeader", "ConstructorDocumentationHeader:The constructor must have a documentation header.", Justification = "", Scope = "member", + Target = "~M:DisCatSharp.Hosting.Tests.BotTwoService.#ctor(Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger{DisCatSharp.Hosting.Tests.BotTwoService},System.IServiceProvider,Microsoft.Extensions.Hosting.IHostApplicationLifetime)")] +[assembly: + SuppressMessage("DocumentationHeader", "ConstructorDocumentationHeader:The constructor must have a documentation header.", Justification = "", Scope = "member", + Target = "~M:DisCatSharp.Hosting.Tests.MyCustomBot.#ctor(Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger{DisCatSharp.Hosting.Tests.MyCustomBot},System.IServiceProvider,Microsoft.Extensions.Hosting.IHostApplicationLifetime)")] [assembly: SuppressMessage("Usage", "DCS0102:[Discord] Deprecated", Justification = "")] [assembly: SuppressMessage("Usage", "DCS0101:[Discord] InExperiment", Justification = "")] [assembly: SuppressMessage("Usage", "DCS0103:[Discord] InExperiment", Justification = "")] diff --git a/DisCatSharp.Hosting.Tests/HostTests.cs b/DisCatSharp.Hosting.Tests/HostTests.cs index c9918a8234..4d8155b0f4 100644 --- a/DisCatSharp.Hosting.Tests/HostTests.cs +++ b/DisCatSharp.Hosting.Tests/HostTests.cs @@ -37,7 +37,6 @@ public interface IBotTwoService : IDiscordHostedService string GiveMeAResponse(); } - public sealed class BotTwoService : DiscordHostedService, IBotTwoService { public BotTwoService(IConfiguration config, ILogger logger, IServiceProvider provider, IHostApplicationLifetime lifetime) : base(config, logger, provider, lifetime, "BotTwo") @@ -54,56 +53,95 @@ public class HostTests private Dictionary DefaultDiscord() => new() { - { "DisCatSharp:Discord:Token", "1234567890" }, - { "DisCatSharp:Discord:TokenType", "Bot" }, - { "DisCatSharp:Discord:MinimumLogLevel", "Information" }, - { "DisCatSharp:Discord:UseRelativeRateLimit", "true" }, - { "DisCatSharp:Discord:LogTimestampFormat", "yyyy-MM-dd HH:mm:ss zzz" }, - { "DisCatSharp:Discord:LargeThreshold", "250" }, - { "DisCatSharp:Discord:AutoReconnect", "true" }, - { "DisCatSharp:Discord:ShardId", "123123" }, - { "DisCatSharp:Discord:GatewayCompressionLevel", "Stream" }, - { "DisCatSharp:Discord:MessageCacheSize", "1024" }, - { "DisCatSharp:Discord:HttpTimeout", "00:00:20" }, - { "DisCatSharp:Discord:ReconnectIndefinitely", "false" }, - { "DisCatSharp:Discord:AlwaysCacheMembers", "true" }, - { "DisCatSharp:Discord:DiscordIntents", "AllUnprivileged" }, - { "DisCatSharp:Discord:MobileStatus", "false" }, - { "DisCatSharp:Discord:UseCanary", "false" }, - { "DisCatSharp:Discord:AutoRefreshChannelCache", "false" }, - { "DisCatSharp:Discord:Intents", "AllUnprivileged" } + { + "DisCatSharp:Discord:Token", "1234567890" + }, + { + "DisCatSharp:Discord:TokenType", "Bot" + }, + { + "DisCatSharp:Discord:MinimumLogLevel", "Information" + }, + { + "DisCatSharp:Discord:UseRelativeRateLimit", "true" + }, + { + "DisCatSharp:Discord:LogTimestampFormat", "yyyy-MM-dd HH:mm:ss zzz" + }, + { + "DisCatSharp:Discord:LargeThreshold", "250" + }, + { + "DisCatSharp:Discord:AutoReconnect", "true" + }, + { + "DisCatSharp:Discord:ShardId", "123123" + }, + { + "DisCatSharp:Discord:GatewayCompressionLevel", "Stream" + }, + { + "DisCatSharp:Discord:MessageCacheSize", "1024" + }, + { + "DisCatSharp:Discord:HttpTimeout", "00:00:20" + }, + { + "DisCatSharp:Discord:ReconnectIndefinitely", "false" + }, + { + "DisCatSharp:Discord:AlwaysCacheMembers", "true" + }, + { + "DisCatSharp:Discord:DiscordIntents", "AllUnprivileged" + }, + { + "DisCatSharp:Discord:MobileStatus", "false" + }, + { + "DisCatSharp:Discord:UseCanary", "false" + }, + { + "DisCatSharp:Discord:AutoRefreshChannelCache", "false" + }, + { + "DisCatSharp:Discord:Intents", "AllUnprivileged" + } }; public Dictionary DiscordInteractivity() => new(this.DefaultDiscord()) { - { "DisCatSharp:Using", "[\"DisCatSharp.Interactivity\"]" }, + { + "DisCatSharp:Using", "[\"DisCatSharp.Interactivity\"]" + } }; public Dictionary DiscordInteractivityAndLavalink() => new(this.DefaultDiscord()) { - { "DisCatSharp:Using", "[\"DisCatSharp.Interactivity\", \"DisCatSharp.Lavalink\"]" }, + { + "DisCatSharp:Using", "[\"DisCatSharp.Interactivity\", \"DisCatSharp.Lavalink\"]" + } }; #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. - IHostBuilder Create(Dictionary configValues) => + private IHostBuilder Create(Dictionary configValues) => Host.CreateDefaultBuilder() .ConfigureServices(services => services.AddSingleton()) .ConfigureHostConfiguration(builder => builder.AddInMemoryCollection(configValues)); #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. - IHostBuilder Create(string filename) => + private IHostBuilder Create(string filename) => Host.CreateDefaultBuilder() .ConfigureServices(services => services.AddSingleton()) .ConfigureHostConfiguration(builder => builder.AddJsonFile(filename)); - IHostBuilder Create(string filename) + private IHostBuilder Create(string filename) where TInterface : class, IDiscordHostedService where TBot : class, TInterface, IDiscordHostedService => Host.CreateDefaultBuilder() .ConfigureServices(services => services.AddSingleton()) .ConfigureHostConfiguration(builder => builder.AddJsonFile(filename)); - [Fact] public void TestBotCustomInterface() { @@ -140,10 +178,9 @@ public void TestDifferentSection_InteractivityOnly() Assert.Null(service.Client.GetExtension()); var intents = DiscordIntents.GuildEmojisAndStickers | DiscordIntents.GuildMembers | - DiscordIntents.Guilds; + DiscordIntents.Guilds; Assert.Equal(intents, service.Client.Intents); - var interactivity = service.Client.GetExtension(); Assert.NotNull(interactivity); diff --git a/DisCatSharp.Hosting.Tests/interactivity-different-section.json b/DisCatSharp.Hosting.Tests/interactivity-different-section.json index 1fdcef8fe7..0d8081691d 100644 --- a/DisCatSharp.Hosting.Tests/interactivity-different-section.json +++ b/DisCatSharp.Hosting.Tests/interactivity-different-section.json @@ -1,12 +1,12 @@ { - "MyCustomBot": { - "Using": [ - "Interactivity" - ], + "MyCustomBot": { + "Using": [ + "Interactivity" + ], - "Discord": { - "Token": "1234567890", - "Intents": "GuildEmojisAndStickers,GuildMembers,Guilds" - } - } + "Discord": { + "Token": "1234567890", + "Intents": "GuildEmojisAndStickers,GuildMembers,Guilds" + } + } } diff --git a/DisCatSharp.Hosting.Tests/interactivity-lavalink.json b/DisCatSharp.Hosting.Tests/interactivity-lavalink.json index 1121fb5294..9486a9ecf9 100644 --- a/DisCatSharp.Hosting.Tests/interactivity-lavalink.json +++ b/DisCatSharp.Hosting.Tests/interactivity-lavalink.json @@ -1,8 +1,8 @@ { - "DisCatSharp": { - "Using": [ - "Interactivity", - "Lavalink" - ] - } + "DisCatSharp": { + "Using": [ + "Interactivity", + "Lavalink" + ] + } } diff --git a/DisCatSharp.Hosting.Tests/lavalink-different-section.json b/DisCatSharp.Hosting.Tests/lavalink-different-section.json index 91d48b92fb..65a75f94c1 100644 --- a/DisCatSharp.Hosting.Tests/lavalink-different-section.json +++ b/DisCatSharp.Hosting.Tests/lavalink-different-section.json @@ -1,12 +1,12 @@ { - "MyCustomBot": { - "Using": [ - "Lavalink" - ], + "MyCustomBot": { + "Using": [ + "Lavalink" + ], - "Discord": { - "Token": "1234567890", - "Intents": "Guilds" - } - } + "Discord": { + "Token": "1234567890", + "Intents": "Guilds" + } + } } diff --git a/DisCatSharp.Hosting/BaseHostedService.cs b/DisCatSharp.Hosting/BaseHostedService.cs index e21641dc12..8c1a2af5ba 100644 --- a/DisCatSharp.Hosting/BaseHostedService.cs +++ b/DisCatSharp.Hosting/BaseHostedService.cs @@ -33,11 +33,13 @@ public abstract class BaseHostedService : BackgroundService /// The service provider. /// The application lifetime. /// The config bot section. - internal BaseHostedService(IConfiguration config, + internal BaseHostedService( + IConfiguration config, ILogger logger, IServiceProvider serviceProvider, IHostApplicationLifetime applicationLifetime, - string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB) + string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB + ) { this.Configuration = config; this.Logger = logger; @@ -97,7 +99,10 @@ Public Constructors --> Public var instance = ctors.Any(x => x.GetParameters().Length == 1 && x.GetParameters().First().ParameterType == typePair.Value.ConfigType) ? Activator.CreateInstance(typePair.Value.ImplementationType, flags, null, - new[] { configInstance }, null) + new[] + { + configInstance + }, null) : Activator.CreateInstance(typePair.Value.ImplementationType, true); /* @@ -108,7 +113,6 @@ Those who don't -- simply instantiate ActivatorUtilities requires a public constructor, anything with internal breaks */ - if (instance == null) { this.Logger.LogError($"Unable to instantiate '{typePair.Value.ImplementationType.Name}'"); @@ -166,11 +170,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) catch (Exception ex) { /* - * Anything before DOTNET 6 will - * fail silently despite throwing an exception in this method - * So to overcome this obstacle we need to log what happens and - * manually exit - */ + * Anything before DOTNET 6 will + * fail silently despite throwing an exception in this method + * So to overcome this obstacle we need to log what happens and + * manually exit + */ this.Logger.LogError($"Was unable to start {this.GetType().Name} Bot as a Hosted Service"); // Power given to developer for handling exception diff --git a/DisCatSharp.Hosting/ConfigurationExtensions.cs b/DisCatSharp.Hosting/ConfigurationExtensions.cs index 53d251198f..9f91d0abda 100644 --- a/DisCatSharp.Hosting/ConfigurationExtensions.cs +++ b/DisCatSharp.Hosting/ConfigurationExtensions.cs @@ -16,10 +16,12 @@ internal struct ExtensionConfigResult /// Gets or sets the section. /// public ConfigSection? Section { get; set; } + /// /// Gets or sets the config type. /// public Type ConfigType { get; set; } + /// /// Gets or sets the implementation type. /// @@ -44,7 +46,6 @@ internal static class ConfigurationExtensions /// Assemblies which meet the given names. No duplicates public static List FindAssemblies(IEnumerable? names) { - /* There is a possibility that an assembly can be referenced in multiple assemblies. To alleviate duplicates we need to shrink our queue as we find things @@ -68,13 +69,11 @@ To alleviate duplicates we need to shrink our queue as we find things // Is this something we're looking for? if (queue.Remove(loadedAssemblyName)) - { results.Add(assembly); - } // Time to check if one of the referenced assemblies is something we're looking for foreach (var referencedAssembly in assembly.GetReferencedAssemblies() - .Where(x => x.Name != null && queue.Contains(x.Name))) + .Where(x => x.Name != null && queue.Contains(x.Name))) try { // Must load the assembly into our workspace so we can do stuff with it later @@ -97,8 +96,10 @@ To alleviate duplicates we need to shrink our queue as we find things /// /// /// Dictionary where Key -> Name of implemented type
Value ->
- public static Dictionary FindImplementedExtensions(this IConfiguration configuration, - string rootName = Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB) + public static Dictionary FindImplementedExtensions( + this IConfiguration configuration, + string rootName = Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB + ) { if (string.IsNullOrEmpty(rootName)) throw new ArgumentNullException(nameof(rootName), "Root name must be provided"); @@ -120,7 +121,7 @@ JSON or as Text. assemblyNames = string.IsNullOrEmpty(configuration[configuration.ConfigPath(rootName, "Using")]) ? configuration.GetSection(configuration.ConfigPath(rootName, "Using")).Get() : Newtonsoft.Json.JsonConvert.DeserializeObject( - configuration[configuration.ConfigPath(rootName, "Using")]); + configuration[configuration.ConfigPath(rootName, "Using")]); foreach (var assembly in FindAssemblies(assemblyNames.Select(x => x.StartsWith(Constants.LibName) ? x : $"{Constants.LibName}.{x}"))) { ExtensionConfigResult result = new(); @@ -167,5 +168,4 @@ In the event a user has some "fluff" between prefix and suffix we'll return results; } - } diff --git a/DisCatSharp.Hosting/Constants.cs b/DisCatSharp.Hosting/Constants.cs index a79effa0f9..80648e4fd2 100644 --- a/DisCatSharp.Hosting/Constants.cs +++ b/DisCatSharp.Hosting/Constants.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Hosting; /// @@ -10,10 +9,12 @@ internal static class Constants /// Gets the lib name. /// public static string LibName => Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB; + /// /// Gets the config suffix. /// public static string ConfigSuffix => "Configuration"; + /// /// Gets the extension suffix. /// diff --git a/DisCatSharp.Hosting/DiscordHostedService.cs b/DisCatSharp.Hosting/DiscordHostedService.cs index f7c8700944..d158bfbbb5 100644 --- a/DisCatSharp.Hosting/DiscordHostedService.cs +++ b/DisCatSharp.Hosting/DiscordHostedService.cs @@ -25,15 +25,15 @@ public abstract class DiscordHostedService : BaseHostedService, IDiscordHostedSe /// ServiceProvider reference which contains all items currently registered for Dependency Injection /// Contains the appropriate methods for disposing / stopping BackgroundServices during runtime /// The name of the JSON/Config Key which contains the configuration for this Discord Service - protected DiscordHostedService(IConfiguration config, + protected DiscordHostedService( + IConfiguration config, ILogger logger, IServiceProvider serviceProvider, IHostApplicationLifetime applicationLifetime, - string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB) + string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB + ) : base(config, logger, serviceProvider, applicationLifetime, configBotSection) - { - - } + { } protected override Task ConfigureAsync() { @@ -49,6 +49,7 @@ protected override Task ConfigureAsync() return Task.CompletedTask; } + protected sealed override async Task ConnectAsync() => await this.Client.ConnectAsync(); protected override Task ConfigureExtensionsAsync() diff --git a/DisCatSharp.Hosting/DiscordSharedHostedService.cs b/DisCatSharp.Hosting/DiscordSharedHostedService.cs index 151c594110..cce174473e 100644 --- a/DisCatSharp.Hosting/DiscordSharedHostedService.cs +++ b/DisCatSharp.Hosting/DiscordSharedHostedService.cs @@ -24,22 +24,22 @@ public abstract class DiscordShardedHostedService : BaseHostedService, IDiscordH /// The service provider. /// The application lifetime. /// The config bot section. - protected DiscordShardedHostedService(IConfiguration config, + protected DiscordShardedHostedService( + IConfiguration config, ILogger logger, IServiceProvider serviceProvider, IHostApplicationLifetime applicationLifetime, - string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB) + string configBotSection = DisCatSharp.Configuration.ConfigurationExtensions.DEFAULT_ROOT_LIB + ) : base(config, logger, serviceProvider, applicationLifetime, configBotSection) - { - - } + { } protected override Task ConfigureAsync() { try { var config = this.Configuration.ExtractConfig(this.ServiceProvider, "Discord", this.BotSection); - this.ShardedClient = new DiscordShardedClient(config); + this.ShardedClient = new(config); } catch (Exception ex) { @@ -55,9 +55,7 @@ protected override Task ConfigureAsync() protected override Task ConfigureExtensionsAsync() { foreach (var client in this.ShardedClient.ShardClients.Values) - { this.InitializeExtensions(client); - } return Task.CompletedTask; } diff --git a/DisCatSharp.Hosting/IDiscordHostedService.cs b/DisCatSharp.Hosting/IDiscordHostedService.cs index c9c4d06c5d..cf8539beb7 100644 --- a/DisCatSharp.Hosting/IDiscordHostedService.cs +++ b/DisCatSharp.Hosting/IDiscordHostedService.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Hosting; /// diff --git a/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj b/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj index 554b34102f..d290157415 100644 --- a/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj +++ b/DisCatSharp.Interactivity/DisCatSharp.Interactivity.csproj @@ -1,44 +1,45 @@ + - - - - - - - - - DisCatSharp.Interactivity - DisCatSharp.Interactivity - - - - DisCatSharp.Interactivity - -DisCatSharp Interactivity Extension - -Unleash the full power of discord commands. - -Documentation: https://docs.dcs.aitsys.dev/articles/modules/interactivity.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Pagination,Reactions,Buttons,Interactive Commands,Interactivity,Message Components - annotations - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - + + + + + + + + + DisCatSharp.Interactivity + DisCatSharp.Interactivity + + + + DisCatSharp.Interactivity + + DisCatSharp Interactivity Extension + + Unleash the full power of discord commands. + + Documentation: https://docs.dcs.aitsys.dev/articles/modules/interactivity.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Pagination,Reactions,Buttons,Interactive Commands,Interactivity,Message Components + annotations + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/DisCatSharp.Interactivity/Enums/ButtonPaginationBehavior.cs b/DisCatSharp.Interactivity/Enums/ButtonPaginationBehavior.cs index 98a459fa52..69e3c723b9 100644 --- a/DisCatSharp.Interactivity/Enums/ButtonPaginationBehavior.cs +++ b/DisCatSharp.Interactivity/Enums/ButtonPaginationBehavior.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// @@ -10,14 +9,17 @@ public enum ButtonPaginationBehavior /// The buttons should be disabled when pagination times out. /// Disable, + /// /// The buttons should be left as is when pagination times out. /// Ignore, + /// /// The entire message should be deleted when pagination times out. /// DeleteMessage, + /// /// The buttons should be removed entirely when pagination times out. /// diff --git a/DisCatSharp.Interactivity/Enums/InteractionResponseBehavior.cs b/DisCatSharp.Interactivity/Enums/InteractionResponseBehavior.cs index f881ff164c..10cb73e32b 100644 --- a/DisCatSharp.Interactivity/Enums/InteractionResponseBehavior.cs +++ b/DisCatSharp.Interactivity/Enums/InteractionResponseBehavior.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// @@ -10,10 +9,12 @@ public enum InteractionResponseBehavior /// Indicates that invalid input should be ignored when waiting for interactions. This will cause the interaction to fail. /// Ignore, + /// /// Indicates that invalid input should be ACK'd. The interaction will succeed, but nothing will happen. /// Ack, + /// /// Indicates that invalid input should warrant an ephemeral error message. /// diff --git a/DisCatSharp.Interactivity/Enums/Modal/ModalPage.cs b/DisCatSharp.Interactivity/Enums/Modal/ModalPage.cs index 02bb2c9ed6..b74401baae 100644 --- a/DisCatSharp.Interactivity/Enums/Modal/ModalPage.cs +++ b/DisCatSharp.Interactivity/Enums/Modal/ModalPage.cs @@ -17,7 +17,7 @@ public class ModalPage public ModalPage(DiscordInteractionModalBuilder modal, DiscordButtonComponent openButton = null, string openText = null) { this.Modal = modal; - this.OpenButton = openButton ?? new DiscordButtonComponent(ButtonStyle.Primary, null, "Open next page", false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("📄"))); + this.OpenButton = openButton ?? new DiscordButtonComponent(ButtonStyle.Primary, null, "Open next page", false, new(DiscordEmoji.FromUnicode("📄"))); this.OpenMessage = new DiscordInteractionResponseBuilder().WithContent(openText ?? "`Click the button below to continue to the next page.`").AsEphemeral(); } diff --git a/DisCatSharp.Interactivity/Enums/PaginationBehaviour.cs b/DisCatSharp.Interactivity/Enums/PaginationBehaviour.cs index 32c64ba576..8a8476ab21 100644 --- a/DisCatSharp.Interactivity/Enums/PaginationBehaviour.cs +++ b/DisCatSharp.Interactivity/Enums/PaginationBehaviour.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// diff --git a/DisCatSharp.Interactivity/Enums/PaginationDeletion.cs b/DisCatSharp.Interactivity/Enums/PaginationDeletion.cs index dd9d8cf4e7..bb3dc35bb8 100644 --- a/DisCatSharp.Interactivity/Enums/PaginationDeletion.cs +++ b/DisCatSharp.Interactivity/Enums/PaginationDeletion.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// diff --git a/DisCatSharp.Interactivity/Enums/PollBehaviour.cs b/DisCatSharp.Interactivity/Enums/PollBehaviour.cs index 4fdc320b5a..1acb3306a8 100644 --- a/DisCatSharp.Interactivity/Enums/PollBehaviour.cs +++ b/DisCatSharp.Interactivity/Enums/PollBehaviour.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// diff --git a/DisCatSharp.Interactivity/Enums/SplitType.cs b/DisCatSharp.Interactivity/Enums/SplitType.cs index fb5549d196..630a8cb94e 100644 --- a/DisCatSharp.Interactivity/Enums/SplitType.cs +++ b/DisCatSharp.Interactivity/Enums/SplitType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity.Enums; /// diff --git a/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs b/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs index b63ccc6bae..f5d249721d 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/ComponentEventWaiter.cs @@ -36,7 +36,10 @@ public ComponentEventWaiter(DiscordClient client, InteractivityConfiguration con this._client.ComponentInteractionCreated += this.Handle; this._config = config; - this._message = new DiscordFollowupMessageBuilder { Content = config.ResponseMessage ?? "This message was not meant for you.", IsEphemeral = true }; + this._message = new() + { + Content = config.ResponseMessage ?? "This message was not meant for you.", IsEphemeral = true + }; } /// @@ -95,17 +98,13 @@ public async Task> CollectMat private async Task Handle(DiscordClient _, ComponentInteractionCreateEventArgs args) { foreach (var mreq in this._matchRequests) - { if (mreq.Message == args.Message && mreq.IsMatch(args)) mreq.Tcs.TrySetResult(args); else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); - } - foreach (var creq in this._collectRequests) - { if (creq.Message == args.Message && creq.IsMatch(args)) { await args.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate).ConfigureAwait(false); @@ -116,8 +115,8 @@ private async Task Handle(DiscordClient _, ComponentInteractionCreateEventArgs a else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); } - } } + /// /// Disposes the waiter. /// diff --git a/DisCatSharp.Interactivity/EventHandling/Components/ComponentPaginator.cs b/DisCatSharp.Interactivity/EventHandling/Components/ComponentPaginator.cs index 0df7a0866c..c2485b8913 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/ComponentPaginator.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/ComponentPaginator.cs @@ -70,7 +70,6 @@ public async Task DoPaginationAsync(IPaginationRequest request) /// public void Dispose() => this._client.ComponentInteractionCreated -= this.Handle; - /// /// Handles the pagination event. /// @@ -93,7 +92,10 @@ private async Task Handle(DiscordClient _, ComponentInteractionCreateEventArgs e if (await req.GetUserAsync().ConfigureAwait(false) != e.User) { if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) - await e.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder { Content = this._config.ResponseMessage, IsEphemeral = true }).ConfigureAwait(false); + await e.Interaction.CreateFollowupMessageAsync(new() + { + Content = this._config.ResponseMessage, IsEphemeral = true + }).ConfigureAwait(false); return; } @@ -124,7 +126,7 @@ private async Task HandlePaginationAsync(IPaginationRequest request, ComponentIn _ when id == buttons.SkipRight.CustomId => request.SkipRightAsync(), _ when id == buttons.Stop.CustomId => Task.FromResult(tcs.TrySetResult(true)), _ when id == buttons.Left.CustomId => request.PreviousPageAsync(), - _ when id == buttons.Right.CustomId => request.NextPageAsync(), + _ when id == buttons.Right.CustomId => request.NextPageAsync() }; await paginationTask.ConfigureAwait(false); @@ -134,7 +136,6 @@ private async Task HandlePaginationAsync(IPaginationRequest request, ComponentIn var page = await request.GetPageAsync().ConfigureAwait(false); - var bts = await request.GetButtonsAsync().ConfigureAwait(false); if (request is InteractionPaginationRequest ipr) @@ -156,6 +157,5 @@ private async Task HandlePaginationAsync(IPaginationRequest request, ComponentIn .AddComponents(bts); await this._builder.ModifyAsync(msg).ConfigureAwait(false); - } } diff --git a/DisCatSharp.Interactivity/EventHandling/Components/ModalEventWaiter.cs b/DisCatSharp.Interactivity/EventHandling/Components/ModalEventWaiter.cs index 0e5c2c7535..af5ffba4bd 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/ModalEventWaiter.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/ModalEventWaiter.cs @@ -33,7 +33,10 @@ public ModalEventWaiter(DiscordClient client, InteractivityConfiguration config) this._client.ComponentInteractionCreated += this.Handle; this._config = config; - this._message = new DiscordFollowupMessageBuilder { Content = config.ResponseMessage ?? "This modal was not meant for you.", IsEphemeral = true }; + this._message = new() + { + Content = config.ResponseMessage ?? "This modal was not meant for you.", IsEphemeral = true + }; } /// @@ -68,13 +71,11 @@ public async Task WaitForModalMatchAsync(Mo private async Task Handle(DiscordClient _, ComponentInteractionCreateEventArgs args) { foreach (var mreq in this._modalMatchRequests) - { if (mreq.CustomId == args.Interaction.Data.CustomId && mreq.IsMatch(args)) mreq.Tcs.TrySetResult(args); else if (this._config.ResponseBehavior is InteractionResponseBehavior.Respond) await args.Interaction.CreateFollowupMessageAsync(this._message).ConfigureAwait(false); - } } /// diff --git a/DisCatSharp.Interactivity/EventHandling/Components/PaginationButtons.cs b/DisCatSharp.Interactivity/EventHandling/Components/PaginationButtons.cs index 49e6a0dd94..b5374021ca 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/PaginationButtons.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/PaginationButtons.cs @@ -38,11 +38,7 @@ public class PaginationButtons /// internal DiscordButtonComponent[] ButtonArray => new[] { - this.SkipLeft, - this.Left, - this.Stop, - this.Right, - this.SkipRight + this.SkipLeft, this.Left, this.Stop, this.Right, this.SkipRight }; public const string SKIP_LEFT_CUSTOM_ID = "pgb-skip-left"; @@ -56,11 +52,11 @@ public class PaginationButtons /// public PaginationButtons() { - this.SkipLeft = new DiscordButtonComponent(ButtonStyle.Secondary, "leftskip", null, false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("⏮"))); - this.Left = new DiscordButtonComponent(ButtonStyle.Secondary, "left", null, false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("◀"))); - this.Stop = new DiscordButtonComponent(ButtonStyle.Secondary, "stop", null, false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("⏹"))); - this.Right = new DiscordButtonComponent(ButtonStyle.Secondary, "right", null, false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶"))); - this.SkipRight = new DiscordButtonComponent(ButtonStyle.Secondary, "rightskip", null, false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("⏭"))); + this.SkipLeft = new(ButtonStyle.Secondary, "leftskip", null, false, new(DiscordEmoji.FromUnicode("⏮"))); + this.Left = new(ButtonStyle.Secondary, "left", null, false, new(DiscordEmoji.FromUnicode("◀"))); + this.Stop = new(ButtonStyle.Secondary, "stop", null, false, new(DiscordEmoji.FromUnicode("⏹"))); + this.Right = new(ButtonStyle.Secondary, "right", null, false, new(DiscordEmoji.FromUnicode("▶"))); + this.SkipRight = new(ButtonStyle.Secondary, "rightskip", null, false, new(DiscordEmoji.FromUnicode("⏭"))); } /// @@ -69,10 +65,10 @@ public PaginationButtons() /// The other . public PaginationButtons(PaginationButtons other) { - this.Stop = new DiscordButtonComponent(other.Stop); - this.Left = new DiscordButtonComponent(other.Left); - this.Right = new DiscordButtonComponent(other.Right); - this.SkipLeft = new DiscordButtonComponent(other.SkipLeft); - this.SkipRight = new DiscordButtonComponent(other.SkipRight); + this.Stop = new(other.Stop); + this.Left = new(other.Left); + this.Right = new(other.Right); + this.SkipLeft = new(other.SkipLeft); + this.SkipRight = new(other.SkipRight); } } diff --git a/DisCatSharp.Interactivity/EventHandling/Components/Requests/ButtonPaginationRequest.cs b/DisCatSharp.Interactivity/EventHandling/Components/Requests/ButtonPaginationRequest.cs index 9f5119ba8b..811b25ce65 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/Requests/ButtonPaginationRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/Requests/ButtonPaginationRequest.cs @@ -36,13 +36,19 @@ internal class ButtonPaginationRequest : IPaginationRequest /// The buttons. /// The pages. /// The token. - public ButtonPaginationRequest(DiscordMessage message, DiscordUser user, - PaginationBehaviour behavior, ButtonPaginationBehavior buttonBehavior, - PaginationButtons buttons, IEnumerable pages, CancellationToken token) + public ButtonPaginationRequest( + DiscordMessage message, + DiscordUser user, + PaginationBehaviour behavior, + ButtonPaginationBehavior buttonBehavior, + PaginationButtons buttons, + IEnumerable pages, + CancellationToken token + ) { this._user = user; this._token = token; - this._buttons = new PaginationButtons(buttons); + this._buttons = new(buttons); this._message = message; this._wrapBehavior = behavior; this._behaviorBehavior = buttonBehavior; diff --git a/DisCatSharp.Interactivity/EventHandling/Components/Requests/InteractionPaginationRequest.cs b/DisCatSharp.Interactivity/EventHandling/Components/Requests/InteractionPaginationRequest.cs index f93019186c..800f93d7d8 100644 --- a/DisCatSharp.Interactivity/EventHandling/Components/Requests/InteractionPaginationRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Components/Requests/InteractionPaginationRequest.cs @@ -19,7 +19,6 @@ internal class InteractionPaginationRequest : IPaginationRequest private readonly TaskCompletionSource _tcs = new(); - private DiscordInteraction _lastInteraction; private CancellationTokenSource _interactionCts; @@ -30,7 +29,6 @@ internal class InteractionPaginationRequest : IPaginationRequest private readonly PaginationBehaviour _wrapBehavior; private readonly ButtonPaginationBehavior _behaviorBehavior; - /// /// Initializes a new instance of the class. /// @@ -42,13 +40,20 @@ internal class InteractionPaginationRequest : IPaginationRequest /// The buttons. /// The pages. /// The token. - public InteractionPaginationRequest(DiscordInteraction interaction, DiscordMessage message, DiscordUser user, - PaginationBehaviour behavior, ButtonPaginationBehavior behaviorBehavior, - PaginationButtons buttons, IEnumerable pages, CancellationToken token) + public InteractionPaginationRequest( + DiscordInteraction interaction, + DiscordMessage message, + DiscordUser user, + PaginationBehaviour behavior, + ButtonPaginationBehavior behaviorBehavior, + PaginationButtons buttons, + IEnumerable pages, + CancellationToken token + ) { this._user = user; this._token = token; - this._buttons = new PaginationButtons(buttons); + this._buttons = new(buttons); this._message = message; this._wrapBehavior = behavior; this._behaviorBehavior = behaviorBehavior; @@ -71,7 +76,7 @@ internal void RegenerateCts(DiscordInteraction interaction) { this._interactionCts?.Dispose(); this._lastInteraction = interaction; - this._interactionCts = new CancellationTokenSource(TimeSpan.FromSeconds((60 * 15) - 5)); + this._interactionCts = new(TimeSpan.FromSeconds(60 * 15 - 5)); this._interactionCts.Token.Register(() => this._tcs.TrySetResult(false)); } diff --git a/DisCatSharp.Interactivity/EventHandling/EventWaiter.cs b/DisCatSharp.Interactivity/EventHandling/EventWaiter.cs index f0acc41f69..739cc18714 100644 --- a/DisCatSharp.Interactivity/EventHandling/EventWaiter.cs +++ b/DisCatSharp.Interactivity/EventHandling/EventWaiter.cs @@ -20,12 +20,12 @@ namespace DisCatSharp.Interactivity.EventHandling; /// internal class EventWaiter : IDisposable where T : AsyncEventArgs { - DiscordClient _client; - AsyncEvent _event; - AsyncEventHandler _handler; - ConcurrentHashSet> _matchRequests; - ConcurrentHashSet> _collectRequests; - bool _disposed; + private DiscordClient _client; + private AsyncEvent _event; + private AsyncEventHandler _handler; + private ConcurrentHashSet> _matchRequests; + private ConcurrentHashSet> _collectRequests; + private bool _disposed; /// /// Creates a new EventWaiter object. @@ -36,10 +36,10 @@ public EventWaiter(DiscordClient client) this._client = client; var tinfo = this._client.GetType().GetTypeInfo(); var handler = tinfo.DeclaredFields.First(x => x.FieldType == typeof(AsyncEvent)); - this._matchRequests = new ConcurrentHashSet>(); - this._collectRequests = new ConcurrentHashSet>(); + this._matchRequests = new(); + this._collectRequests = new(); this._event = (AsyncEvent)handler.GetValue(this._client); - this._handler = new AsyncEventHandler(this.HandleEvent); + this._handler = new(this.HandleEvent); this._event.Register(this._handler); } @@ -65,6 +65,7 @@ public async Task WaitForMatchAsync(MatchRequest request) request.Dispose(); this._matchRequests.TryRemove(request); } + return result; } @@ -86,10 +87,11 @@ public async Task> CollectMatchesAsync(CollectRequest r } finally { - result = new ReadOnlyCollection(new HashSet(request.Collected).ToList()); + result = new(new HashSet(request.Collected).ToList()); request.Dispose(); this._collectRequests.TryRemove(request); } + return result; } @@ -103,20 +105,12 @@ private Task HandleEvent(DiscordClient client, T eventArgs) if (!this._disposed) { foreach (var req in this._matchRequests) - { if (req.Predicate(eventArgs)) - { req.Tcs.TrySetResult(eventArgs); - } - } foreach (var req in this._collectRequests) - { if (req.Predicate(eventArgs)) - { req.Collected.Add(eventArgs); - } - } } return Task.CompletedTask; diff --git a/DisCatSharp.Interactivity/EventHandling/Paginator.cs b/DisCatSharp.Interactivity/EventHandling/Paginator.cs index 6ab00da4ce..9e1bcd93d8 100644 --- a/DisCatSharp.Interactivity/EventHandling/Paginator.cs +++ b/DisCatSharp.Interactivity/EventHandling/Paginator.cs @@ -17,8 +17,8 @@ namespace DisCatSharp.Interactivity.EventHandling; /// internal class Paginator : IPaginator { - DiscordClient _client; - ConcurrentHashSet _requests; + private DiscordClient _client; + private ConcurrentHashSet _requests; /// /// Creates a new EventWaiter object. @@ -27,7 +27,7 @@ internal class Paginator : IPaginator public Paginator(DiscordClient client) { this._client = client; - this._requests = new ConcurrentHashSet(); + this._requests = new(); this._client.MessageReactionAdded += this.HandleReactionAdd; this._client.MessageReactionRemoved += this.HandleReactionRemove; @@ -88,36 +88,26 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs if (eventArgs.User.Id == usr.Id) { if (req.PageCount > 1 && - (eventArgs.Emoji == emojis.Left || - eventArgs.Emoji == emojis.SkipLeft || - eventArgs.Emoji == emojis.Right || - eventArgs.Emoji == emojis.SkipRight || - eventArgs.Emoji == emojis.Stop)) - { + (eventArgs.Emoji == emojis.Left || + eventArgs.Emoji == emojis.SkipLeft || + eventArgs.Emoji == emojis.Right || + eventArgs.Emoji == emojis.SkipRight || + eventArgs.Emoji == emojis.Stop)) await this.PaginateAsync(req, eventArgs.Emoji).ConfigureAwait(false); - } else if (eventArgs.Emoji == emojis.Stop && - req is PaginationRequest paginationRequest && - paginationRequest.PaginationDeletion == PaginationDeletion.DeleteMessage) - { + req is PaginationRequest paginationRequest && + paginationRequest.PaginationDeletion == PaginationDeletion.DeleteMessage) await this.PaginateAsync(req, eventArgs.Emoji).ConfigureAwait(false); - } else - { await msg.DeleteReactionAsync(eventArgs.Emoji, eventArgs.User).ConfigureAwait(false); - } } else if (eventArgs.User.Id != this._client.CurrentUser.Id) - { if (eventArgs.Emoji != emojis.Left && - eventArgs.Emoji != emojis.SkipLeft && - eventArgs.Emoji != emojis.Right && - eventArgs.Emoji != emojis.SkipRight && - eventArgs.Emoji != emojis.Stop) - { + eventArgs.Emoji != emojis.SkipLeft && + eventArgs.Emoji != emojis.Right && + eventArgs.Emoji != emojis.SkipRight && + eventArgs.Emoji != emojis.Stop) await msg.DeleteReactionAsync(eventArgs.Emoji, eventArgs.User).ConfigureAwait(false); - } - } } } }); @@ -143,26 +133,20 @@ private Task HandleReactionRemove(DiscordClient client, MessageReactionRemoveEve var usr = await req.GetUserAsync().ConfigureAwait(false); if (msg.Id == eventArgs.Message.Id) - { if (eventArgs.User.Id == usr.Id) { if (req.PageCount > 1 && - (eventArgs.Emoji == emojis.Left || - eventArgs.Emoji == emojis.SkipLeft || - eventArgs.Emoji == emojis.Right || - eventArgs.Emoji == emojis.SkipRight || - eventArgs.Emoji == emojis.Stop)) - { + (eventArgs.Emoji == emojis.Left || + eventArgs.Emoji == emojis.SkipLeft || + eventArgs.Emoji == emojis.Right || + eventArgs.Emoji == emojis.SkipRight || + eventArgs.Emoji == emojis.Stop)) await this.PaginateAsync(req, eventArgs.Emoji).ConfigureAwait(false); - } else if (eventArgs.Emoji == emojis.Stop && - req is PaginationRequest paginationRequest && - paginationRequest.PaginationDeletion == PaginationDeletion.DeleteMessage) - { + req is PaginationRequest paginationRequest && + paginationRequest.PaginationDeletion == PaginationDeletion.DeleteMessage) await this.PaginateAsync(req, eventArgs.Emoji).ConfigureAwait(false); - } } - } } }); @@ -186,9 +170,7 @@ private Task HandleReactionClear(DiscordClient client, MessageReactionsClearEven var msg = await req.GetMessageAsync().ConfigureAwait(false); if (msg.Id == eventArgs.Message.Id) - { await this.ResetReactionsAsync(req).ConfigureAwait(false); - } } }); @@ -225,9 +207,7 @@ private async Task ResetReactionsAsync(IPaginationRequest p) await msg.CreateReactionAsync(emojis.Stop).ConfigureAwait(false); } else if (emojis.Stop != null && p is PaginationRequest paginationRequest && paginationRequest.PaginationDeletion == PaginationDeletion.DeleteMessage) - { await msg.CreateReactionAsync(emojis.Stop).ConfigureAwait(false); - } } /// diff --git a/DisCatSharp.Interactivity/EventHandling/Poller.cs b/DisCatSharp.Interactivity/EventHandling/Poller.cs index 0ff6933c53..72712d98a0 100644 --- a/DisCatSharp.Interactivity/EventHandling/Poller.cs +++ b/DisCatSharp.Interactivity/EventHandling/Poller.cs @@ -18,8 +18,8 @@ namespace DisCatSharp.Interactivity.EventHandling; /// internal class Poller { - DiscordClient _client; - ConcurrentHashSet _requests; + private DiscordClient _client; + private ConcurrentHashSet _requests; /// /// Creates a new EventWaiter object. @@ -28,7 +28,7 @@ internal class Poller public Poller(DiscordClient client) { this._client = client; - this._requests = new ConcurrentHashSet(); + this._requests = new(); this._client.MessageReactionAdded += this.HandleReactionAdd; this._client.MessageReactionRemoved += this.HandleReactionRemove; @@ -54,10 +54,11 @@ public async Task> DoPollAsync(PollRequest request } finally { - result = new ReadOnlyCollection(new HashSet(request.Collected).ToList()); + result = new(new HashSet(request.Collected).ToList()); request.Dispose(); this._requests.TryRemove(request); } + return result; } @@ -75,7 +76,6 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs _ = Task.Run(async () => { foreach (var req in this._requests) - { // match message if (req.Message.Id == eventArgs.Message.Id && req.Message.ChannelId == eventArgs.Channel.Id) { @@ -91,7 +91,6 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs await eventArgs.Message.DeleteReactionAsync(eventArgs.Emoji, eventArgs.User).ConfigureAwait(false); } } - } }); return Task.CompletedTask; } @@ -105,14 +104,10 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs private Task HandleReactionRemove(DiscordClient client, MessageReactionRemoveEventArgs eventArgs) { foreach (var req in this._requests) - { // match message if (req.Message.Id == eventArgs.Message.Id && req.Message.ChannelId == eventArgs.Channel.Id) - { if (eventArgs.User.Id != this._client.CurrentUser.Id) req.RemoveReaction(eventArgs.Emoji, eventArgs.User); - } - } return Task.CompletedTask; } @@ -125,13 +120,9 @@ private Task HandleReactionRemove(DiscordClient client, MessageReactionRemoveEve private Task HandleReactionClear(DiscordClient client, MessageReactionsClearEventArgs eventArgs) { foreach (var req in this._requests) - { // match message if (req.Message.Id == eventArgs.Message.Id && req.Message.ChannelId == eventArgs.Channel.Id) - { req.ClearCollected(); - } - } return Task.CompletedTask; } diff --git a/DisCatSharp.Interactivity/EventHandling/ReactionCollector.cs b/DisCatSharp.Interactivity/EventHandling/ReactionCollector.cs index ebc1505e3a..52c8cb5c6e 100644 --- a/DisCatSharp.Interactivity/EventHandling/ReactionCollector.cs +++ b/DisCatSharp.Interactivity/EventHandling/ReactionCollector.cs @@ -22,18 +22,18 @@ namespace DisCatSharp.Interactivity.EventHandling; /// internal class ReactionCollector : IDisposable { - DiscordClient _client; + private DiscordClient _client; - AsyncEvent _reactionAddEvent; - AsyncEventHandler _reactionAddHandler; + private AsyncEvent _reactionAddEvent; + private AsyncEventHandler _reactionAddHandler; - AsyncEvent _reactionRemoveEvent; - AsyncEventHandler _reactionRemoveHandler; + private AsyncEvent _reactionRemoveEvent; + private AsyncEventHandler _reactionRemoveHandler; - AsyncEvent _reactionClearEvent; - AsyncEventHandler _reactionClearHandler; + private AsyncEvent _reactionClearEvent; + private AsyncEventHandler _reactionClearHandler; - ConcurrentHashSet _requests; + private ConcurrentHashSet _requests; /// /// Creates a new EventWaiter object. @@ -44,25 +44,25 @@ public ReactionCollector(DiscordClient client) this._client = client; var tinfo = this._client.GetType().GetTypeInfo(); - this._requests = new ConcurrentHashSet(); + this._requests = new(); // Grabbing all three events from client var handler = tinfo.DeclaredFields.First(x => x.FieldType == typeof(AsyncEvent)); this._reactionAddEvent = (AsyncEvent)handler.GetValue(this._client); - this._reactionAddHandler = new AsyncEventHandler(this.HandleReactionAdd); + this._reactionAddHandler = new(this.HandleReactionAdd); this._reactionAddEvent.Register(this._reactionAddHandler); handler = tinfo.DeclaredFields.First(x => x.FieldType == typeof(AsyncEvent)); this._reactionRemoveEvent = (AsyncEvent)handler.GetValue(this._client); - this._reactionRemoveHandler = new AsyncEventHandler(this.HandleReactionRemove); + this._reactionRemoveHandler = new(this.HandleReactionRemove); this._reactionRemoveEvent.Register(this._reactionRemoveHandler); handler = tinfo.DeclaredFields.First(x => x.FieldType == typeof(AsyncEvent)); this._reactionClearEvent = (AsyncEvent)handler.GetValue(this._client); - this._reactionClearHandler = new AsyncEventHandler(this.HandleReactionClear); + this._reactionClearHandler = new(this.HandleReactionClear); this._reactionClearEvent.Register(this._reactionClearHandler); } @@ -86,10 +86,11 @@ public async Task> CollectAsync(ReactionCollectRequ } finally { - result = new ReadOnlyCollection(new HashSet(request.Collected).ToList()); + result = new(new HashSet(request.Collected).ToList()); request.Dispose(); this._requests.TryRemove(request); } + return result; } @@ -103,7 +104,6 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs { // foreach request add foreach (var req in this._requests) - { if (req.Message.Id == eventArgs.Message.Id) { if (req.Collected.Any(x => x.Emoji == eventArgs.Emoji && x.Users.Any(y => y.Id == eventArgs.User.Id))) @@ -114,15 +114,16 @@ private Task HandleReactionAdd(DiscordClient client, MessageReactionAddEventArgs req.Collected.Add(reaction); } else - { - req.Collected.Add(new Reaction() + req.Collected.Add(new() { Emoji = eventArgs.Emoji, - Users = new ConcurrentHashSet() { eventArgs.User } + Users = new() + { + eventArgs.User + } }); - } } - } + return Task.CompletedTask; } @@ -136,9 +137,7 @@ private Task HandleReactionRemove(DiscordClient client, MessageReactionRemoveEve { // foreach request remove foreach (var req in this._requests) - { if (req.Message.Id == eventArgs.Message.Id) - { if (req.Collected.Any(x => x.Emoji == eventArgs.Emoji && x.Users.Any(y => y.Id == eventArgs.User.Id))) { var reaction = req.Collected.First(x => x.Emoji == eventArgs.Emoji && x.Users.Any(y => y.Id == eventArgs.User.Id)); @@ -147,8 +146,7 @@ private Task HandleReactionRemove(DiscordClient client, MessageReactionRemoveEve if (reaction.Users.Count > 0) req.Collected.Add(reaction); } - } - } + return Task.CompletedTask; } @@ -162,12 +160,8 @@ private Task HandleReactionClear(DiscordClient client, MessageReactionsClearEven { // foreach request add foreach (var req in this._requests) - { if (req.Message.Id == eventArgs.Message.Id) - { req.Collected.Clear(); - } - } return Task.CompletedTask; } @@ -219,10 +213,10 @@ public class ReactionCollectRequest : IDisposable public ReactionCollectRequest(DiscordMessage msg, TimeSpan timeout) { this.Message = msg; - this.Collected = new ConcurrentHashSet(); + this.Collected = new(); this.Timeout = timeout; - this.Tcs = new TaskCompletionSource(); - this.Ct = new CancellationTokenSource(this.Timeout); + this.Tcs = new(); + this.Ct = new(this.Timeout); this.Ct.Token.Register(() => this.Tcs.TrySetResult(null)); } @@ -254,10 +248,12 @@ public class Reaction /// Gets the emoji. /// public DiscordEmoji Emoji { get; internal set; } + /// /// Gets the users. /// public ConcurrentHashSet Users { get; internal set; } + /// /// Gets the total. /// diff --git a/DisCatSharp.Interactivity/EventHandling/Requests/CollectRequest.cs b/DisCatSharp.Interactivity/EventHandling/Requests/CollectRequest.cs index 2633f2b878..65dacaa69a 100644 --- a/DisCatSharp.Interactivity/EventHandling/Requests/CollectRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Requests/CollectRequest.cs @@ -28,12 +28,12 @@ internal class CollectRequest : IDisposable where T : AsyncEventArgs /// Timeout time public CollectRequest(Func predicate, TimeSpan timeout) { - this.Tcs = new TaskCompletionSource(); - this.Ct = new CancellationTokenSource(timeout); + this.Tcs = new(); + this.Ct = new(timeout); this.Predicate = predicate; this.Ct.Token.Register(() => this.Tcs.TrySetResult(true)); this.Timeout = timeout; - this.Collected = new ConcurrentHashSet(); + this.Collected = new(); } ~CollectRequest() @@ -55,11 +55,11 @@ public void Dispose() this.Collected.Clear(); this.Collected = null; } + GC.SuppressFinalize(this); } } - /* ^ ^ ( Quack! )> (ミචᆽචミ) diff --git a/DisCatSharp.Interactivity/EventHandling/Requests/MatchRequest.cs b/DisCatSharp.Interactivity/EventHandling/Requests/MatchRequest.cs index 13a64cb49d..7d4c6dde76 100644 --- a/DisCatSharp.Interactivity/EventHandling/Requests/MatchRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Requests/MatchRequest.cs @@ -25,8 +25,8 @@ internal class MatchRequest : IDisposable where T : AsyncEventArgs /// Timeout time public MatchRequest(Func predicate, TimeSpan timeout) { - this.Tcs = new TaskCompletionSource(); - this.Ct = new CancellationTokenSource(timeout); + this.Tcs = new(); + this.Ct = new(timeout); this.Predicate = predicate; this.Ct.Token.Register(() => this.Tcs.TrySetResult(null)); this.Timeout = timeout; diff --git a/DisCatSharp.Interactivity/EventHandling/Requests/PaginationRequest.cs b/DisCatSharp.Interactivity/EventHandling/Requests/PaginationRequest.cs index e619468e83..0739dc118c 100644 --- a/DisCatSharp.Interactivity/EventHandling/Requests/PaginationRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Requests/PaginationRequest.cs @@ -33,11 +33,18 @@ internal class PaginationRequest : IPaginationRequest /// Emojis for this pagination object /// Timeout time /// Pagination pages - internal PaginationRequest(DiscordMessage message, DiscordUser user, PaginationBehaviour behaviour, PaginationDeletion deletion, - PaginationEmojis emojis, TimeSpan timeout, IEnumerable pages) + internal PaginationRequest( + DiscordMessage message, + DiscordUser user, + PaginationBehaviour behaviour, + PaginationDeletion deletion, + PaginationEmojis emojis, + TimeSpan timeout, + IEnumerable pages + ) { - this._tcs = new TaskCompletionSource(); - this._ct = new CancellationTokenSource(timeout); + this._tcs = new(); + this._ct = new(timeout); this._ct.Token.Register(() => this._tcs.TrySetResult(true)); this._timeout = timeout; @@ -48,11 +55,9 @@ internal PaginationRequest(DiscordMessage message, DiscordUser user, PaginationB this._behaviour = behaviour; this._emojis = emojis; - this._pages = new List(); + this._pages = new(); foreach (var p in pages) - { this._pages.Add(p); - } } /// @@ -277,6 +282,7 @@ public class Page /// Gets or sets the content. /// public string Content { get; set; } + /// /// Gets or sets the embed. /// diff --git a/DisCatSharp.Interactivity/EventHandling/Requests/PollRequest.cs b/DisCatSharp.Interactivity/EventHandling/Requests/PollRequest.cs index 4f0fcdf188..a504fc37f1 100644 --- a/DisCatSharp.Interactivity/EventHandling/Requests/PollRequest.cs +++ b/DisCatSharp.Interactivity/EventHandling/Requests/PollRequest.cs @@ -30,18 +30,16 @@ public class PollRequest /// public PollRequest(DiscordMessage message, TimeSpan timeout, IEnumerable emojis) { - this.Tcs = new TaskCompletionSource(); - this.Ct = new CancellationTokenSource(timeout); + this.Tcs = new(); + this.Ct = new(timeout); this.Ct.Token.Register(() => this.Tcs.TrySetResult(true)); this.Timeout = timeout; this.Emojis = emojis.ToList(); - this.Collected = new ConcurrentHashSet(); + this.Collected = new(); this.Message = message; foreach (var e in emojis) - { - this.Collected.Add(new PollEmoji(e)); - } + this.Collected.Add(new(e)); } /// @@ -51,9 +49,7 @@ internal void ClearCollected() { this.Collected.Clear(); foreach (var e in this.Emojis) - { - this.Collected.Add(new PollEmoji(e)); - } + this.Collected.Add(new(e)); } /// @@ -64,7 +60,6 @@ internal void ClearCollected() internal void RemoveReaction(DiscordEmoji emoji, DiscordUser member) { if (this.Collected.Any(x => x.Emoji == emoji)) - { if (this.Collected.Any(x => x.Voted.Contains(member))) { var e = this.Collected.First(x => x.Emoji == emoji); @@ -72,7 +67,6 @@ internal void RemoveReaction(DiscordEmoji emoji, DiscordUser member) e.Voted.TryRemove(member); this.Collected.Add(e); } - } } /// @@ -83,7 +77,6 @@ internal void RemoveReaction(DiscordEmoji emoji, DiscordUser member) internal void AddReaction(DiscordEmoji emoji, DiscordUser member) { if (this.Collected.Any(x => x.Emoji == emoji)) - { if (!this.Collected.Any(x => x.Voted.Contains(member))) { var e = this.Collected.First(x => x.Emoji == emoji); @@ -91,7 +84,6 @@ internal void AddReaction(DiscordEmoji emoji, DiscordUser member) e.Voted.Add(member); this.Collected.Add(e); } - } } ~PollRequest() @@ -121,11 +113,12 @@ public class PollEmoji internal PollEmoji(DiscordEmoji emoji) { this.Emoji = emoji; - this.Voted = new ConcurrentHashSet(); + this.Voted = new(); } public DiscordEmoji Emoji; public ConcurrentHashSet Voted; + /// /// Gets the total. /// diff --git a/DisCatSharp.Interactivity/Extensions/ChannelExtensions.cs b/DisCatSharp.Interactivity/Extensions/ChannelExtensions.cs index 214231aa73..6d7e7e76fc 100644 --- a/DisCatSharp.Interactivity/Extensions/ChannelExtensions.cs +++ b/DisCatSharp.Interactivity/Extensions/ChannelExtensions.cs @@ -54,7 +54,6 @@ public static Task> GetNextMessageAsync(this public static Task> WaitForUserTypingAsync(this DiscordChannel channel, DiscordUser user, TimeSpan? timeoutOverride = null) => GetInteractivity(channel).WaitForUserTypingAsync(user, channel, timeoutOverride); - /// /// Sends a new paginated message. /// @@ -101,7 +100,6 @@ public static Task SendPaginatedMessageAsync(this DiscordChannel channel, Discor public static Task SendPaginatedMessageAsync(this DiscordChannel channel, DiscordUser user, IEnumerable pages, PaginationButtons buttons, TimeSpan? timeoutOverride, PaginationBehaviour? behaviour = default, ButtonPaginationBehavior? deletion = default) => GetInteractivity(channel).SendPaginatedMessageAsync(channel, user, pages, buttons, timeoutOverride, behaviour, deletion); - /// /// Sends the paginated message async. /// diff --git a/DisCatSharp.Interactivity/Extensions/ClientExtensions.cs b/DisCatSharp.Interactivity/Extensions/ClientExtensions.cs index 55c84efe28..b24ddff755 100644 --- a/DisCatSharp.Interactivity/Extensions/ClientExtensions.cs +++ b/DisCatSharp.Interactivity/Extensions/ClientExtensions.cs @@ -22,7 +22,7 @@ public static InteractivityExtension UseInteractivity(this DiscordClient client, { if (client.GetExtension() != null) throw new InvalidOperationException($"Interactivity is already enabled for this {(client.IsShard ? "shard" : "client")}."); - configuration ??= new InteractivityConfiguration(); + configuration ??= new(); var extension = new InteractivityExtension(configuration); client.AddExtension(extension); @@ -68,10 +68,8 @@ public static async Task> GetInt var extensions = new Dictionary(); foreach (var shard in client.ShardClients.Select(xkvp => xkvp.Value)) - { extensions.Add(shard.ShardId, shard.GetExtension()); - } - return new ReadOnlyDictionary(extensions); + return new(extensions); } } diff --git a/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs b/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs index 61d56bd5fa..aaa18d6e93 100644 --- a/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs +++ b/DisCatSharp.Interactivity/Extensions/InteractionExtensions.cs @@ -64,27 +64,34 @@ public static async Task CreatePaginatedModalResponseAsy { await previousInteraction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, b.OpenMessage.AddComponents(b.OpenButton)).ConfigureAwait(false); var originalResponse = await previousInteraction.GetOriginalResponseAsync().ConfigureAwait(false); - var modalOpen = await interactivity.WaitForButtonAsync(originalResponse, new List { b.OpenButton }, timeOutOverride).ConfigureAwait(false); + var modalOpen = await interactivity.WaitForButtonAsync(originalResponse, new List + { + b.OpenButton + }, timeOutOverride).ConfigureAwait(false); if (modalOpen.TimedOut) { _ = previousInteraction.EditOriginalResponseAsync(new DiscordWebhookBuilder().WithContent(b.OpenMessage.Content).AddComponents(b.OpenButton.Disable())); - return new PaginatedModalResponse { TimedOut = true }; + return new() + { + TimedOut = true + }; } await modalOpen.Result.Interaction.CreateInteractionModalResponseAsync(modal).ConfigureAwait(false); } else - { await previousInteraction.CreateInteractionModalResponseAsync(modal).ConfigureAwait(false); - } _ = previousInteraction.EditOriginalResponseAsync(new DiscordWebhookBuilder().WithContent(b.OpenMessage.Content).AddComponents(b.OpenButton.Disable())); var modalResult = await interactivity.WaitForModalAsync(modal.CustomId, timeOutOverride).ConfigureAwait(false); if (modalResult.TimedOut) - return new PaginatedModalResponse { TimedOut = true }; + return new() + { + TimedOut = true + }; foreach (var submissions in modalResult.Result.Interaction.Data.Components) caughtResponses.Add(submissions.CustomId, submissions.Value); @@ -94,6 +101,9 @@ public static async Task CreatePaginatedModalResponseAsy await previousInteraction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral()).ConfigureAwait(false); - return new PaginatedModalResponse { TimedOut = false, Responses = caughtResponses, Interaction = previousInteraction }; + return new() + { + TimedOut = false, Responses = caughtResponses, Interaction = previousInteraction + }; } } diff --git a/DisCatSharp.Interactivity/Extensions/MessageExtensions.cs b/DisCatSharp.Interactivity/Extensions/MessageExtensions.cs index 7c8f44c7c5..6d056acab2 100644 --- a/DisCatSharp.Interactivity/Extensions/MessageExtensions.cs +++ b/DisCatSharp.Interactivity/Extensions/MessageExtensions.cs @@ -33,6 +33,7 @@ public static Task> GetNextMessageAsync(this /// Overrides the timeout set in public static Task> GetNextMessageAsync(this DiscordMessage message, Func predicate, TimeSpan? timeoutOverride = null) => message.Channel.GetNextMessageAsync(msg => msg.Author.Id == message.Author.Id && message.ChannelId == msg.ChannelId && predicate(msg), timeoutOverride); + /// /// Waits for any button to be pressed on the specified message. /// @@ -47,6 +48,7 @@ public static Task> Wai /// Overrides the timeout set in public static Task> WaitForButtonAsync(this DiscordMessage message, TimeSpan? timeoutOverride = null) => GetInteractivity(message).WaitForButtonAsync(message, timeoutOverride); + /// /// Waits for any button to be pressed on the specified message. /// @@ -54,6 +56,7 @@ public static Task> Wai /// A custom cancellation token that can be cancelled at any point. public static Task> WaitForButtonAsync(this DiscordMessage message, CancellationToken token) => GetInteractivity(message).WaitForButtonAsync(message, token); + /// /// Waits for a button with the specified Id to be pressed on the specified message. /// @@ -119,7 +122,6 @@ public static Task> Wai public static Task> WaitForSelectAsync(this DiscordMessage message, Func predicate, ComponentType selectType, TimeSpan? timeoutOverride = null) => GetInteractivity(message).WaitForSelectAsync(message, predicate, selectType, timeoutOverride); - /// /// Waits for any dropdown to be interacted with. /// @@ -171,7 +173,7 @@ public static Task> Wai /// The type of the select menu. /// A custom cancellation token that can be cancelled at any point. public static Task> WaitForSelectAsync(this DiscordMessage message, DiscordUser user, string id, ComponentType selectType, CancellationToken token) - => GetInteractivity(message).WaitForSelectAsync(message, user, id, selectType, token); + => GetInteractivity(message).WaitForSelectAsync(message, user, id, selectType, token); /// /// Waits for a reaction on this message from a specific user. @@ -203,7 +205,6 @@ public static Task> WaitForReac public static Task> CollectReactionsAsync(this DiscordMessage message, TimeSpan? timeoutOverride = null) => GetInteractivity(message).CollectReactionsAsync(message, timeoutOverride); - /// /// Begins a poll using this message. /// diff --git a/DisCatSharp.Interactivity/Helpers/InteractivityHelpers.cs b/DisCatSharp.Interactivity/Helpers/InteractivityHelpers.cs index 0186b7bd62..da316d5b1c 100644 --- a/DisCatSharp.Interactivity/Helpers/InteractivityHelpers.cs +++ b/DisCatSharp.Interactivity/Helpers/InteractivityHelpers.cs @@ -18,6 +18,7 @@ public static List Recalculate(this List pages) recalulatedPages.Add(tempPage); pageCount++; } + return recalulatedPages; } } diff --git a/DisCatSharp.Interactivity/InteractivityConfiguration.cs b/DisCatSharp.Interactivity/InteractivityConfiguration.cs index 5be5c87180..bb75306018 100644 --- a/DisCatSharp.Interactivity/InteractivityConfiguration.cs +++ b/DisCatSharp.Interactivity/InteractivityConfiguration.cs @@ -68,8 +68,7 @@ public sealed class InteractivityConfiguration /// [ActivatorUtilitiesConstructor] public InteractivityConfiguration() - { - } + { } /// /// Creates a new instance of , copying the properties of another configuration. diff --git a/DisCatSharp.Interactivity/InteractivityExtension.cs b/DisCatSharp.Interactivity/InteractivityExtension.cs index 5eb7ed900f..ebdcc7b77a 100644 --- a/DisCatSharp.Interactivity/InteractivityExtension.cs +++ b/DisCatSharp.Interactivity/InteractivityExtension.cs @@ -19,7 +19,6 @@ namespace DisCatSharp.Interactivity; /// public class InteractivityExtension : BaseExtension { - /// /// Gets the config. /// @@ -44,7 +43,7 @@ public class InteractivityExtension : BaseExtension private Poller _poller; private Paginator _paginator; - private ComponentPaginator _compPaginator; + private ComponentPaginator _compPaginator; /// /// Initializes a new instance of the class. @@ -52,7 +51,7 @@ public class InteractivityExtension : BaseExtension /// The configuration. internal InteractivityExtension(InteractivityConfiguration cfg) { - this.Config = new InteractivityConfiguration(cfg); + this.Config = new(cfg); } /// @@ -62,18 +61,17 @@ internal InteractivityExtension(InteractivityConfiguration cfg) protected internal override void Setup(DiscordClient client) { this.Client = client; - this._messageCreatedWaiter = new EventWaiter(this.Client); - this._messageReactionAddWaiter = new EventWaiter(this.Client); - this._componentInteractionWaiter = new EventWaiter(this.Client); - this._modalInteractionWaiter = new EventWaiter(this.Client); - this._typingStartWaiter = new EventWaiter(this.Client); - this._poller = new Poller(this.Client); - this._reactionCollector = new ReactionCollector(this.Client); - this._paginator = new Paginator(this.Client); - this._compPaginator = new ComponentPaginator(this.Client, this.Config); - this._componentEventWaiter = new ComponentEventWaiter(this.Client, this.Config); - this._modalEventWaiter = new ModalEventWaiter(this.Client, this.Config); - + this._messageCreatedWaiter = new(this.Client); + this._messageReactionAddWaiter = new(this.Client); + this._componentInteractionWaiter = new(this.Client); + this._modalInteractionWaiter = new(this.Client); + this._typingStartWaiter = new(this.Client); + this._poller = new(this.Client); + this._reactionCollector = new(this.Client); + this._paginator = new(this.Client); + this._compPaginator = new(this.Client, this.Config); + this._componentEventWaiter = new(this.Client, this.Config); + this._modalEventWaiter = new(this.Client, this.Config); } /// @@ -95,7 +93,7 @@ public async Task> DoPollAsync(DiscordMessage m, I foreach (var em in emojis) await m.CreateReactionAsync(em).ConfigureAwait(false); - var res = await this._poller.DoPollAsync(new PollRequest(m, timeout ?? this.Config.Timeout, emojis)).ConfigureAwait(false); + var res = await this._poller.DoPollAsync(new(m, timeout ?? this.Config.Timeout, emojis)).ConfigureAwait(false); var pollBehaviour = behaviour ?? this.Config.PollBehaviour; var thisMember = await m.Channel.Guild.GetMemberAsync(this.Client.CurrentUser.Id).ConfigureAwait(false); @@ -103,7 +101,7 @@ public async Task> DoPollAsync(DiscordMessage m, I if (pollBehaviour == PollBehaviour.DeleteEmojis && m.Channel.PermissionsFor(thisMember).HasPermission(Permissions.ManageMessages)) await m.DeleteAllReactionsAsync().ConfigureAwait(false); - return new ReadOnlyCollection(res.ToList()); + return new(res.ToList()); } /// @@ -127,7 +125,7 @@ public Task> WaitForBut /// A with the result of button that was pressed, if any. /// Thrown when attempting to wait for a message that is not authored by the current user. /// Thrown when the message does not contain a button with the specified Id, or any buttons at all. - public async Task> WaitForButtonAsync(DiscordMessage message, IEnumerable buttons, CancellationToken token) + public async Task> WaitForButtonAsync(DiscordMessage message, IEnumerable buttons, CancellationToken token) { if (message.Author != this.Client.CurrentUser) throw new InvalidOperationException("Interaction events are only sent to the application that created them."); @@ -142,12 +140,12 @@ public async Task> Wait throw new ArgumentException("Provided Message does not contain any button components."); var res = await this._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, + .WaitForMatchAsync(new(message, c => c.Interaction.Data.ComponentType == ComponentType.Button && buttons.Any(b => b.CustomId == c.Id), token)).ConfigureAwait(false); - return new InteractivityResult(res is null, res); + return new(res is null, res); } /// @@ -156,8 +154,8 @@ public async Task> Wait /// The custom id of the modal to wait for. /// Override the timeout period specified in . /// A with the result of the modal. - public Task> WaitForModalAsync(string customId, TimeSpan? timeoutOverride = null) - => this.WaitForModalAsync(customId, this.GetCancellationToken(timeoutOverride)); + public Task> WaitForModalAsync(string customId, TimeSpan? timeoutOverride = null) + => this.WaitForModalAsync(customId, this.GetCancellationToken(timeoutOverride)); /// /// Waits for a user modal submit. @@ -169,11 +167,11 @@ public async Task> Wait { var result = await this - ._modalEventWaiter - .WaitForModalMatchAsync(new ModalMatchRequest(customId, c => c.Interaction.Type == InteractionType.ModalSubmit, token)) - .ConfigureAwait(false); + ._modalEventWaiter + .WaitForModalMatchAsync(new(customId, c => c.Interaction.Type == InteractionType.ModalSubmit, token)) + .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } /// @@ -210,11 +208,11 @@ public async Task> Wait var result = await this - ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, c => c.Interaction.Data.ComponentType == ComponentType.Button && ids.Contains(c.Id), token)) - .ConfigureAwait(false); + ._componentEventWaiter + .WaitForMatchAsync(new(message, c => c.Interaction.Data.ComponentType == ComponentType.Button && ids.Contains(c.Id), token)) + .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } /// @@ -251,11 +249,10 @@ public async Task> Wait var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, (c) => c.Interaction.Data.ComponentType is ComponentType.Button && c.User == user, token)) + .WaitForMatchAsync(new(message, (c) => c.Interaction.Data.ComponentType is ComponentType.Button && c.User == user, token)) .ConfigureAwait(false); - return new InteractivityResult(result is null, result); - + return new(result is null, result); } /// @@ -292,12 +289,13 @@ public async Task> Wait if (!message.Components.SelectMany(c => c.Components).OfType().Any(c => c.CustomId == id)) throw new ArgumentException($"Message does not contain button with Id of '{id}'."); + var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, (c) => c.Interaction.Data.ComponentType is ComponentType.Button && c.Id == id, token)) + .WaitForMatchAsync(new(message, (c) => c.Interaction.Data.ComponentType is ComponentType.Button && c.Id == id, token)) .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } /// @@ -328,13 +326,12 @@ public async Task> Wait var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, c => c.Interaction.Data.ComponentType is ComponentType.Button && predicate(c), token)) + .WaitForMatchAsync(new(message, c => c.Interaction.Data.ComponentType is ComponentType.Button && predicate(c), token)) .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } - /// /// Waits for any dropdown to be interacted with. /// @@ -367,10 +364,10 @@ public async Task> Wait var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, c => c.Interaction.Data.ComponentType == selectType && predicate(c), token)) + .WaitForMatchAsync(new(message, c => c.Interaction.Data.ComponentType == selectType && predicate(c), token)) .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } /// @@ -409,10 +406,10 @@ public async Task> Wait var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, (c) => c.Interaction.Data.ComponentType == selectType && c.Id == id, token)) + .WaitForMatchAsync(new(message, (c) => c.Interaction.Data.ComponentType == selectType && c.Id == id, token)) .ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } /// @@ -452,27 +449,28 @@ public async Task> Wait var result = await this ._componentEventWaiter - .WaitForMatchAsync(new ComponentMatchRequest(message, (c) => c.Id == id && c.User == user, token)).ConfigureAwait(false); + .WaitForMatchAsync(new(message, (c) => c.Id == id && c.User == user, token)).ConfigureAwait(false); - return new InteractivityResult(result is null, result); + return new(result is null, result); } - /// /// Waits for a specific message. /// /// Predicate to match. /// Override timeout period. - public async Task> WaitForMessageAsync(Func predicate, - TimeSpan? timeoutOverride = null) + public async Task> WaitForMessageAsync( + Func predicate, + TimeSpan? timeoutOverride = null + ) { if (!Utilities.HasMessageIntents(this.Client.Configuration.Intents)) throw new InvalidOperationException("No message intents are enabled."); var timeout = timeoutOverride ?? this.Config.Timeout; - var returns = await this._messageCreatedWaiter.WaitForMatchAsync(new MatchRequest(x => predicate(x.Message), timeout)).ConfigureAwait(false); + var returns = await this._messageCreatedWaiter.WaitForMatchAsync(new(x => predicate(x.Message), timeout)).ConfigureAwait(false); - return new InteractivityResult(returns == null, returns?.Message); + return new(returns == null, returns?.Message); } /// @@ -480,16 +478,18 @@ public async Task> WaitForMessageAsync(Func< /// /// Predicate to match. /// Override timeout period. - public async Task> WaitForReactionAsync(Func predicate, - TimeSpan? timeoutOverride = null) + public async Task> WaitForReactionAsync( + Func predicate, + TimeSpan? timeoutOverride = null + ) { if (!Utilities.HasReactionIntents(this.Client.Configuration.Intents)) throw new InvalidOperationException("No reaction intents are enabled."); var timeout = timeoutOverride ?? this.Config.Timeout; - var returns = await this._messageReactionAddWaiter.WaitForMatchAsync(new MatchRequest(predicate, timeout)).ConfigureAwait(false); + var returns = await this._messageReactionAddWaiter.WaitForMatchAsync(new(predicate, timeout)).ConfigureAwait(false); - return new InteractivityResult(returns == null, returns); + return new(returns == null, returns); } /// @@ -499,8 +499,11 @@ public async Task> WaitForReact /// Message reaction was added to. /// User that made the reaction. /// Override timeout period. - public async Task> WaitForReactionAsync(DiscordMessage message, DiscordUser user, - TimeSpan? timeoutOverride = null) + public async Task> WaitForReactionAsync( + DiscordMessage message, + DiscordUser user, + TimeSpan? timeoutOverride = null + ) => await this.WaitForReactionAsync(x => x.User.Id == user.Id && x.Message.Id == message.Id, timeoutOverride).ConfigureAwait(false); /// @@ -511,8 +514,12 @@ public async Task> WaitForReact /// Message reaction was added to. /// User that made the reaction. /// Override timeout period. - public async Task> WaitForReactionAsync(Func predicate, - DiscordMessage message, DiscordUser user, TimeSpan? timeoutOverride = null) + public async Task> WaitForReactionAsync( + Func predicate, + DiscordMessage message, + DiscordUser user, + TimeSpan? timeoutOverride = null + ) => await this.WaitForReactionAsync(x => predicate(x) && x.User.Id == user.Id && x.Message.Id == message.Id, timeoutOverride).ConfigureAwait(false); /// @@ -522,8 +529,11 @@ public async Task> WaitForReact /// predicate to match. /// User that made the reaction. /// Override timeout period. - public async Task> WaitForReactionAsync(Func predicate, - DiscordUser user, TimeSpan? timeoutOverride = null) + public async Task> WaitForReactionAsync( + Func predicate, + DiscordUser user, + TimeSpan? timeoutOverride = null + ) => await this.WaitForReactionAsync(x => predicate(x) && x.User.Id == user.Id, timeoutOverride).ConfigureAwait(false); /// @@ -532,18 +542,21 @@ public async Task> WaitForReact /// User that starts typing. /// Channel the user is typing in. /// Override timeout period. - public async Task> WaitForUserTypingAsync(DiscordUser user, - DiscordChannel channel, TimeSpan? timeoutOverride = null) + public async Task> WaitForUserTypingAsync( + DiscordUser user, + DiscordChannel channel, + TimeSpan? timeoutOverride = null + ) { if (!Utilities.HasTypingIntents(this.Client.Configuration.Intents)) throw new InvalidOperationException("No typing intents are enabled."); var timeout = timeoutOverride ?? this.Config.Timeout; var returns = await this._typingStartWaiter.WaitForMatchAsync( - new MatchRequest(x => x.User.Id == user.Id && x.Channel.Id == channel.Id, timeout)) + new(x => x.User.Id == user.Id && x.Channel.Id == channel.Id, timeout)) .ConfigureAwait(false); - return new InteractivityResult(returns == null, returns); + return new(returns == null, returns); } /// @@ -558,10 +571,10 @@ public async Task> WaitForUserTypingAs var timeout = timeoutOverride ?? this.Config.Timeout; var returns = await this._typingStartWaiter.WaitForMatchAsync( - new MatchRequest(x => x.User.Id == user.Id, timeout)) + new(x => x.User.Id == user.Id, timeout)) .ConfigureAwait(false); - return new InteractivityResult(returns == null, returns); + return new(returns == null, returns); } /// @@ -576,10 +589,10 @@ public async Task> WaitForTypingAsync( var timeout = timeoutOverride ?? this.Config.Timeout; var returns = await this._typingStartWaiter.WaitForMatchAsync( - new MatchRequest(x => x.Channel.Id == channel.Id, timeout)) + new(x => x.Channel.Id == channel.Id, timeout)) .ConfigureAwait(false); - return new InteractivityResult(returns == null, returns); + return new(returns == null, returns); } /// @@ -593,7 +606,7 @@ public async Task> CollectReactionsAsync(DiscordMes throw new InvalidOperationException("No reaction intents are enabled."); var timeout = timeoutOverride ?? this.Config.Timeout; - var collection = await this._reactionCollector.CollectAsync(new ReactionCollectRequest(m, timeout)).ConfigureAwait(false); + var collection = await this._reactionCollector.CollectAsync(new(m, timeout)).ConfigureAwait(false); return collection; } @@ -609,8 +622,8 @@ public async Task> WaitForEventArgsAsync(Func var timeout = timeoutOverride ?? this.Config.Timeout; using var waiter = new EventWaiter(this.Client); - var res = await waiter.WaitForMatchAsync(new MatchRequest(predicate, timeout)).ConfigureAwait(false); - return new InteractivityResult(res == null, res); + var res = await waiter.WaitForMatchAsync(new(predicate, timeout)).ConfigureAwait(false); + return new(res == null, res); } /// @@ -623,7 +636,7 @@ public async Task> CollectEventArgsAsync(Func var timeout = timeoutOverride ?? this.Config.Timeout; using var waiter = new EventWaiter(this.Client); - var res = await waiter.CollectMatchesAsync(new CollectRequest(predicate, timeout)).ConfigureAwait(false); + var res = await waiter.CollectMatchesAsync(new(predicate, timeout)).ConfigureAwait(false); return res; } @@ -638,14 +651,20 @@ public async Task> CollectEventArgsAsync(Func /// Deletion behaviour. /// A custom cancellation token that can be cancelled at any point. public async Task SendPaginatedMessageAsync( - DiscordChannel channel, DiscordUser user, IEnumerable pages, PaginationButtons buttons, - PaginationBehaviour? behaviour = default, ButtonPaginationBehavior? deletion = default, CancellationToken token = default) + DiscordChannel channel, + DiscordUser user, + IEnumerable pages, + PaginationButtons buttons, + PaginationBehaviour? behaviour = default, + ButtonPaginationBehavior? deletion = default, + CancellationToken token = default + ) { var bhv = behaviour ?? this.Config.PaginationBehaviour; var del = deletion ?? this.Config.ButtonBehavior; var bts = buttons ?? this.Config.PaginationButtons; - bts = new PaginationButtons(bts); + bts = new(bts); if (bhv is PaginationBehaviour.Ignore) { bts.SkipLeft.Disable(); @@ -675,8 +694,14 @@ public async Task SendPaginatedMessageAsync( /// Deletion behaviour. /// Override timeout period. public Task SendPaginatedMessageAsync( - DiscordChannel channel, DiscordUser user, IEnumerable pages, PaginationButtons buttons, TimeSpan? timeoutOverride, - PaginationBehaviour? behaviour = default, ButtonPaginationBehavior? deletion = default) + DiscordChannel channel, + DiscordUser user, + IEnumerable pages, + PaginationButtons buttons, + TimeSpan? timeoutOverride, + PaginationBehaviour? behaviour = default, + ButtonPaginationBehavior? deletion = default + ) => this.SendPaginatedMessageAsync(channel, user, pages, buttons, behaviour, deletion, this.GetCancellationToken(timeoutOverride)); /// @@ -716,8 +741,15 @@ public Task SendPaginatedMessageAsync(DiscordChannel channel, DiscordUser user, /// Pagination behaviour (when hitting max and min indices). /// Deletion behaviour. /// Override timeout period. - public async Task SendPaginatedMessageAsync(DiscordChannel channel, DiscordUser user, IEnumerable pages, PaginationEmojis emojis, - PaginationBehaviour? behaviour = default, PaginationDeletion? deletion = default, TimeSpan? timeoutOverride = null) + public async Task SendPaginatedMessageAsync( + DiscordChannel channel, + DiscordUser user, + IEnumerable pages, + PaginationEmojis emojis, + PaginationBehaviour? behaviour = default, + PaginationDeletion? deletion = default, + TimeSpan? timeoutOverride = null + ) { var builder = new DiscordMessageBuilder() .WithContent(pages.First().Content) @@ -756,7 +788,7 @@ public async Task SendPaginatedResponseAsync(DiscordInteraction interaction, boo var del = deletion ?? this.Config.ButtonBehavior; var bts = buttons ?? this.Config.PaginationButtons; - bts = new PaginationButtons(bts); + bts = new(bts); if (bhv is PaginationBehaviour.Ignore) { bts.SkipLeft.Disable(); @@ -777,17 +809,17 @@ public async Task SendPaginatedResponseAsync(DiscordInteraction interaction, boo if (deferred) { var builder = new DiscordWebhookBuilder() - .WithContent(pages.First().Content) - .AddEmbed(pages.First().Embed) - .AddComponents(bts.ButtonArray); + .WithContent(pages.First().Content) + .AddEmbed(pages.First().Embed) + .AddComponents(bts.ButtonArray); message = await interaction.EditOriginalResponseAsync(builder).ConfigureAwait(false); } else { var builder = new DiscordInteractionResponseBuilder() - .WithContent(pages.First().Content) - .AddEmbed(pages.First().Embed) - .AddComponents(bts.ButtonArray); + .WithContent(pages.First().Content) + .AddEmbed(pages.First().Embed) + .AddComponents(bts.ButtonArray); if (ephemeral) builder = builder.AsEphemeral(); await interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder).ConfigureAwait(false); @@ -799,7 +831,6 @@ public async Task SendPaginatedResponseAsync(DiscordInteraction interaction, boo await this._compPaginator.DoPaginationAsync(req).ConfigureAwait(false); } - /// /// Waits for a custom pagination request to finish. /// This does NOT handle removing emojis after finishing for you. @@ -839,7 +870,7 @@ public IEnumerable GeneratePagesInContent(string input, SplitType splitTyp case SplitType.Line: var subsplit = input.Split('\n'); - split = new List(); + split = new(); var s = ""; for (var i = 0; i < subsplit.Length; i++) @@ -851,6 +882,7 @@ public IEnumerable GeneratePagesInContent(string input, SplitType splitTyp s = ""; } } + if (split.All(x => x != s)) split.Add(s); break; @@ -859,7 +891,7 @@ public IEnumerable GeneratePagesInContent(string input, SplitType splitTyp var page = 1; foreach (var s in split) { - result.Add(new Page($"Page {page}:\n{s}")); + result.Add(new($"Page {page}:\n{s}")); page++; } @@ -892,7 +924,7 @@ public IEnumerable GeneratePagesInEmbed(string input, SplitType splitType case SplitType.Line: var subsplit = input.Split('\n'); - split = new List(); + split = new(); var s = ""; for (var i = 0; i < subsplit.Length; i++) @@ -904,6 +936,7 @@ public IEnumerable GeneratePagesInEmbed(string input, SplitType splitType s = ""; } } + if (!split.Any(x => x == s)) split.Add(s); break; @@ -912,7 +945,7 @@ public IEnumerable GeneratePagesInEmbed(string input, SplitType splitType var page = 1; foreach (var s in split) { - result.Add(new Page("", new DiscordEmbedBuilder(embed).WithDescription(s).WithFooter($"Page {page}/{split.Count}"))); + result.Add(new("", new DiscordEmbedBuilder(embed).WithDescription(s).WithFooter($"Page {page}/{split.Count}"))); page++; } @@ -955,7 +988,10 @@ private async Task HandleInvalidInteraction(DiscordInteraction interaction) var at = this.Config.ResponseBehavior switch { InteractionResponseBehavior.Ack => interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate), - InteractionResponseBehavior.Respond => interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder { Content = this.Config.ResponseMessage, IsEphemeral = true}), + InteractionResponseBehavior.Respond => interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new() + { + Content = this.Config.ResponseMessage, IsEphemeral = true + }), InteractionResponseBehavior.Ignore => Task.CompletedTask, _ => throw new ArgumentException("Unknown enum value.") }; diff --git a/DisCatSharp.Interactivity/InteractivityResult.cs b/DisCatSharp.Interactivity/InteractivityResult.cs index 4749317c41..c0db7b8b4d 100644 --- a/DisCatSharp.Interactivity/InteractivityResult.cs +++ b/DisCatSharp.Interactivity/InteractivityResult.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Interactivity; /// @@ -11,6 +10,7 @@ public readonly struct InteractivityResult /// Whether interactivity was timed out /// public bool TimedOut { get; } + /// /// Result /// diff --git a/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj b/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj index 14ae416f24..734d68555e 100644 --- a/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj +++ b/DisCatSharp.Lavalink/DisCatSharp.Lavalink.csproj @@ -1,47 +1,48 @@ + - - - - - - - - - DisCatSharp.Lavalink - DisCatSharp.Lavalink - true - - - - DisCatSharp.Lavalink - - DisCatSharp Lavalink V4 Extension - - Extend your bot with the full power of lavalink. - Play your favorite music in discord! - - Requires Lavalink Server v4 - - Documentation: https://docs.dcs.aitsys.dev/articles/modules/audio/lavalink_v4/intro.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Lavalink,Lavalink V4,Audio Player,Music,YouTube,Spotify,SoundCloud,Twitch,Vimeo,BandCamp,Apple Music,Yandex Music,Spotify,Spotify Recommendations,Deezer,Deezer ISRC,Local Music,Direct Url Music - annotations - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + + + + DisCatSharp.Lavalink + DisCatSharp.Lavalink + true + + + + DisCatSharp.Lavalink + + DisCatSharp Lavalink V4 Extension + + Extend your bot with the full power of lavalink. + Play your favorite music in discord! + + Requires Lavalink Server v4 + + Documentation: https://docs.dcs.aitsys.dev/articles/modules/audio/lavalink_v4/intro.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Lavalink,Lavalink V4,Audio Player,Music,YouTube,Spotify,SoundCloud,Twitch,Vimeo,BandCamp,Apple Music,Yandex Music,Spotify,Spotify Recommendations,Deezer,Deezer ISRC,Local Music,Direct Url Music + annotations + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/DisCatSharp.Lavalink/Entities/Filters/IPluginFilter.cs b/DisCatSharp.Lavalink/Entities/Filters/IPluginFilter.cs index 10490bed2f..288decd711 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/IPluginFilter.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/IPluginFilter.cs @@ -1,10 +1,7 @@ - namespace DisCatSharp.Lavalink.Entities.Filters; /// /// Represents an plugin filter. /// public interface IPluginFilter -{ - -} +{ } diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkChannelMix.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkChannelMix.cs index 62f034d652..eef22201c1 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkChannelMix.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkChannelMix.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkDisortion.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkDisortion.cs index 3a804351e6..98fd864307 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkDisortion.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkDisortion.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkEqualizer.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkEqualizer.cs index a6c7e1764d..3f6eeadcc9 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkEqualizer.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkEqualizer.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums.Filters; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkFilters.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkFilters.cs index ca558a7979..43c350e7a0 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkFilters.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkFilters.cs @@ -1,4 +1,3 @@ - using System.Collections.Generic; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkKaraoke.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkKaraoke.cs index b7f8fa89ce..24aa1af9b4 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkKaraoke.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkKaraoke.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkLowPass.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkLowPass.cs index 565522e334..21d8a5a9f9 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkLowPass.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkLowPass.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkRotation.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkRotation.cs index 95dcaf3969..695f164c8a 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkRotation.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkRotation.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkTimescale.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkTimescale.cs index b13ec1bec5..a3b9ef8ba6 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkTimescale.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkTimescale.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkTremolo.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkTremolo.cs index 4ba062492f..c3b4730ecb 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkTremolo.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkTremolo.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Filters/LavalinkVibrato.cs b/DisCatSharp.Lavalink/Entities/Filters/LavalinkVibrato.cs index b2da6ee9ef..1d355b55f3 100644 --- a/DisCatSharp.Lavalink/Entities/Filters/LavalinkVibrato.cs +++ b/DisCatSharp.Lavalink/Entities/Filters/LavalinkVibrato.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/IQueueEntry.cs b/DisCatSharp.Lavalink/Entities/IQueueEntry.cs index f383cca6eb..c8c9b9a851 100644 --- a/DisCatSharp.Lavalink/Entities/IQueueEntry.cs +++ b/DisCatSharp.Lavalink/Entities/IQueueEntry.cs @@ -1,4 +1,3 @@ - using System.Threading.Tasks; namespace DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkException.cs b/DisCatSharp.Lavalink/Entities/LavalinkException.cs index d0380ba65a..386d6c0526 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkException.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkException.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkInfo.cs b/DisCatSharp.Lavalink/Entities/LavalinkInfo.cs index c17ce237b7..a3e689669f 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkInfo.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkInfo.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; @@ -22,6 +21,7 @@ public sealed class LavalinkInfo /// [JsonIgnore] public DateTimeOffset BuildTime => Utilities.GetDateTimeOffsetFromMilliseconds(this._buildTime); + /// /// Gets the timestamp when this version was built. /// @@ -158,4 +158,3 @@ public sealed class Version [JsonProperty("build")] public string? Build { get; internal set; } } - diff --git a/DisCatSharp.Lavalink/Entities/LavalinkPlayer.cs b/DisCatSharp.Lavalink/Entities/LavalinkPlayer.cs index 34a54709d3..e3f99625df 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkPlayer.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkPlayer.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Entities.Filters; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkPlayerState.cs b/DisCatSharp.Lavalink/Entities/LavalinkPlayerState.cs index 348702e893..acfc3cb0e4 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkPlayerState.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkPlayerState.cs @@ -1,4 +1,3 @@ - using System; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkPlaylist.cs b/DisCatSharp.Lavalink/Entities/LavalinkPlaylist.cs index 8f55ce4829..a55029e408 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkPlaylist.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkPlaylist.cs @@ -1,4 +1,3 @@ - using System.Collections.Generic; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkPlaylistInfo.cs b/DisCatSharp.Lavalink/Entities/LavalinkPlaylistInfo.cs index 5749be3652..78740877df 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkPlaylistInfo.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkPlaylistInfo.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkRestResponse.cs b/DisCatSharp.Lavalink/Entities/LavalinkRestResponse.cs index f649217bfd..7d9b201e3d 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkRestResponse.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkRestResponse.cs @@ -1,4 +1,3 @@ - using System.Net; using System.Net.Http.Headers; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkSessionConfiguration.cs b/DisCatSharp.Lavalink/Entities/LavalinkSessionConfiguration.cs index c6ec7eb03b..21dbf0e0c9 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkSessionConfiguration.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkSessionConfiguration.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkStats.cs b/DisCatSharp.Lavalink/Entities/LavalinkStats.cs index 189c74fdcb..79da5ba39b 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkStats.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkStats.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkTrack.cs b/DisCatSharp.Lavalink/Entities/LavalinkTrack.cs index bde437acff..2f3d7f93af 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkTrack.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkTrack.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; @@ -81,6 +80,7 @@ public sealed class LavalinkTrackInfo /// [JsonIgnore] public TimeSpan Length => !this.IsStream ? TimeSpan.FromMilliseconds(this.LengthInternal) : TimeSpan.Zero; + [JsonProperty("length")] internal long LengthInternal; @@ -95,6 +95,7 @@ public sealed class LavalinkTrackInfo /// [JsonIgnore] public TimeSpan Position => TimeSpan.FromMilliseconds(this.PositionInternal); + [JsonProperty("position")] internal long PositionInternal; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkTrackLoadingResult.cs b/DisCatSharp.Lavalink/Entities/LavalinkTrackLoadingResult.cs index dd16fd540b..ec7eaa98a7 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkTrackLoadingResult.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkTrackLoadingResult.cs @@ -1,4 +1,3 @@ - using System.Collections.Generic; using System.IO; diff --git a/DisCatSharp.Lavalink/Entities/LavalinkVoiceState.cs b/DisCatSharp.Lavalink/Entities/LavalinkVoiceState.cs index bfccca6ed1..5fd0216f82 100644 --- a/DisCatSharp.Lavalink/Entities/LavalinkVoiceState.cs +++ b/DisCatSharp.Lavalink/Entities/LavalinkVoiceState.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/EventOP.cs b/DisCatSharp.Lavalink/Entities/Websocket/EventOP.cs index f47dba4079..2df1198e43 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/EventOP.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/EventOP.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums.Websocket; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/LavalinkOp.cs b/DisCatSharp.Lavalink/Entities/Websocket/LavalinkOp.cs index 83d8cb4a19..4eac00c3ad 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/LavalinkOp.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/LavalinkOp.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums.Websocket; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/PlayerUpdateOp.cs b/DisCatSharp.Lavalink/Entities/Websocket/PlayerUpdateOp.cs index a9e6fbdca4..6a6b21954b 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/PlayerUpdateOp.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/PlayerUpdateOp.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/ReadyOp.cs b/DisCatSharp.Lavalink/Entities/Websocket/ReadyOp.cs index 3a097dd94a..5f4905639f 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/ReadyOp.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/ReadyOp.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/StatsOp.cs b/DisCatSharp.Lavalink/Entities/Websocket/StatsOp.cs index 5cf345eccc..7922996bf4 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/StatsOp.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/StatsOp.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/TrackEndEvent.cs b/DisCatSharp.Lavalink/Entities/Websocket/TrackEndEvent.cs index d201b23d8a..c5439fc4f3 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/TrackEndEvent.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/TrackEndEvent.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/TrackException.cs b/DisCatSharp.Lavalink/Entities/Websocket/TrackException.cs index 4c49db769f..765f7b775a 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/TrackException.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/TrackException.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Enums; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/TrackExceptionEvent.cs b/DisCatSharp.Lavalink/Entities/Websocket/TrackExceptionEvent.cs index 87e9ac6bc2..28b76beb2e 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/TrackExceptionEvent.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/TrackExceptionEvent.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/TrackStartEvent.cs b/DisCatSharp.Lavalink/Entities/Websocket/TrackStartEvent.cs index 1a3cd32584..c8f7bda966 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/TrackStartEvent.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/TrackStartEvent.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/TrackStuckEvent.cs b/DisCatSharp.Lavalink/Entities/Websocket/TrackStuckEvent.cs index 7433ae9340..e8581dffb5 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/TrackStuckEvent.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/TrackStuckEvent.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Entities/Websocket/WebSocketClosedEvent.cs b/DisCatSharp.Lavalink/Entities/Websocket/WebSocketClosedEvent.cs index f65220097b..683a763ff0 100644 --- a/DisCatSharp.Lavalink/Entities/Websocket/WebSocketClosedEvent.cs +++ b/DisCatSharp.Lavalink/Entities/Websocket/WebSocketClosedEvent.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Entities.Websocket; diff --git a/DisCatSharp.Lavalink/Enums/Filters/LavalinkFilterBand.cs b/DisCatSharp.Lavalink/Enums/Filters/LavalinkFilterBand.cs index fdd4bf5431..9d1e974bb5 100644 --- a/DisCatSharp.Lavalink/Enums/Filters/LavalinkFilterBand.cs +++ b/DisCatSharp.Lavalink/Enums/Filters/LavalinkFilterBand.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Lavalink.Enums.Filters; /// diff --git a/DisCatSharp.Lavalink/Enums/LavalinkEvents.cs b/DisCatSharp.Lavalink/Enums/LavalinkEvents.cs index e0d1cfd829..f811fa7732 100644 --- a/DisCatSharp.Lavalink/Enums/LavalinkEvents.cs +++ b/DisCatSharp.Lavalink/Enums/LavalinkEvents.cs @@ -1,4 +1,3 @@ - using Microsoft.Extensions.Logging; namespace DisCatSharp.Lavalink.Enums; diff --git a/DisCatSharp.Lavalink/Enums/LavalinkLoadResultType.cs b/DisCatSharp.Lavalink/Enums/LavalinkLoadResultType.cs index 9a6ca02456..9498823d33 100644 --- a/DisCatSharp.Lavalink/Enums/LavalinkLoadResultType.cs +++ b/DisCatSharp.Lavalink/Enums/LavalinkLoadResultType.cs @@ -1,4 +1,3 @@ - using System.Runtime.Serialization; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Enums/LavalinkRestEndpoints.cs b/DisCatSharp.Lavalink/Enums/LavalinkRestEndpoints.cs index bb1c89cbef..db7a7a9e84 100644 --- a/DisCatSharp.Lavalink/Enums/LavalinkRestEndpoints.cs +++ b/DisCatSharp.Lavalink/Enums/LavalinkRestEndpoints.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Lavalink.Enums; /// @@ -10,18 +9,22 @@ internal static class Endpoints /// The version endpoint. /// internal const string VERSION = "/version"; + /// /// The websocket endpoint. /// internal const string WEBSOCKET = "/websocket"; + /// /// The v4 endpoint. /// internal const string V4 = "/v4"; + /// /// The info endpoint. /// internal const string INFO = "/info"; + /// /// The stats endpoint. /// @@ -32,6 +35,7 @@ internal static class Endpoints /// THe sessions endpoint. /// internal const string SESSIONS = "/sessions"; + /// /// The players endpoint. /// @@ -42,10 +46,12 @@ internal static class Endpoints /// The load tracks endpoint. /// internal const string LOAD_TRACKS = "/loadtracks"; + /// /// The decode track endpoint. /// internal const string DECODE_TRACK = "/decodetrack"; + /// /// The decode tracks endpoint. /// @@ -56,14 +62,17 @@ internal static class Endpoints /// The route planner endpoint. /// internal const string ROUTE_PLANNER = "/routeplanner"; + /// /// The status endpoint. /// internal const string STATUS = "/status"; + /// /// The free address endpoint. /// internal const string FREE_ADDRESS = "/free/address"; + /// /// The free all endpoint. /// diff --git a/DisCatSharp.Lavalink/Enums/LavalinkSearchType.cs b/DisCatSharp.Lavalink/Enums/LavalinkSearchType.cs index 876d5bc09c..c18648c3d6 100644 --- a/DisCatSharp.Lavalink/Enums/LavalinkSearchType.cs +++ b/DisCatSharp.Lavalink/Enums/LavalinkSearchType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Lavalink.Enums; /// diff --git a/DisCatSharp.Lavalink/Enums/LavalinkTrackEndReason.cs b/DisCatSharp.Lavalink/Enums/LavalinkTrackEndReason.cs index 7430f97445..bcbd289bda 100644 --- a/DisCatSharp.Lavalink/Enums/LavalinkTrackEndReason.cs +++ b/DisCatSharp.Lavalink/Enums/LavalinkTrackEndReason.cs @@ -1,4 +1,3 @@ - using System.Runtime.Serialization; using DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/Enums/Severity.cs b/DisCatSharp.Lavalink/Enums/Severity.cs index 1579ee1030..743b18b167 100644 --- a/DisCatSharp.Lavalink/Enums/Severity.cs +++ b/DisCatSharp.Lavalink/Enums/Severity.cs @@ -1,4 +1,3 @@ - using System.Runtime.Serialization; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Enums/Websocket/EventOpType.cs b/DisCatSharp.Lavalink/Enums/Websocket/EventOpType.cs index 35f324fffe..e1628b708b 100644 --- a/DisCatSharp.Lavalink/Enums/Websocket/EventOpType.cs +++ b/DisCatSharp.Lavalink/Enums/Websocket/EventOpType.cs @@ -1,4 +1,3 @@ - using System.Runtime.Serialization; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Enums/Websocket/OpType.cs b/DisCatSharp.Lavalink/Enums/Websocket/OpType.cs index 9c4911b4b4..d5589b768b 100644 --- a/DisCatSharp.Lavalink/Enums/Websocket/OpType.cs +++ b/DisCatSharp.Lavalink/Enums/Websocket/OpType.cs @@ -1,4 +1,3 @@ - using System.Runtime.Serialization; using DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/GuildPlayerDestroyedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/GuildPlayerDestroyedEventArgs.cs index 14d9f94665..bfc07222ee 100644 --- a/DisCatSharp.Lavalink/EventArgs/GuildPlayerDestroyedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/GuildPlayerDestroyedEventArgs.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using DisCatSharp.EventArgs; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkPlayerStateUpdateEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkPlayerStateUpdateEventArgs.cs index eb5a7f405f..8e08c45cf9 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkPlayerStateUpdateEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkPlayerStateUpdateEventArgs.cs @@ -1,4 +1,3 @@ - using DisCatSharp.EventArgs; using DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkSessionConnectedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkSessionConnectedEventArgs.cs index 22c1a5ad8f..78c5d9ac09 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkSessionConnectedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkSessionConnectedEventArgs.cs @@ -1,4 +1,3 @@ - using DisCatSharp.EventArgs; namespace DisCatSharp.Lavalink.EventArgs; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkSessionDisconnectedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkSessionDisconnectedEventArgs.cs index 6b88633a2a..ae3ffd4fec 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkSessionDisconnectedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkSessionDisconnectedEventArgs.cs @@ -1,4 +1,3 @@ - using DisCatSharp.EventArgs; namespace DisCatSharp.Lavalink.EventArgs; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkStatsReceivedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkStatsReceivedEventArgs.cs index 27c764c8fe..4b981c6701 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkStatsReceivedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkStatsReceivedEventArgs.cs @@ -1,4 +1,3 @@ - using DisCatSharp.EventArgs; using DisCatSharp.Lavalink.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackEndedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackEndedEventArgs.cs index eaee302e7f..cce4e1d8be 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackEndedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackEndedEventArgs.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackExceptionEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackExceptionEventArgs.cs index 2cde5a0fac..63ba1d67f4 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackExceptionEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackExceptionEventArgs.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Entities; @@ -51,9 +50,7 @@ internal LavalinkTrackExceptionEventArgs(DiscordClient client, TrackExceptionEve this.Track = eventArgs.Track; this.Exception = new() { - Message = eventArgs.Exception.Message, - Severity = eventArgs.Exception.Severity, - Cause = eventArgs.Exception.Cause + Message = eventArgs.Exception.Message, Severity = eventArgs.Exception.Severity, Cause = eventArgs.Exception.Cause }; this.GuildId = Convert.ToUInt64(eventArgs.GuildId); } diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStartedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStartedEventArgs.cs index b035aadc7c..a852c14750 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStartedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStartedEventArgs.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStuckEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStuckEventArgs.cs index 80a1b1e936..d3e6881a01 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStuckEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkTrackStuckEventArgs.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/EventArgs/LavalinkWebsocketClosedEventArgs.cs b/DisCatSharp.Lavalink/EventArgs/LavalinkWebsocketClosedEventArgs.cs index 75b2b6e732..3009434f99 100644 --- a/DisCatSharp.Lavalink/EventArgs/LavalinkWebsocketClosedEventArgs.cs +++ b/DisCatSharp.Lavalink/EventArgs/LavalinkWebsocketClosedEventArgs.cs @@ -1,4 +1,3 @@ - using System; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/Exceptions/LavalinkRestException.cs b/DisCatSharp.Lavalink/Exceptions/LavalinkRestException.cs index 7526250db1..01fbcd8ff6 100644 --- a/DisCatSharp.Lavalink/Exceptions/LavalinkRestException.cs +++ b/DisCatSharp.Lavalink/Exceptions/LavalinkRestException.cs @@ -1,4 +1,3 @@ - using System; using System.Net; using System.Net.Http.Headers; @@ -17,6 +16,7 @@ public sealed class LavalinkRestException : Exception /// [JsonIgnore] public DateTimeOffset Timestamp => Utilities.GetDateTimeOffsetFromMilliseconds(this._timestamp); + [JsonProperty("timestamp")] #pragma warning disable CS0649 // Field 'LavalinkRestException._timestamp' is never assigned to, and will always have its default value 0 private readonly long _timestamp; diff --git a/DisCatSharp.Lavalink/ExtensionMethods.cs b/DisCatSharp.Lavalink/ExtensionMethods.cs index 3a6eba1480..8c847327fe 100644 --- a/DisCatSharp.Lavalink/ExtensionMethods.cs +++ b/DisCatSharp.Lavalink/ExtensionMethods.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Collections.ObjectModel; diff --git a/DisCatSharp.Lavalink/GlobalSuppressions.cs b/DisCatSharp.Lavalink/GlobalSuppressions.cs index be9d48287a..db87553648 100644 --- a/DisCatSharp.Lavalink/GlobalSuppressions.cs +++ b/DisCatSharp.Lavalink/GlobalSuppressions.cs @@ -1,4 +1,3 @@ - using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Usage", "DCS0102:[Discord] Deprecated", Justification = "")] diff --git a/DisCatSharp.Lavalink/LavalinkConfiguration.cs b/DisCatSharp.Lavalink/LavalinkConfiguration.cs index b03d43b3cb..cc30fda50b 100644 --- a/DisCatSharp.Lavalink/LavalinkConfiguration.cs +++ b/DisCatSharp.Lavalink/LavalinkConfiguration.cs @@ -1,4 +1,3 @@ - using System; using System.Net; @@ -110,15 +109,11 @@ public LavalinkConfiguration(LavalinkConfiguration other) { this.RestEndpoint = new() { - Hostname = other.RestEndpoint.Hostname, - Port = other.RestEndpoint.Port, - Secured = other.RestEndpoint.Secured + Hostname = other.RestEndpoint.Hostname, Port = other.RestEndpoint.Port, Secured = other.RestEndpoint.Secured }; this.SocketEndpoint = new() { - Hostname = other.SocketEndpoint.Hostname, - Port = other.SocketEndpoint.Port, - Secured = other.SocketEndpoint.Secured + Hostname = other.SocketEndpoint.Hostname, Port = other.SocketEndpoint.Port, Secured = other.SocketEndpoint.Secured }; this.Password = other.Password; this.SessionId = other.SessionId; diff --git a/DisCatSharp.Lavalink/LavalinkExtension.cs b/DisCatSharp.Lavalink/LavalinkExtension.cs index 8b636a23e8..f88e4df23c 100644 --- a/DisCatSharp.Lavalink/LavalinkExtension.cs +++ b/DisCatSharp.Lavalink/LavalinkExtension.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -25,6 +24,7 @@ public event AsyncEventHandler this._sessionDisconnected.Register(value); remove => this._sessionDisconnected.Unregister(value); } + private AsyncEvent _sessionDisconnected; /// @@ -35,6 +35,7 @@ public event AsyncEventHandler this._sessionConnected.Register(value); remove => this._sessionConnected.Unregister(value); } + private AsyncEvent _sessionConnected; /// @@ -80,7 +81,6 @@ protected internal override void Setup(DiscordClient client) this._sessionConnected = new("LAVALINK_SESSION_CONNECTED", TimeSpan.Zero, this.Client.EventErrorHandler); } - /// /// Connect to a Lavalink session. /// @@ -100,6 +100,7 @@ public async Task ConnectAsync(LavalinkConfiguration config) var versionInfo = await this.REST.GetVersionAsync().ConfigureAwait(false); if (!versionInfo.Headers.Contains("Lavalink-Api-Version")) throw new("Lavalink v4 is required"); + if (versionInfo.Headers.TryGetValues("Lavalink-Api-Version", out var headerValues)) if (headerValues.First() != "4") throw new("Lavalink v4 is required"); @@ -183,27 +184,27 @@ private LavalinkSession FilterByLoad(LavalinkSession[] sessions) var bPenaltyCount = b.Statistics.PlayingPlayers; //cpu load - aPenaltyCount += (int)Math.Pow(1.05d, (100 * (a.Statistics.Cpu.SystemLoad / a.Statistics.Cpu.Cores) * 10) - 10); - bPenaltyCount += (int)Math.Pow(1.05d, (100 * (b.Statistics.Cpu.SystemLoad / a.Statistics.Cpu.Cores) * 10) - 10); + aPenaltyCount += (int)Math.Pow(1.05d, 100 * (a.Statistics.Cpu.SystemLoad / a.Statistics.Cpu.Cores) * 10 - 10); + bPenaltyCount += (int)Math.Pow(1.05d, 100 * (b.Statistics.Cpu.SystemLoad / a.Statistics.Cpu.Cores) * 10 - 10); //frame load if (a.Statistics.Frames!.Deficit > 0) { //deficit frame load - aPenaltyCount += (int)((Math.Pow(1.03d, 500f * (a.Statistics.Frames.Deficit / 3000f)) * 600) - 600); + aPenaltyCount += (int)(Math.Pow(1.03d, 500f * (a.Statistics.Frames.Deficit / 3000f)) * 600 - 600); //null frame load - aPenaltyCount += (int)((Math.Pow(1.03d, 500f * (a.Statistics.Frames.Deficit / 3000f)) * 300) - 300); + aPenaltyCount += (int)(Math.Pow(1.03d, 500f * (a.Statistics.Frames.Deficit / 3000f)) * 300 - 300); } //frame load if (b.Statistics.Frames!.Deficit > 0) { //deficit frame load - bPenaltyCount += (int)((Math.Pow(1.03d, 500f * (b.Statistics.Frames.Deficit / 3000f)) * 600) - 600); + bPenaltyCount += (int)(Math.Pow(1.03d, 500f * (b.Statistics.Frames.Deficit / 3000f)) * 600 - 600); //null frame load - bPenaltyCount += (int)((Math.Pow(1.03d, 500f * (b.Statistics.Frames.Deficit / 3000f)) * 300) - 300); + bPenaltyCount += (int)(Math.Pow(1.03d, 500f * (b.Statistics.Frames.Deficit / 3000f)) * 300 - 300); } return aPenaltyCount - bPenaltyCount; diff --git a/DisCatSharp.Lavalink/LavalinkGuildPlayer.cs b/DisCatSharp.Lavalink/LavalinkGuildPlayer.cs index 257d630a69..6d2196a544 100644 --- a/DisCatSharp.Lavalink/LavalinkGuildPlayer.cs +++ b/DisCatSharp.Lavalink/LavalinkGuildPlayer.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Linq; @@ -34,6 +33,7 @@ internal event AsyncEventHandler Voice add => this._voiceStateUpdated.Register(value); remove => this._voiceStateUpdated.Unregister(value); } + private readonly AsyncEvent _voiceStateUpdated; /// @@ -44,6 +44,7 @@ public event AsyncEventHandler this.TrackStartedEvent.Register(value); remove => this.TrackStartedEvent.Unregister(value); } + internal readonly AsyncEvent TrackStartedEvent; /// @@ -54,6 +55,7 @@ public event AsyncEventHandler add => this.TrackEndedEvent.Register(value); remove => this.TrackEndedEvent.Unregister(value); } + internal readonly AsyncEvent TrackEndedEvent; /// @@ -64,6 +66,7 @@ public event AsyncEventHandler this.TrackExceptionEvent.Register(value); remove => this.TrackExceptionEvent.Unregister(value); } + internal readonly AsyncEvent TrackExceptionEvent; /// @@ -74,6 +77,7 @@ public event AsyncEventHandler add => this.TrackStuckEvent.Register(value); remove => this.TrackStuckEvent.Unregister(value); } + internal readonly AsyncEvent TrackStuckEvent; /// @@ -84,6 +88,7 @@ public event AsyncEventHandler this.StateUpdatedEvent.Register(value); remove => this.StateUpdatedEvent.Unregister(value); } + internal readonly AsyncEvent StateUpdatedEvent; /// @@ -170,6 +175,7 @@ public IReadOnlyList QueueEntries /// public IReadOnlyList CurrentUsers => new List(this.CurrentUsersInternal.Values); + /// /// Gets the internal list of users. /// @@ -379,6 +385,7 @@ public async Task SetVolumeAsync(int volume) { if (volume is < 0 or > 1000) throw new ArgumentException("Volume can only be between 0 and 1000", nameof(volume)); + this.Player = await this.Session.Rest.UpdatePlayerAsync(this.Session.Config.SessionId!, this.GuildId, true, volume: volume).ConfigureAwait(false); return this; } @@ -425,6 +432,7 @@ public async Task PlayDirectUrlAsync(string url) { if (url.Contains("playlist")) throw new NotSupportedException("Lavalink is unable to play a playlist directly."); + var match = CommonRegEx.AdvancedYoutubeRegex.Match(url); if (match.Groups["list"] != null! && !string.IsNullOrEmpty(match.Groups["list"].Value)) { @@ -443,7 +451,7 @@ public async Task PlayDirectUrlAsync(string url) return this; } - #region Queue Operations +#region Queue Operations /// /// Adds a to the queue. @@ -477,6 +485,7 @@ public async void PlayQueueAsync() { if (!this.QUEUE_SYSTEM_ENABLED) return; + while (this._queueEntriesInternal.Count > 0) { this._queueTsc = new(); @@ -496,7 +505,7 @@ public async void PlayQueueAsync() } } - #endregion +#endregion /// /// Switches the player to a new channel. @@ -508,16 +517,14 @@ public async Task SwitchChannelAsync(DiscordChannel channel, bool deafened = tru { if (channel.Type != ChannelType.Stage && channel.Type != ChannelType.Voice) throw new ArgumentException("Cannot switch to a non-voice channel", nameof(channel)); + this.ChannelId = channel.Id; var vsd = new DiscordDispatchPayload { OpCode = 4, Payload = new VoiceStateUpdatePayload() { - GuildId = this.GuildId, - ChannelId = this.ChannelId, - Deafened = deafened, - Muted = false + GuildId = this.GuildId, ChannelId = this.ChannelId, Deafened = deafened, Muted = false } }; await this.Session.Discord.WsSendAsync(LavalinkJson.SerializeObject(vsd)).ConfigureAwait(false); @@ -537,7 +544,6 @@ internal void UpdatePlayerState(LavalinkPlayerState state) internal void UpdateVoiceState(LavalinkVoiceState voiceState) => this.Player.VoiceState = voiceState; - /// /// Disconnect the guild player from the channel. /// @@ -561,10 +567,7 @@ internal async Task DisconnectVoiceAsync() OpCode = 4, Payload = new VoiceStateUpdatePayload() { - GuildId = this.GuildId, - ChannelId = null, - Deafened = false, - Muted = false + GuildId = this.GuildId, ChannelId = null, Deafened = false, Muted = false } }; await this.Session.Discord.WsSendAsync(LavalinkJson.SerializeObject(vsd)).ConfigureAwait(false); diff --git a/DisCatSharp.Lavalink/LavalinkJson.cs b/DisCatSharp.Lavalink/LavalinkJson.cs index df2091bca9..e96527e31f 100644 --- a/DisCatSharp.Lavalink/LavalinkJson.cs +++ b/DisCatSharp.Lavalink/LavalinkJson.cs @@ -1,4 +1,3 @@ - using System.Diagnostics; using DisCatSharp.Entities; diff --git a/DisCatSharp.Lavalink/LavalinkRestClient.cs b/DisCatSharp.Lavalink/LavalinkRestClient.cs index 22027c72e4..c3b3a7a697 100644 --- a/DisCatSharp.Lavalink/LavalinkRestClient.cs +++ b/DisCatSharp.Lavalink/LavalinkRestClient.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Globalization; @@ -59,16 +58,12 @@ internal LavalinkRestClient(LavalinkConfiguration configuration, DiscordClient c var httpHandler = new HttpClientHandler { - UseCookies = false, - AutomaticDecompression = DecompressionMethods.All, - UseProxy = configuration.Proxy != null!, - Proxy = configuration.Proxy + UseCookies = false, AutomaticDecompression = DecompressionMethods.All, UseProxy = configuration.Proxy != null!, Proxy = configuration.Proxy }; this.HttpClient = new(httpHandler) { - BaseAddress = new($"{configuration.RestEndpoint.ToHttpString()}"), - Timeout = configuration.HttpTimeout + BaseAddress = new($"{configuration.RestEndpoint.ToHttpString()}"), Timeout = configuration.HttpTimeout }; this.TRACE_ENABLED = configuration.EnableTrace; @@ -105,6 +100,7 @@ private static string GetPath(string route, object routeParams) { if (routeParams == null!) return route; + var routeParamsProperties = routeParams.GetType() .GetTypeInfo() .DeclaredProperties; @@ -118,13 +114,19 @@ private static string GetPath(string route, object routeParams) ? dt.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) : val is DateTimeOffset dto ? dto.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) - : val is IFormattable xf ? xf.ToString(null, CultureInfo.InvariantCulture) : val.ToString(); + : val is IFormattable xf + ? xf.ToString(null, CultureInfo.InvariantCulture) + : val.ToString(); } + return s_routeArgumentRegex.Replace(route, xm => extractedRouteParams[xm.Groups[1].Value]); } private Dictionary GetDefaultParams() - => new() { ["trace"] = this.TRACE_ENABLED.ToString().ToLower() }; + => new() + { + ["trace"] = this.TRACE_ENABLED.ToString().ToLower() + }; /// /// Executes a rest request. @@ -144,6 +146,7 @@ private async Task DoRequestAsync(HttpMethod method, strin request.Content = new StringContent(payload); request.Content.Headers.ContentType = new("application/json"); } + request.Method = method; request.RequestUri = new(this.HttpClient.BaseAddress!, path); var response = await this.HttpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false); @@ -160,9 +163,7 @@ private async Task DoRequestAsync(HttpMethod method, strin var res = new LavalinkRestResponse() { - ResponseCode = response.StatusCode, - Response = response.StatusCode != HttpStatusCode.NoContent ? await response.Content.ReadAsStringAsync().ConfigureAwait(false) : null, - Headers = response.Headers + ResponseCode = response.StatusCode, Response = response.StatusCode != HttpStatusCode.NoContent ? await response.Content.ReadAsStringAsync().ConfigureAwait(false) : null, Headers = response.Headers }; return res; @@ -176,7 +177,8 @@ internal async Task GetVersionAsync() { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.VERSION}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); return await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); } @@ -188,7 +190,8 @@ internal async Task GetInfoAsync() { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.INFO}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -201,7 +204,8 @@ internal async Task GetStatsAsync() { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.STATS}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -216,7 +220,10 @@ internal async Task UpdateSessionAsync(string sess { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id"; - var path = GetPath(route, new { session_id = sessionId }); + var path = GetPath(route, new + { + session_id = sessionId + }); var res = await this.DoRequestAsync(HttpMethod.Patch, $"{path}{BuildQueryString(queryDict)}", payload: LavalinkJson.SerializeObject(config)).ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -230,7 +237,10 @@ internal async Task> GetPlayersAsync(string sessio { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}"; - var path = GetPath(route, new { session_id = sessionId }); + var path = GetPath(route, new + { + session_id = sessionId + }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); return LavalinkJson.DeserializeObject>(res.Response!)!; } @@ -247,7 +257,10 @@ internal async Task CreatePlayerAsync(string sessionId, ulong guildId, int defau queryDict.Add("noReplace", "false"); var pld = new LavalinkRestPlayerCreatePayload(guildId.ToString(), defaultVolume); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}/:guild_id"; - var path = GetPath(route, new { session_id = sessionId, guild_id = guildId }); + var path = GetPath(route, new + { + session_id = sessionId, guild_id = guildId + }); await this.DoRequestAsync(HttpMethod.Patch, $"{path}{BuildQueryString(queryDict)}", payload: LavalinkJson.SerializeObject(pld)).ConfigureAwait(false); } @@ -261,7 +274,10 @@ internal async Task GetPlayerAsync(string sessionId, ulong guild { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}/:guild_id"; - var path = GetPath(route, new { session_id = sessionId, guild_id = guildId }); + var path = GetPath(route, new + { + session_id = sessionId, guild_id = guildId + }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -280,10 +296,18 @@ internal async Task GetPlayerAsync(string sessionId, ulong guild /// Whether to pause the track. /// The filters. /// The updated object. - internal async Task UpdatePlayerAsync(string sessionId, ulong guildId, bool noReplace = false, - Optional encodedTrack = default, Optional identifier = default, - Optional position = default, Optional endTime = default, - Optional volume = default, Optional paused = default, Optional filters = default) + internal async Task UpdatePlayerAsync( + string sessionId, + ulong guildId, + bool noReplace = false, + Optional encodedTrack = default, + Optional identifier = default, + Optional position = default, + Optional endTime = default, + Optional volume = default, + Optional paused = default, + Optional filters = default + ) { var queryDict = this.GetDefaultParams(); queryDict.Add("noReplace", noReplace.ToString().ToLower()); @@ -298,7 +322,10 @@ internal async Task UpdatePlayerAsync(string sessionId, ulong gu Filters = filters }; var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}/:guild_id"; - var path = GetPath(route, new { session_id = sessionId, guild_id = guildId }); + var path = GetPath(route, new + { + session_id = sessionId, guild_id = guildId + }); var res = await this.DoRequestAsync(HttpMethod.Patch, $"{path}{BuildQueryString(queryDict)}", payload: LavalinkJson.SerializeObject(pld)).ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -317,7 +344,10 @@ internal async Task UpdatePlayerVoiceStateAsync(string sessionId, ulong guildId, var pld = new LavalinkRestVoiceStateUpdatePayload(state, guildId.ToString()); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}/:guild_id"; - var path = GetPath(route, new { session_id = sessionId, guild_id = guildId }); + var path = GetPath(route, new + { + session_id = sessionId, guild_id = guildId + }); await this.DoRequestAsync(HttpMethod.Patch, $"{path}{BuildQueryString(queryDict)}", payload: LavalinkJson.SerializeObject(pld)).ConfigureAwait(false); } @@ -331,7 +361,10 @@ internal async Task DestroyPlayerAsync(string sessionId, ulong guildId) { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.SESSIONS}/:session_id{Endpoints.PLAYERS}/:guild_id"; - var path = GetPath(route, new { session_id = sessionId, guild_id = guildId }); + var path = GetPath(route, new + { + session_id = sessionId, guild_id = guildId + }); await this.DoRequestAsync(HttpMethod.Delete, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); } @@ -345,13 +378,13 @@ internal async Task LoadTracksAsync(string identifie var queryDict = this.GetDefaultParams(); queryDict.Add("identifier", identifier); var route = $"{Endpoints.V4}{Endpoints.LOAD_TRACKS}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); var obj = JObject.Parse(res.Response!); - return new LavalinkTrackLoadingResult() + return new() { - LoadType = obj.GetValue("loadType")!.ToObject(), - RawResult = LavalinkJson.SerializeObject(obj.GetValue("data")) + LoadType = obj.GetValue("loadType")!.ToObject(), RawResult = LavalinkJson.SerializeObject(obj.GetValue("data")) }; } @@ -365,7 +398,8 @@ internal async Task DecodeTrackAsync(string base64Track) var queryDict = this.GetDefaultParams(); queryDict.Add("encodedTrack", base64Track); var route = $"{Endpoints.V4}{Endpoints.DECODE_TRACK}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); var res = await this.DoRequestAsync(HttpMethod.Get, $"{path}{BuildQueryString(queryDict)}").ConfigureAwait(false); return LavalinkJson.DeserializeObject(res.Response!)!; } @@ -379,7 +413,8 @@ internal async Task> DecodeTracksAsync(IEnumerable< { var queryDict = this.GetDefaultParams(); var route = $"{Endpoints.V4}{Endpoints.DECODE_TRACKS}"; - var path = GetPath(route, new { }); + var path = GetPath(route, new + { }); var res = await this.DoRequestAsync(HttpMethod.Post, $"{path}{BuildQueryString(queryDict)}", payload: LavalinkJson.SerializeObject(base64Tracks)).ConfigureAwait(false); return LavalinkJson.DeserializeObject>(res.Response!)!; } diff --git a/DisCatSharp.Lavalink/LavalinkSession.cs b/DisCatSharp.Lavalink/LavalinkSession.cs index b740bf05ce..5c81f87745 100644 --- a/DisCatSharp.Lavalink/LavalinkSession.cs +++ b/DisCatSharp.Lavalink/LavalinkSession.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -43,6 +42,7 @@ public event AsyncEventHandler LavalinkSo add => this._lavalinkSocketError.Register(value); remove => this._lavalinkSocketError.Unregister(value); } + private readonly AsyncEvent _lavalinkSocketError; /// @@ -53,6 +53,7 @@ internal event AsyncEventHandler this._lavalinkSessionDisconnected.Register(value); remove => this._lavalinkSessionDisconnected.Unregister(value); } + private readonly AsyncEvent _lavalinkSessionDisconnected; /// @@ -63,6 +64,7 @@ internal event AsyncEventHandler this._lavalinkSessionConnected.Register(value); remove => this._lavalinkSessionConnected.Unregister(value); } + private readonly AsyncEvent _lavalinkSessionConnected; /// @@ -73,6 +75,7 @@ public event AsyncEventHandler add => this._statsReceived.Register(value); remove => this._statsReceived.Unregister(value); } + private readonly AsyncEvent _statsReceived; /// @@ -83,6 +86,7 @@ public event AsyncEventHandler G add => this.GuildPlayerDestroyedEvent.Register(value); remove => this.GuildPlayerDestroyedEvent.Unregister(value); } + internal readonly AsyncEvent GuildPlayerDestroyedEvent; /// @@ -93,6 +97,7 @@ public event AsyncEventHandler this._websocketClosed.Register(value); remove => this._websocketClosed.Unregister(value); } + private readonly AsyncEvent _websocketClosed; /// @@ -120,6 +125,7 @@ public ConnectionEndpoint NodeEndpoint /// Gets the minimum backoff. /// private const int MINIMUM_BACKOFF = 7500; + /// /// Gets the maximum backoff. /// @@ -168,8 +174,7 @@ public IReadOnlyDictionary ConnectedPlayers /// public LavalinkSessionConfiguration Configuration { get; internal set; } = new() { - Resuming = true, - TimeoutSeconds = 60 + Resuming = true, TimeoutSeconds = 60 }; /// @@ -303,7 +308,7 @@ public async Task ConnectAsync(DiscordChannel channel, bool if (this.ConnectedPlayersInternal.TryGetValue(channel.Guild.Id, out var connectedGuild)) return connectedGuild; - if (channel.Guild == null! || (channel.Type != ChannelType.Voice && channel.Type != ChannelType.Stage)) + if (channel.Guild == null! || channel.Type != ChannelType.Voice && channel.Type != ChannelType.Stage) throw new ArgumentException("Invalid channel specified.", nameof(channel)); var vstut = new TaskCompletionSource(); @@ -316,10 +321,7 @@ public async Task ConnectAsync(DiscordChannel channel, bool OpCode = 4, Payload = new VoiceStateUpdatePayload() { - GuildId = channel.Guild.Id, - ChannelId = channel.Id, - Deafened = deafened, - Muted = false + GuildId = channel.Guild.Id, ChannelId = channel.Id, Deafened = deafened, Muted = false } }; await this.Rest.CreatePlayerAsync(this.Config.SessionId!, channel.Guild.Id, this.Config.DefaultVolume).ConfigureAwait(false); @@ -328,9 +330,7 @@ public async Task ConnectAsync(DiscordChannel channel, bool var vsr = await vsrut.Task.ConfigureAwait(false); // Wait for voice server update to get token, guild_id & endpoint await this.Rest.UpdatePlayerVoiceStateAsync(this.Config.SessionId!, channel.Guild.Id, new() { - Endpoint = vsr.Endpoint, - Token = vsr.VoiceToken, - SessionId = vst.SessionId + Endpoint = vsr.Endpoint, Token = vsr.VoiceToken, SessionId = vst.SessionId }).ConfigureAwait(false); var player = await this.Rest.GetPlayerAsync(this.Config.SessionId!, channel.Guild.Id).ConfigureAwait(false); @@ -506,8 +506,7 @@ internal async Task EstablishConnectionAsync() this.Discord.Logger.LogCritical(LavalinkEvents.LavalinkConnectionError, ex, "Failed to connect to Lavalink, retrying in {count} ms.", this._backoff); } - } - while (this.Config.SocketAutoReconnect); + } while (this.Config.SocketAutoReconnect); Volatile.Write(ref this._isDisposed, false); } @@ -640,7 +639,10 @@ await player.TrackExceptionEvent.InvokeAsync(player, /// The websocket client. /// The event args. private Task Lavalink_WebSocket_ExceptionThrown(IWebSocketClient client, SocketErrorEventArgs args) - => this._lavalinkSocketError.InvokeAsync(this, new(client.ServiceProvider) { Exception = args.Exception }); + => this._lavalinkSocketError.InvokeAsync(this, new(client.ServiceProvider) + { + Exception = args.Exception + }); /// /// Handles the event when the websocket disconnected. @@ -673,12 +675,14 @@ private async Task Lavalink_WebSocket_Disconnected(IWebSocketClient client, Sock _ = Task.Run(async () => await this.GuildPlayerDestroyedEvent.InvokeAsync(this, new(kvp.Value)).ConfigureAwait(false)); _ = this.ConnectedPlayersInternal.TryRemove(kvp.Key, out _); } + this.SessionDisconnected?.Invoke(this); await this._lavalinkSessionDisconnected.InvokeAsync(this, new(this, false)).ConfigureAwait(false); if (this.Config.SocketAutoReconnect) await this.EstablishConnectionAsync().ConfigureAwait(false); } + args.Handled = true; } @@ -728,9 +732,7 @@ private Task Discord_VoiceStateUpdated(DiscordClient client, VoiceStateUpdateEve { var state = new LavalinkVoiceState() { - Endpoint = guildPlayer.Player.VoiceState.Endpoint, - Token = guildPlayer.Player.VoiceState.Token, - SessionId = args.After.SessionId + Endpoint = guildPlayer.Player.VoiceState.Endpoint, Token = guildPlayer.Player.VoiceState.Token, SessionId = args.After.SessionId }; guildPlayer.UpdateVoiceState(state); await this.Rest.UpdatePlayerVoiceStateAsync(this.Config.SessionId!, guildPlayer.GuildId, state).ConfigureAwait(false); @@ -759,9 +761,7 @@ private Task Discord_VoiceServerUpdated(DiscordClient client, VoiceServerUpdateE { var state = new LavalinkVoiceState() { - Endpoint = args.Endpoint, - Token = args.VoiceToken, - SessionId = guildPlayer.Player.VoiceState.SessionId + Endpoint = args.Endpoint, Token = args.VoiceToken, SessionId = guildPlayer.Player.VoiceState.SessionId }; await this.Rest.UpdatePlayerVoiceStateAsync(this.Config.SessionId!, guildPlayer.GuildId, state).ConfigureAwait(false); guildPlayer.UpdateVoiceState(state); diff --git a/DisCatSharp.Lavalink/Models/LavalinkPlayerUpdateModel.cs b/DisCatSharp.Lavalink/Models/LavalinkPlayerUpdateModel.cs index 35e2360a64..3acaec6106 100644 --- a/DisCatSharp.Lavalink/Models/LavalinkPlayerUpdateModel.cs +++ b/DisCatSharp.Lavalink/Models/LavalinkPlayerUpdateModel.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using DisCatSharp.Lavalink.Entities; using DisCatSharp.Lavalink.Entities.Filters; diff --git a/DisCatSharp.Lavalink/Payloads/DiscordDispatchPayload.cs b/DisCatSharp.Lavalink/Payloads/DiscordDispatchPayload.cs index 89e78e3eb6..c769a00391 100644 --- a/DisCatSharp.Lavalink/Payloads/DiscordDispatchPayload.cs +++ b/DisCatSharp.Lavalink/Payloads/DiscordDispatchPayload.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Payloads; diff --git a/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerCreatePayload.cs b/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerCreatePayload.cs index 506bc60785..09a179f548 100644 --- a/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerCreatePayload.cs +++ b/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerCreatePayload.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Payloads; diff --git a/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerUpdatePayload.cs b/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerUpdatePayload.cs index f43630d01f..69243dd93a 100644 --- a/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerUpdatePayload.cs +++ b/DisCatSharp.Lavalink/Payloads/LavalinkRestPlayerUpdatePayload.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Entities; using DisCatSharp.Lavalink.Entities.Filters; diff --git a/DisCatSharp.Lavalink/Payloads/LavalinkRestVoiceStateUpdatePayload.cs b/DisCatSharp.Lavalink/Payloads/LavalinkRestVoiceStateUpdatePayload.cs index 75c0386020..d511748318 100644 --- a/DisCatSharp.Lavalink/Payloads/LavalinkRestVoiceStateUpdatePayload.cs +++ b/DisCatSharp.Lavalink/Payloads/LavalinkRestVoiceStateUpdatePayload.cs @@ -1,4 +1,3 @@ - using DisCatSharp.Lavalink.Entities; using Newtonsoft.Json; diff --git a/DisCatSharp.Lavalink/Payloads/VoiceStateUpdatePayload.cs b/DisCatSharp.Lavalink/Payloads/VoiceStateUpdatePayload.cs index 76ba9a16de..1d4b899ce0 100644 --- a/DisCatSharp.Lavalink/Payloads/VoiceStateUpdatePayload.cs +++ b/DisCatSharp.Lavalink/Payloads/VoiceStateUpdatePayload.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Lavalink.Payloads; diff --git a/DisCatSharp.Targets/DisCatSharp.targets b/DisCatSharp.Targets/DisCatSharp.targets index ed1db36622..17d3ae9b82 100644 --- a/DisCatSharp.Targets/DisCatSharp.targets +++ b/DisCatSharp.Targets/DisCatSharp.targets @@ -1,33 +1,34 @@ + - - AITSYS, DisCatSharp, DisCatSharp Contributors - AITSYS - False - https://docs.dcs.aitsys.dev - https://github.com/Aiko-IT-Systems/DisCatSharp - Git - logobig.png - - LICENSE.md - True - False - + + AITSYS, DisCatSharp, DisCatSharp Contributors + AITSYS + False + https://docs.dcs.aitsys.dev + https://github.com/Aiko-IT-Systems/DisCatSharp + Git + logobig.png + + LICENSE.md + True + False + - - - True - - - - True - - - - - - True - - - + + + True + + + + True + + + + + + True + + + diff --git a/DisCatSharp.Targets/InternalsVisibleTo.targets b/DisCatSharp.Targets/InternalsVisibleTo.targets index 98a726adc3..b1748c115d 100644 --- a/DisCatSharp.Targets/InternalsVisibleTo.targets +++ b/DisCatSharp.Targets/InternalsVisibleTo.targets @@ -1,37 +1,39 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DisCatSharp.Targets/Library.targets b/DisCatSharp.Targets/Library.targets index b2914f8fdf..195be394e1 100644 --- a/DisCatSharp.Targets/Library.targets +++ b/DisCatSharp.Targets/Library.targets @@ -1,8 +1,9 @@ + - - Library - net6.0;net7.0 - enable - + + Library + net6.0;net7.0 + enable + diff --git a/DisCatSharp.Targets/NuGet.targets b/DisCatSharp.Targets/NuGet.targets index 737d91d103..4134e7347c 100644 --- a/DisCatSharp.Targets/NuGet.targets +++ b/DisCatSharp.Targets/NuGet.targets @@ -1,4 +1,5 @@ + true @@ -11,26 +12,27 @@ true - $(DefineConstants);CI_BUILD - true + $(DefineConstants);CI_BUILD + true true - $(DefineConstants);CI_BUILD - true + $(DefineConstants);CI_BUILD + true true - $(DefineConstants);CI_BUILD - true + $(DefineConstants);CI_BUILD + true false - + - + aitsys discatsharp true diff --git a/DisCatSharp.Targets/Package.targets b/DisCatSharp.Targets/Package.targets index daffb9ed87..e7ce5a0fd8 100644 --- a/DisCatSharp.Targets/Package.targets +++ b/DisCatSharp.Targets/Package.targets @@ -1,12 +1,13 @@ + - - 1591;NU5128;DV2001 - latest - True - True - - - False - + + 1591;NU5128;DV2001 + latest + True + True + + + False + diff --git a/DisCatSharp.Targets/Version.targets b/DisCatSharp.Targets/Version.targets index dbf6a376f4..de60198d8a 100644 --- a/DisCatSharp.Targets/Version.targets +++ b/DisCatSharp.Targets/Version.targets @@ -1,21 +1,22 @@ + - - 10.4.2 - - - $(VersionPrefix)-$(VersionSuffix)-$(BuildNumber) - $(VersionPrefix).$(BuildNumber) - $(VersionPrefix).$(BuildNumber) - - - $(VersionPrefix)-$(VersionSuffix) - $(VersionPrefix).0 - $(VersionPrefix).0 - - - $(VersionPrefix) - $(VersionPrefix).0 - $(VersionPrefix).0 - + + 10.4.2 + + + $(VersionPrefix)-$(VersionSuffix)-$(BuildNumber) + $(VersionPrefix).$(BuildNumber) + $(VersionPrefix).$(BuildNumber) + + + $(VersionPrefix)-$(VersionSuffix) + $(VersionPrefix).0 + $(VersionPrefix).0 + + + $(VersionPrefix) + $(VersionPrefix).0 + $(VersionPrefix).0 + diff --git a/DisCatSharp.Tests/SafetyTests/HttpTest.cs b/DisCatSharp.Tests/SafetyTests/HttpTest.cs index 2eaf037319..e7c2ee3ce8 100644 --- a/DisCatSharp.Tests/SafetyTests/HttpTest.cs +++ b/DisCatSharp.Tests/SafetyTests/HttpTest.cs @@ -1,4 +1,3 @@ - using System; using FluentAssertions; @@ -12,7 +11,10 @@ public class HttpTests [Fact(DisplayName = "Ensure that no authorization header is set by DiscordClient")] public void BuiltInRestClientEnsureNoAuthorization() { - DiscordClient client = new(new() { Token = "super_secret_bot_token" }); + DiscordClient client = new(new() + { + Token = "super_secret_bot_token" + }); var action = () => client.RestClient.DefaultRequestHeaders.GetValues("Authorization").ToString(); action.Should() .Throw() diff --git a/DisCatSharp.VoiceNext.Natives/DisCatSharp.VoiceNext.Natives.csproj b/DisCatSharp.VoiceNext.Natives/DisCatSharp.VoiceNext.Natives.csproj index 77a7d92b87..0cdab6d400 100644 --- a/DisCatSharp.VoiceNext.Natives/DisCatSharp.VoiceNext.Natives.csproj +++ b/DisCatSharp.VoiceNext.Natives/DisCatSharp.VoiceNext.Natives.csproj @@ -1,47 +1,48 @@ + - - - - - - - - false - win-x86;win-x64 - true - false - symbols.nupkg - - - - DisCatSharp.VoiceNext.Natives - -Natives for DisCatSharp Voice Next Extension - -Manual Download: https://docs.dcs.aitsys.dev/natives/index.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Audio Player - annotations - - - - - true - runtimes - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + + + + + + + false + win-x86;win-x64 + true + false + symbols.nupkg + + + + DisCatSharp.VoiceNext.Natives + + Natives for DisCatSharp Voice Next Extension + + Manual Download: https://docs.dcs.aitsys.dev/natives/index.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Audio Player + annotations + + + + + true + runtimes + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/DisCatSharp.VoiceNext/AudioFormat.cs b/DisCatSharp.VoiceNext/AudioFormat.cs index 2377504e3d..d0384d4d84 100644 --- a/DisCatSharp.VoiceNext/AudioFormat.cs +++ b/DisCatSharp.VoiceNext/AudioFormat.cs @@ -14,17 +14,26 @@ 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 }); + 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 }); + 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 }); + 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. @@ -137,5 +146,5 @@ internal int SampleCountToSampleSize(int sampleCount) /// 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); + (this.VoiceApplication == VoiceApplication.Music || this.VoiceApplication == VoiceApplication.Voice || this.VoiceApplication == VoiceApplication.LowLatency); } diff --git a/DisCatSharp.VoiceNext/Codec/Interop.cs b/DisCatSharp.VoiceNext/Codec/Interop.cs index a577ed9e40..350fa57272 100644 --- a/DisCatSharp.VoiceNext/Codec/Interop.cs +++ b/DisCatSharp.VoiceNext/Codec/Interop.cs @@ -8,7 +8,8 @@ namespace DisCatSharp.VoiceNext.Codec; /// internal static class Interop { - #region Sodium wrapper +#region Sodium wrapper + /// /// The sodium library name. /// @@ -63,7 +64,7 @@ internal static class Interop /// The key. /// An int. [DllImport(SODIUM_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "crypto_secretbox_easy")] - private static unsafe extern int _SodiumSecretBoxCreate(byte* buffer, byte* message, ulong messageLength, byte* nonce, byte* key); + private static extern unsafe int _SodiumSecretBoxCreate(byte* buffer, byte* message, ulong messageLength, byte* nonce, byte* key); /// /// _S the sodium secret box open. @@ -75,7 +76,7 @@ internal static class Interop /// The key. /// An int. [DllImport(SODIUM_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "crypto_secretbox_open_easy")] - private static unsafe extern int _SodiumSecretBoxOpen(byte* buffer, byte* encryptedMessage, ulong encryptedLength, byte* nonce, byte* key); + private static extern unsafe int _SodiumSecretBoxOpen(byte* buffer, byte* encryptedMessage, ulong encryptedLength, byte* nonce, byte* key); /// /// Encrypts supplied buffer using xsalsa20_poly1305 algorithm, using supplied key and nonce to perform encryption. @@ -116,9 +117,11 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R return status; } - #endregion - #region Opus wrapper +#endregion + +#region Opus wrapper + /// /// The opus library name. /// @@ -152,7 +155,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R /// The max data bytes. /// An int. [DllImport(OPUS_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "opus_encode")] - private static unsafe extern int _OpusEncode(IntPtr encoder, byte* pcmData, int frameSize, byte* data, int maxDataBytes); + private static extern unsafe int _OpusEncode(IntPtr encoder, byte* pcmData, int frameSize, byte* data, int maxDataBytes); /// /// _S the opus encoder control. @@ -192,7 +195,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R /// The decode fec. /// An int. [DllImport(OPUS_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "opus_decode")] - private static unsafe extern int _OpusDecode(IntPtr decoder, byte* opusData, int opusDataLength, byte* data, int frameSize, int decodeFec); + private static extern unsafe int _OpusDecode(IntPtr decoder, byte* opusData, int opusDataLength, byte* data, int frameSize, int decodeFec); /// /// _S the opus get packet channel count. @@ -200,7 +203,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R /// The opus data. /// An int. [DllImport(OPUS_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "opus_packet_get_nb_channels")] - private static unsafe extern int _OpusGetPacketChannelCount(byte* opusData); + private static extern unsafe int _OpusGetPacketChannelCount(byte* opusData); /// /// _S the opus get packet frame count. @@ -209,7 +212,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R /// The length. /// An int. [DllImport(OPUS_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "opus_packet_get_nb_frames")] - private static unsafe extern int _OpusGetPacketFrameCount(byte* opusData, int length); + private static extern unsafe int _OpusGetPacketFrameCount(byte* opusData, int length); /// /// _S the opus get packet sample per frame count. @@ -218,7 +221,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R /// The sampling rate. /// An int. [DllImport(OPUS_LIBRARY_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "opus_packet_get_samples_per_frame")] - private static unsafe extern int _OpusGetPacketSamplePerFrameCount(byte* opusData, int samplingRate); + private static extern unsafe int _OpusGetPacketSamplePerFrameCount(byte* opusData, int samplingRate); /// /// _S the opus decoder control. @@ -238,7 +241,7 @@ public static unsafe int Decrypt(ReadOnlySpan source, Span target, R public static IntPtr OpusCreateEncoder(AudioFormat audioFormat) { var encoder = _OpusCreateEncoder(audioFormat.SampleRate, audioFormat.ChannelCount, (int)audioFormat.VoiceApplication, out var error); - return error != OpusError.Ok ? throw new Exception($"Could not instantiate Opus encoder: {error} ({(int)error}).") : encoder; + return error != OpusError.Ok ? throw new($"Could not instantiate Opus encoder: {error} ({(int)error}).") : encoder; } /// @@ -251,7 +254,7 @@ public static void OpusSetEncoderOption(IntPtr encoder, OpusControl option, int { var error = OpusError.Ok; if ((error = _OpusEncoderControl(encoder, option, value)) != OpusError.Ok) - throw new Exception($"Could not set Opus encoder option: {error} ({(int)error})."); + throw new($"Could not set Opus encoder option: {error} ({(int)error})."); } /// @@ -272,7 +275,7 @@ public static unsafe void OpusEncode(IntPtr encoder, ReadOnlySpan pcm, int if (len < 0) { var error = (OpusError)len; - throw new Exception($"Could not encode PCM data to Opus: {error} ({(int)error})."); + throw new($"Could not encode PCM data to Opus: {error} ({(int)error})."); } opus = opus[..len]; @@ -286,7 +289,7 @@ public static unsafe void OpusEncode(IntPtr encoder, ReadOnlySpan pcm, int public static IntPtr OpusCreateDecoder(AudioFormat audioFormat) { var decoder = _OpusCreateDecoder(audioFormat.SampleRate, audioFormat.ChannelCount, out var error); - return error != OpusError.Ok ? throw new Exception($"Could not instantiate Opus decoder: {error} ({(int)error}).") : decoder; + return error != OpusError.Ok ? throw new($"Could not instantiate Opus decoder: {error} ({(int)error}).") : decoder; } /// @@ -309,7 +312,7 @@ public static unsafe int OpusDecode(IntPtr decoder, ReadOnlySpan opus, int if (len < 0) { var error = (OpusError)len; - throw new Exception($"Could not decode PCM data from Opus: {error} ({(int)error})."); + throw new($"Could not decode PCM data from Opus: {error} ({(int)error})."); } return len; @@ -332,7 +335,7 @@ public static unsafe int OpusDecode(IntPtr decoder, int frameSize, Span pc if (len < 0) { var error = (OpusError)len; - throw new Exception($"Could not decode PCM data from Opus: {error} ({(int)error})."); + throw new($"Could not decode PCM data from Opus: {error} ({(int)error})."); } return len; @@ -366,5 +369,6 @@ public static unsafe void OpusGetPacketMetrics(ReadOnlySpan opus, int samp /// The sample count. public static void OpusGetLastPacketDuration(IntPtr decoder, out int sampleCount) => _OpusDecoderControl(decoder, OpusControl.GetLastPacketDuration, out sampleCount); - #endregion + +#endregion } diff --git a/DisCatSharp.VoiceNext/Codec/Opus.cs b/DisCatSharp.VoiceNext/Codec/Opus.cs index 72b48d51b4..95f387d427 100644 --- a/DisCatSharp.VoiceNext/Codec/Opus.cs +++ b/DisCatSharp.VoiceNext/Codec/Opus.cs @@ -47,12 +47,13 @@ public Opus(AudioFormat audioFormat) sig = OpusSignal.Voice; break; } + Interop.OpusSetEncoderOption(this._encoder, OpusControl.SetSignal, (int)sig); Interop.OpusSetEncoderOption(this._encoder, OpusControl.SetPacketLossPercent, 15); Interop.OpusSetEncoderOption(this._encoder, OpusControl.SetInBandFec, 1); Interop.OpusSetEncoderOption(this._encoder, OpusControl.SetBitrate, 131072); - this._managedDecoders = new List(); + this._managedDecoders = new(); } /// @@ -89,7 +90,7 @@ public void Decode(OpusDecoder decoder, ReadOnlySpan opus, ref Span // throw new ArgumentException("PCM target buffer size needs to be equal to maximum buffer size for specified audio format.", nameof(target)); Interop.OpusGetPacketMetrics(opus, this.AudioFormat.SampleRate, out var channels, out var frames, out var samplesPerFrame, out var frameSize); - outputFormat = this.AudioFormat.ChannelCount != channels ? new AudioFormat(this.AudioFormat.SampleRate, channels, this.AudioFormat.VoiceApplication) : this.AudioFormat; + outputFormat = this.AudioFormat.ChannelCount != channels ? new(this.AudioFormat.SampleRate, channels, this.AudioFormat.VoiceApplication) : this.AudioFormat; if (decoder.AudioFormat.ChannelCount != channels) decoder.Initialize(outputFormat); @@ -157,10 +158,8 @@ public void Dispose() Interop.OpusDestroyEncoder(this._encoder); lock (this._managedDecoders) - { foreach (var decoder in this._managedDecoders) decoder.Dispose(); - } } } @@ -178,6 +177,7 @@ public class OpusDecoder : IDisposable /// Gets the opus. /// internal Opus Opus { get; } + /// /// Gets the decoder. /// @@ -262,5 +262,5 @@ internal enum OpusSignal : int { Auto = -1000, Voice = 3001, - Music = 3002, + Music = 3002 } diff --git a/DisCatSharp.VoiceNext/Codec/Rtp.cs b/DisCatSharp.VoiceNext/Codec/Rtp.cs index 0fda40f204..5f5d9667c9 100644 --- a/DisCatSharp.VoiceNext/Codec/Rtp.cs +++ b/DisCatSharp.VoiceNext/Codec/Rtp.cs @@ -17,10 +17,12 @@ internal sealed class Rtp : IDisposable /// The rtp no extension. /// private const byte RTP_NO_EXTENSION = 0x80; + /// /// The rtp extension. /// private const byte RTP_EXTENSION = 0x90; + /// /// The rtp version. /// @@ -48,9 +50,9 @@ public void EncodeHeader(ushort sequence, uint timestamp, uint ssrc, Span target[1] = RTP_VERSION; // Write data big endian - BinaryPrimitives.WriteUInt16BigEndian(target[2..], sequence); // header + magic + BinaryPrimitives.WriteUInt16BigEndian(target[2..], sequence); // header + magic BinaryPrimitives.WriteUInt32BigEndian(target[4..], timestamp); // header + magic + sizeof(sequence) - BinaryPrimitives.WriteUInt32BigEndian(target[8..], ssrc); // header + magic + sizeof(sequence) + sizeof(timestamp) + BinaryPrimitives.WriteUInt32BigEndian(target[8..], ssrc); // header + magic + sizeof(sequence) + sizeof(timestamp) } /// @@ -73,7 +75,7 @@ public void DecodeHeader(ReadOnlySpan source, out ushort sequence, out uin if (source.Length < HEADER_SIZE) throw new ArgumentException("Header buffer is too short.", nameof(source)); - if ((source[0] != RTP_NO_EXTENSION && source[0] != RTP_EXTENSION) || source[1] != RTP_VERSION) + if (source[0] != RTP_NO_EXTENSION && source[0] != RTP_EXTENSION || source[1] != RTP_VERSION) throw new ArgumentException("Invalid RTP header.", nameof(source)); hasExtension = source[0] == RTP_EXTENSION; @@ -96,7 +98,7 @@ public int CalculatePacketSize(int encryptedLength, EncryptionMode encryptionMod EncryptionMode.XSalsa20Poly1305 => HEADER_SIZE + encryptedLength, EncryptionMode.XSalsa20Poly1305Suffix => HEADER_SIZE + encryptedLength + Interop.SodiumNonceSize, EncryptionMode.XSalsa20Poly1305Lite => HEADER_SIZE + encryptedLength + 4, - _ => throw new ArgumentException("Unsupported encryption mode.", nameof(encryptionMode)), + _ => throw new ArgumentException("Unsupported encryption mode.", nameof(encryptionMode)) }; /// @@ -130,7 +132,5 @@ public void GetDataFromPacket(ReadOnlySpan packet, out ReadOnlySpan /// Disposes the Rtp. /// public void Dispose() - { - - } + { } } diff --git a/DisCatSharp.VoiceNext/Codec/Sodium.cs b/DisCatSharp.VoiceNext/Codec/Sodium.cs index f32be03536..540ab137f6 100644 --- a/DisCatSharp.VoiceNext/Codec/Sodium.cs +++ b/DisCatSharp.VoiceNext/Codec/Sodium.cs @@ -45,9 +45,7 @@ static Sodium() { SupportedModes = new ReadOnlyDictionary(new Dictionary() { - ["xsalsa20_poly1305_lite"] = EncryptionMode.XSalsa20Poly1305Lite, - ["xsalsa20_poly1305_suffix"] = EncryptionMode.XSalsa20Poly1305Suffix, - ["xsalsa20_poly1305"] = EncryptionMode.XSalsa20Poly1305 + ["xsalsa20_poly1305_lite"] = EncryptionMode.XSalsa20Poly1305Lite, ["xsalsa20_poly1305_suffix"] = EncryptionMode.XSalsa20Poly1305Suffix, ["xsalsa20_poly1305"] = EncryptionMode.XSalsa20Poly1305 }); } diff --git a/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj b/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj index 3b22724175..86bd3a29b9 100644 --- a/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj +++ b/DisCatSharp.VoiceNext/DisCatSharp.VoiceNext.csproj @@ -1,49 +1,50 @@ + - - - - - - - - - DisCatSharp.VoiceNext - DisCatSharp.VoiceNext - true - - - - DisCatSharp.VoiceNext - -DisCatSharp Voice Next Extension - -Easy made audio player for discord bots. - -Documentation: https://docs.dcs.aitsys.dev/articles/modules/audio/voicenext/prerequisites.html - - DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Audio Player - annotations - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - + + + + + + + + + DisCatSharp.VoiceNext + DisCatSharp.VoiceNext + true + + + + DisCatSharp.VoiceNext + + DisCatSharp Voice Next Extension + + Easy made audio player for discord bots. + + Documentation: https://docs.dcs.aitsys.dev/articles/modules/audio/voicenext/prerequisites.html + + DisCatSharp,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6,Net7,Voice,Audio Player + annotations + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/DisCatSharp.VoiceNext/DiscordClientExtensions.cs b/DisCatSharp.VoiceNext/DiscordClientExtensions.cs index 3d18e893a4..45eb723740 100644 --- a/DisCatSharp.VoiceNext/DiscordClientExtensions.cs +++ b/DisCatSharp.VoiceNext/DiscordClientExtensions.cs @@ -20,7 +20,7 @@ public static class DiscordClientExtensions /// Discord client to create VoiceNext instance for. /// VoiceNext client instance. public static VoiceNextExtension UseVoiceNext(this DiscordClient client) - => UseVoiceNext(client, new VoiceNextConfiguration()); + => UseVoiceNext(client, new()); /// /// Creates a new VoiceNext client with specified settings. @@ -79,9 +79,7 @@ public static async Task> GetVoiceN var extensions = new Dictionary(); foreach (var shard in client.ShardClients.Values) - { extensions.Add(shard.ShardId, shard.GetExtension()); - } return new ReadOnlyDictionary(extensions); } diff --git a/DisCatSharp.VoiceNext/Entities/AudioSender.cs b/DisCatSharp.VoiceNext/Entities/AudioSender.cs index 8b76ff5de9..a43cc95924 100644 --- a/DisCatSharp.VoiceNext/Entities/AudioSender.cs +++ b/DisCatSharp.VoiceNext/Entities/AudioSender.cs @@ -20,7 +20,7 @@ private enum SequenceWrapState { Normal, AssumeNextLowSequenceIsOverflow, - AssumeNextHighSequenceIsOutOfOrder, + AssumeNextHighSequenceIsOutOfOrder } /// @@ -64,7 +64,6 @@ public AudioSender(uint ssrc, OpusDecoder decoder) /// public void Dispose() => this.Decoder?.Dispose(); - /// /// Accepts the 16-bit sequence number from the next RTP header in the associated stream and /// uses heuristics to (attempt to) convert it into a 64-bit counter that takes into account diff --git a/DisCatSharp.VoiceNext/Entities/VoicePacket.cs b/DisCatSharp.VoiceNext/Entities/VoicePacket.cs index 4ab3d09e0e..fc96fd871c 100644 --- a/DisCatSharp.VoiceNext/Entities/VoicePacket.cs +++ b/DisCatSharp.VoiceNext/Entities/VoicePacket.cs @@ -8,10 +8,12 @@ internal struct VoicePacket /// Gets the bytes. /// public ReadOnlyMemory Bytes { get; } + /// /// Gets the millisecond duration. /// public int MillisecondDuration { get; } + /// /// Gets or sets a value indicating whether is silence. /// diff --git a/DisCatSharp.VoiceNext/EventArgs/VoiceReceiveEventArgs.cs b/DisCatSharp.VoiceNext/EventArgs/VoiceReceiveEventArgs.cs index ffdd4e2719..b4aac4e81b 100644 --- a/DisCatSharp.VoiceNext/EventArgs/VoiceReceiveEventArgs.cs +++ b/DisCatSharp.VoiceNext/EventArgs/VoiceReceiveEventArgs.cs @@ -15,7 +15,6 @@ public class VoiceReceiveEventArgs : DiscordEventArgs /// public uint Ssrc { get; internal set; } - /// /// Gets the user that sent the audio data. /// diff --git a/DisCatSharp.VoiceNext/GlobalSuppressions.cs b/DisCatSharp.VoiceNext/GlobalSuppressions.cs index 6ff741a513..6bfbf01085 100644 --- a/DisCatSharp.VoiceNext/GlobalSuppressions.cs +++ b/DisCatSharp.VoiceNext/GlobalSuppressions.cs @@ -1,8 +1,8 @@ - // This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. + using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Usage", "CA2254:Template should be a static expression", Justification = "", Scope = "member", Target = "~M:DisCatSharp.VoiceNext.VoiceNextConnection.Dispose")] diff --git a/DisCatSharp.VoiceNext/Interop/Bindings.cs b/DisCatSharp.VoiceNext/Interop/Bindings.cs index e81833c08d..fdd4f42d55 100644 --- a/DisCatSharp.VoiceNext/Interop/Bindings.cs +++ b/DisCatSharp.VoiceNext/Interop/Bindings.cs @@ -41,14 +41,14 @@ internal static unsafe class Bindings public static IntPtr CreateEncoder(int sampleRate, int channelCount, int application) { var encoder = opus_encoder_create(sampleRate, channelCount, application, out var error); - return error == OpusError.Ok ? encoder : throw new Exception($"Failed to instantiate Opus encoder: {error} ({(int)error})"); + return error == OpusError.Ok ? encoder : throw new($"Failed to instantiate Opus encoder: {error} ({(int)error})"); } public static void SetEncoderOption(IntPtr encoder, OpusControl option, int value) { var error = OpusError.Ok; if ((error = opus_encoder_ctl(encoder, option, value)) != OpusError.Ok) - throw new Exception($"Failed to set Opus encoder option: ${error} ({(int)error})"); + throw new($"Failed to set Opus encoder option: ${error} ({(int)error})"); } public static void Encode(IntPtr encoder, ReadOnlySpan pcm, int frameSize, ref Span data) @@ -62,7 +62,7 @@ public static void Encode(IntPtr encoder, ReadOnlySpan pcm, int frameSize, if (length < 0) { var error = (OpusError)length; - throw new Exception($"Failed to encode PCM data: {error} ({length})"); + throw new($"Failed to encode PCM data: {error} ({length})"); } data = data[..length]; @@ -71,7 +71,7 @@ public static void Encode(IntPtr encoder, ReadOnlySpan pcm, int frameSize, public static IntPtr CreateDecoder(int sampleRate, int channelCount) { var decoder = opus_decoder_create(sampleRate, channelCount, out var error); - return error == OpusError.Ok ? decoder : throw new Exception($"Failed to instantiate Opus decoder: {error} ({(int)error})"); + return error == OpusError.Ok ? decoder : throw new($"Failed to instantiate Opus decoder: {error} ({(int)error})"); } public static int Decode(IntPtr decoder, ReadOnlySpan data, int frameSize, Span pcm, bool useFec) @@ -85,7 +85,7 @@ public static int Decode(IntPtr decoder, ReadOnlySpan data, int frameSize, if (length < 0) { var error = (OpusError)length; - throw new Exception($"Failed to decode PCM data: {error} ({length})"); + throw new($"Failed to decode PCM data: {error} ({length})"); } return length; @@ -101,7 +101,7 @@ public static int Decode(IntPtr decoder, int frameSize, Span pcm) if (length < 0) { var error = (OpusError)length; - throw new Exception($"Failed to decode PCM data: {error} ({length})"); + throw new($"Failed to decode PCM data: {error} ({length})"); } return length; @@ -120,10 +120,7 @@ public static OpusPacketMetrics GetPacketMetrics(ReadOnlySpan data, int sa return new() { - ChannelCount = channels, - FrameCount = frames, - SamplesPerFrame = samplesPerFrame, - FrameSize = frames * samplesPerFrame + ChannelCount = channels, FrameCount = frames, SamplesPerFrame = samplesPerFrame, FrameSize = frames * samplesPerFrame }; } diff --git a/DisCatSharp.VoiceNext/Interop/OpusControl.cs b/DisCatSharp.VoiceNext/Interop/OpusControl.cs index 1c1dac31ce..c96c31cdfd 100644 --- a/DisCatSharp.VoiceNext/Interop/OpusControl.cs +++ b/DisCatSharp.VoiceNext/Interop/OpusControl.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.VoiceNext.Interop; internal enum OpusControl : int diff --git a/DisCatSharp.VoiceNext/Interop/OpusError.cs b/DisCatSharp.VoiceNext/Interop/OpusError.cs index 49ebbb6424..faac9c105f 100644 --- a/DisCatSharp.VoiceNext/Interop/OpusError.cs +++ b/DisCatSharp.VoiceNext/Interop/OpusError.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.VoiceNext.Interop; internal enum OpusError diff --git a/DisCatSharp.VoiceNext/Interop/OpusPacketMetrics.cs b/DisCatSharp.VoiceNext/Interop/OpusPacketMetrics.cs index 220d937f28..31c763f050 100644 --- a/DisCatSharp.VoiceNext/Interop/OpusPacketMetrics.cs +++ b/DisCatSharp.VoiceNext/Interop/OpusPacketMetrics.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.VoiceNext.Interop; internal struct OpusPacketMetrics diff --git a/DisCatSharp.VoiceNext/Interop/OpusSignal.cs b/DisCatSharp.VoiceNext/Interop/OpusSignal.cs index a278ebc566..5559820ab8 100644 --- a/DisCatSharp.VoiceNext/Interop/OpusSignal.cs +++ b/DisCatSharp.VoiceNext/Interop/OpusSignal.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.VoiceNext.Interop; internal enum OpusSignal : int diff --git a/DisCatSharp.VoiceNext/StreamExtensions.cs b/DisCatSharp.VoiceNext/StreamExtensions.cs index c268f4a001..71f244a6a7 100644 --- a/DisCatSharp.VoiceNext/StreamExtensions.cs +++ b/DisCatSharp.VoiceNext/StreamExtensions.cs @@ -37,9 +37,7 @@ public static async Task CopyToAsync(this Stream source, VoiceTransmitSink desti { int bytesRead; while ((bytesRead = await source.ReadAsync(buffer.AsMemory(0, bufferLength), cancellationToken).ConfigureAwait(false)) != 0) - { - await destination.WriteAsync(new ReadOnlyMemory(buffer, 0, bytesRead), cancellationToken).ConfigureAwait(false); - } + await destination.WriteAsync(new(buffer, 0, bytesRead), cancellationToken).ConfigureAwait(false); } finally { diff --git a/DisCatSharp.VoiceNext/VoiceApplication.cs b/DisCatSharp.VoiceNext/VoiceApplication.cs index bf196b21d0..a9db1c186d 100644 --- a/DisCatSharp.VoiceNext/VoiceApplication.cs +++ b/DisCatSharp.VoiceNext/VoiceApplication.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.VoiceNext; /// diff --git a/DisCatSharp.VoiceNext/VoiceNextConfiguration.cs b/DisCatSharp.VoiceNext/VoiceNextConfiguration.cs index 1583f0890a..96d1b01d62 100644 --- a/DisCatSharp.VoiceNext/VoiceNextConfiguration.cs +++ b/DisCatSharp.VoiceNext/VoiceNextConfiguration.cs @@ -37,7 +37,7 @@ public VoiceNextConfiguration() { } /// Configuration the properties of which are to be copied. public VoiceNextConfiguration(VoiceNextConfiguration other) { - this.AudioFormat = new AudioFormat(other.AudioFormat.SampleRate, other.AudioFormat.ChannelCount, other.AudioFormat.VoiceApplication); + this.AudioFormat = new(other.AudioFormat.SampleRate, other.AudioFormat.ChannelCount, other.AudioFormat.VoiceApplication); this.EnableIncoming = other.EnableIncoming; } } diff --git a/DisCatSharp.VoiceNext/VoiceNextConnection.cs b/DisCatSharp.VoiceNext/VoiceNextConnection.cs index 7780d05bd2..9829b06404 100644 --- a/DisCatSharp.VoiceNext/VoiceNextConnection.cs +++ b/DisCatSharp.VoiceNext/VoiceNextConnection.cs @@ -42,6 +42,7 @@ public event AsyncEventHandler UserS add => this._userSpeaking.Register(value); remove => this._userSpeaking.Unregister(value); } + private readonly AsyncEvent _userSpeaking; /// @@ -52,6 +53,7 @@ public event AsyncEventHandler User add => this._userJoined.Register(value); remove => this._userJoined.Unregister(value); } + private readonly AsyncEvent _userJoined; /// @@ -62,6 +64,7 @@ public event AsyncEventHandler Use add => this._userLeft.Register(value); remove => this._userLeft.Unregister(value); } + private readonly AsyncEvent _userLeft; /// @@ -72,6 +75,7 @@ public event AsyncEventHandler Voice add => this._voiceReceived.Register(value); remove => this._voiceReceived.Unregister(value); } + private readonly AsyncEvent _voiceReceived; /// @@ -82,6 +86,7 @@ public event AsyncEventHandler VoiceS add => this._voiceSocketError.Register(value); remove => this._voiceSocketError.Unregister(value); } + private readonly AsyncEvent _voiceSocketError; internal event VoiceDisconnectedEventHandler VoiceDisconnected; @@ -135,6 +140,7 @@ public event AsyncEventHandler VoiceS /// Gets or sets the token source. /// private CancellationTokenSource _tokenSource; + /// /// Gets the token. /// @@ -150,10 +156,12 @@ private CancellationToken TOKEN /// Gets or sets the server data. /// internal VoiceServerUpdatePayload ServerData { get; set; } + /// /// Gets or sets the state data. /// internal VoiceStateUpdatePayload StateData { get; set; } + /// /// Gets or sets a value indicating whether resume. /// @@ -183,6 +191,7 @@ private CancellationToken TOKEN /// Gets or sets the selected encryption mode. /// private EncryptionMode _selectedEncryptionMode; + /// /// Gets or sets the nonce. /// @@ -212,10 +221,12 @@ private CancellationToken TOKEN /// Gets or sets the discovered endpoint. /// private IpEndpoint _discoveredEndpoint; + /// /// Gets or sets the web socket endpoint. /// internal ConnectionEndpoint WebSocketEndpoint { get; set; } + /// /// Gets or sets the udp endpoint. /// @@ -260,6 +271,7 @@ private CancellationToken TOKEN /// Gets the keepalive timestamps. /// private readonly ConcurrentDictionary _keepaliveTimestamps; + private ulong _lastKeepalive; /// @@ -271,6 +283,7 @@ private CancellationToken TOKEN /// Gets or sets the sender token source. /// private CancellationTokenSource _senderTokenSource; + /// /// Gets the sender token. /// @@ -286,6 +299,7 @@ private CancellationToken SENDER_TOKEN /// Gets or sets the receiver token source. /// private CancellationTokenSource _receiverTokenSource; + /// /// Gets the receiver token. /// @@ -301,6 +315,7 @@ private CancellationToken RECEIVER_TOKEN /// Gets or sets the keepalive token source. /// private CancellationTokenSource _keepaliveTokenSource; + /// /// Gets the keepalive token. /// @@ -323,6 +338,7 @@ public bool IsPlaying /// public int WebSocketPing => Volatile.Read(ref this._wsPing); + private int _wsPing; /// @@ -330,6 +346,7 @@ public int WebSocketPing /// public int UdpPing => Volatile.Read(ref this._udpPing); + private int _udpPing; private int _queueCount; @@ -353,21 +370,21 @@ internal VoiceNextConnection(DiscordClient client, DiscordGuild guild, DiscordCh this._discord = client; this._guild = guild; this.TargetChannel = channel; - this._transmittingSsrCs = new ConcurrentDictionary(); + this._transmittingSsrCs = new(); - this._userSpeaking = new AsyncEvent("VNEXT_USER_SPEAKING", TimeSpan.Zero, this._discord.EventErrorHandler); - this._userJoined = new AsyncEvent("VNEXT_USER_JOINED", TimeSpan.Zero, this._discord.EventErrorHandler); - this._userLeft = new AsyncEvent("VNEXT_USER_LEFT", TimeSpan.Zero, this._discord.EventErrorHandler); - this._voiceReceived = new AsyncEvent("VNEXT_VOICE_RECEIVED", TimeSpan.Zero, this._discord.EventErrorHandler); - this._voiceSocketError = new AsyncEvent("VNEXT_WS_ERROR", TimeSpan.Zero, this._discord.EventErrorHandler); - this._tokenSource = new CancellationTokenSource(); + this._userSpeaking = new("VNEXT_USER_SPEAKING", TimeSpan.Zero, this._discord.EventErrorHandler); + this._userJoined = new("VNEXT_USER_JOINED", TimeSpan.Zero, this._discord.EventErrorHandler); + this._userLeft = new("VNEXT_USER_LEFT", TimeSpan.Zero, this._discord.EventErrorHandler); + this._voiceReceived = new("VNEXT_VOICE_RECEIVED", TimeSpan.Zero, this._discord.EventErrorHandler); + this._voiceSocketError = new("VNEXT_WS_ERROR", TimeSpan.Zero, this._discord.EventErrorHandler); + this._tokenSource = new(); this._configuration = config; this._isInitialized = false; this._isDisposed = false; - this._opus = new Opus(this.AudioFormat); + this._opus = new(this.AudioFormat); //this.Sodium = new Sodium(); - this._rtp = new Rtp(); + this._rtp = new(); this.ServerData = server; this.StateData = state; @@ -382,17 +399,19 @@ internal VoiceNextConnection(DiscordClient client, DiscordGuild guild, DiscordCh epp = int.Parse(eps[(epi + 1)..]); } else - { eph = eps; - } - this.WebSocketEndpoint = new ConnectionEndpoint { Hostname = eph, Port = epp }; - this._readyWait = new TaskCompletionSource(); + this.WebSocketEndpoint = new() + { + Hostname = eph, Port = epp + }; + + this._readyWait = new(); this._playingWait = null; this._transmitChannel = Channel.CreateBounded(new BoundedChannelOptions(this._configuration.PacketQueueSize)); - this._keepaliveTimestamps = new ConcurrentDictionary(); - this._pauseEvent = new AsyncManualResetEvent(true); + this._keepaliveTimestamps = new(); + this._pauseEvent = new(true); this._udpClient = this._discord.Configuration.UdpClientFactory(); this._voiceWs = this._discord.Configuration.WebSocketClientFactory(this._discord.Configuration.Proxy, this._discord.ServiceProvider); @@ -415,9 +434,7 @@ internal Task ConnectAsync() { var gwuri = new UriBuilder { - Scheme = "wss", - Host = this.WebSocketEndpoint.Hostname, - Query = "encoding=json&v=4" + Scheme = "wss", Host = this.WebSocketEndpoint.Hostname, Query = "encoding=json&v=4" }; return this._voiceWs.ConnectAsync(gwuri.Uri); @@ -444,10 +461,7 @@ internal async Task StartAsync() vdp.OpCode = 0; vdp.Payload = new VoiceIdentifyPayload { - ServerId = this.ServerData.GuildId, - UserId = this.StateData.UserId.Value, - SessionId = this.StateData.SessionId, - Token = this.ServerData.Token + ServerId = this.ServerData.GuildId, UserId = this.StateData.UserId.Value, SessionId = this.StateData.SessionId, Token = this.ServerData.Token }; this.Resume = true; } @@ -456,11 +470,10 @@ internal async Task StartAsync() vdp.OpCode = 7; vdp.Payload = new VoiceIdentifyPayload { - ServerId = this.ServerData.GuildId, - SessionId = this.StateData.SessionId, - Token = this.ServerData.Token + ServerId = this.ServerData.GuildId, SessionId = this.StateData.SessionId, Token = this.ServerData.Token }; } + var vdj = JsonConvert.SerializeObject(vdp, Formatting.None); await this.WsSendAsync(vdj).ConfigureAwait(false); } @@ -528,7 +541,7 @@ internal bool PreparePacket(ReadOnlySpan pcm, out byte[] target, out int l default: ArrayPool.Shared.Return(packetArray); - throw new Exception("Unsupported encryption mode."); + throw new("Unsupported encryption mode."); } Span encrypted = stackalloc byte[Sodium.CalculateTargetSize(opus)]; @@ -570,7 +583,7 @@ private async Task VoiceSenderTask() this._queueCount--; if (this._playingWait == null || this._playingWait.Task.IsCompleted) - this._playingWait = new TaskCompletionSource(); + this._playingWait = new(); } // Provided by Laura#0090 (214796473689178133); this is Python, but adaptable: @@ -596,7 +609,7 @@ private async Task VoiceSenderTask() var durationModifier = hasPacket ? rawPacket.Duration / 5 : 4; var cts = Math.Max(Stopwatch.GetTimestamp() - synchronizerTicks, 0); if (cts < synchronizerResolution * durationModifier) - await Task.Delay(TimeSpan.FromTicks((long)(((synchronizerResolution * durationModifier) - cts) * tickResolution))).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromTicks((long)((synchronizerResolution * durationModifier - cts) * tickResolution))).ConfigureAwait(false); synchronizerTicks += synchronizerResolution * durationModifier; @@ -614,7 +627,7 @@ private async Task VoiceSenderTask() { var nullpacket = new byte[nullpcm.Length]; var nullpacketmem = nullpacket.AsMemory(); - await this.EnqueuePacketAsync(new RawVoicePacket(nullpacketmem, 20, true)).ConfigureAwait(false); + await this.EnqueuePacketAsync(new(nullpacketmem, 20, true)).ConfigureAwait(false); } } else if (this._queueCount == 0) @@ -650,7 +663,7 @@ private bool ProcessPacket(ReadOnlySpan data, ref Memory opus, ref M { var decoder = this._opus.CreateDecoder(); - vtx = new AudioSender(ssrc, decoder) + vtx = new(ssrc, decoder) { // user isn't present as we haven't received a speaking event yet. User = null @@ -683,12 +696,11 @@ private bool ProcessPacket(ReadOnlySpan data, ref Memory opus, ref M // Strip extensions, if any if (hasExtension) - { // RFC 5285, 4.2 One-Byte header // http://www.rfcreader.com/#rfc5285_line186 if (opusSpan[0] == 0xBE && opusSpan[1] == 0xDE) { - var headerLen = (opusSpan[2] << 8) | opusSpan[3]; + var headerLen = opusSpan[2] << 8 | opusSpan[3]; var i = 4; for (; i < headerLen + 4; i++) { @@ -708,15 +720,11 @@ private bool ProcessPacket(ReadOnlySpan data, ref Memory opus, ref M opusSpan = opusSpan[i..]; } - // TODO: consider implementing RFC 5285, 4.3. Two-Byte Header - } - + // TODO: consider implementing RFC 5285, 4.3. Two-Byte Header if (opusSpan[0] == 0x90) - { // I'm not 100% sure what this header is/does, however removing the data causes no // real issues, and has the added benefit of removing a lot of noise. opusSpan = opusSpan[2..]; - } if (gap == 1) { @@ -771,7 +779,7 @@ private async Task ProcessVoicePacket(byte[] data) return; foreach (var pcmFiller in pcmFillers) - await this._voiceReceived.InvokeAsync(this, new VoiceReceiveEventArgs(this._discord.ServiceProvider) + await this._voiceReceived.InvokeAsync(this, new(this._discord.ServiceProvider) { Ssrc = vtx.Ssrc, User = vtx.User, @@ -781,7 +789,7 @@ private async Task ProcessVoicePacket(byte[] data) AudioDuration = audioFormat.CalculateSampleDuration(pcmFiller.Length) }).ConfigureAwait(false); - await this._voiceReceived.InvokeAsync(this, new VoiceReceiveEventArgs(this._discord.ServiceProvider) + await this._voiceReceived.InvokeAsync(this, new(this._discord.ServiceProvider) { Ssrc = vtx.Ssrc, User = vtx.User, @@ -857,8 +865,7 @@ public async Task SendSpeakingAsync(SpeakingFlags flags = SpeakingFlags.Micropho OpCode = 5, Payload = new VoiceSpeakingPayload { - Speaking = flags, - Delay = 0 + Speaking = flags, Delay = 0 } }; @@ -877,7 +884,7 @@ public VoiceTransmitSink GetTransmitSink(int sampleDuration = 20) if (!AudioFormat.AllowedSampleDurations.Contains(sampleDuration)) throw new ArgumentOutOfRangeException(nameof(sampleDuration), "Invalid PCM sample duration specified."); - this._transmitStream ??= new VoiceTransmitSink(this, sampleDuration); + this._transmitStream ??= new(this, sampleDuration); return this._transmitStream; } @@ -972,7 +979,6 @@ private async Task HeartbeatAsync() var token = this.TOKEN; while (true) - { try { token.ThrowIfCancellationRequested(); @@ -982,8 +988,7 @@ private async Task HeartbeatAsync() var hbd = new VoiceDispatch { - OpCode = 3, - Payload = UnixTimestamp(dt) + OpCode = 3, Payload = UnixTimestamp(dt) }; var hbj = JsonConvert.SerializeObject(hbd); await this.WsSendAsync(hbj).ConfigureAwait(false); @@ -995,7 +1000,6 @@ private async Task HeartbeatAsync() { return; } - } } /// @@ -1041,10 +1045,9 @@ private async Task Stage1(VoiceReadyPayload voiceReady) var ipd = await this._udpClient.ReceiveAsync().ConfigureAwait(false); ReadPacket(ipd, out var ip, out var port); - this._discoveredEndpoint = new IpEndpoint + this._discoveredEndpoint = new() { - Address = ip, - Port = port + Address = ip, Port = port }; this._discord.Logger.LogTrace(VoiceNextEvents.VoiceHandshake, "Endpoint discovery finished - discovered endpoint is {0}:{1}", ip, port); @@ -1082,21 +1085,19 @@ void ReadPacket(byte[] packet, out System.Net.IPAddress decodedIp, out ushort de Payload = new VoiceSelectProtocolPayload { Protocol = "udp", - Data = new VoiceSelectProtocolPayloadData + Data = new() { - Address = this._discoveredEndpoint.Address.ToString(), - Port = (ushort)this._discoveredEndpoint.Port, - Mode = selectedEncryptionMode.Key + Address = this._discoveredEndpoint.Address.ToString(), Port = (ushort)this._discoveredEndpoint.Port, Mode = selectedEncryptionMode.Key } } }; var vsj = JsonConvert.SerializeObject(vsp, Formatting.None); await this.WsSendAsync(vsj).ConfigureAwait(false); - this._senderTokenSource = new CancellationTokenSource(); + this._senderTokenSource = new(); this._senderTask = Task.Run(this.VoiceSenderTask, this.SENDER_TOKEN); - this._receiverTokenSource = new CancellationTokenSource(); + this._receiverTokenSource = new(); this._receiverTask = Task.Run(this.UdpReceiverTask, this.RECEIVER_TOKEN); } @@ -1111,7 +1112,7 @@ private async Task Stage2(VoiceSessionDescriptionPayload voiceSessionDescription this._discord.Logger.LogTrace(VoiceNextEvents.VoiceHandshake, "Discord updated encryption mode - new mode is {0}", this._selectedEncryptionMode); // start keepalive - this._keepaliveTokenSource = new CancellationTokenSource(); + this._keepaliveTokenSource = new(); this._keepaliveTask = this.KeepaliveAsync(); // send 3 packets of silence to get things going @@ -1120,7 +1121,7 @@ private async Task Stage2(VoiceSessionDescriptionPayload voiceSessionDescription { var nullPcm = new byte[nullpcm.Length]; var nullpacketmem = nullPcm.AsMemory(); - await this.EnqueuePacketAsync(new RawVoicePacket(nullpacketmem, 20, true)).ConfigureAwait(false); + await this.EnqueuePacketAsync(new(nullpacketmem, 20, true)).ConfigureAwait(false); } this._isInitialized = true; @@ -1143,7 +1144,7 @@ private async Task HandleDispatch(JObject jo) this._discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received READY (OP2)"); var vrp = opp.ToObject(); this._ssrc = vrp.Ssrc; - this.UdpEndpoint = new ConnectionEndpoint(vrp.Address, vrp.Port); + this.UdpEndpoint = new(vrp.Address, vrp.Port); // this is not the valid interval // oh, discord //this.HeartbeatInterval = vrp.HeartbeatInterval; @@ -1155,27 +1156,23 @@ private async Task HandleDispatch(JObject jo) this._discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received SESSION_DESCRIPTION (OP4)"); var vsd = opp.ToObject(); this._key = vsd.SecretKey; - this._sodium = new Sodium(this._key.AsMemory()); + this._sodium = new(this._key.AsMemory()); await this.Stage2(vsd).ConfigureAwait(false); break; case 5: // SPEAKING - // Don't spam OP5 - // No longer spam, Discord supposedly doesn't send many of these + // Don't spam OP5 + // No longer spam, Discord supposedly doesn't send many of these this._discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received SPEAKING (OP5)"); var spd = opp.ToObject(); var foundUserInCache = this._discord.TryGetCachedUserInternal(spd.UserId.Value, out var resolvedUser); var spk = new UserSpeakingEventArgs(this._discord.ServiceProvider) { - Speaking = spd.Speaking, - Ssrc = spd.Ssrc.Value, - User = resolvedUser, + Speaking = spd.Speaking, Ssrc = spd.Ssrc.Value, User = resolvedUser }; if (foundUserInCache && this._transmittingSsrCs.TryGetValue(spk.Ssrc, out var txssrc5) && txssrc5.Id == 0) - { txssrc5.User = spk.User; - } else { var opus = this._opus.CreateDecoder(); @@ -1200,7 +1197,7 @@ private async Task HandleDispatch(JObject jo) break; case 8: // HELLO - // this sends a heartbeat interval that we need to use for heartbeating + // this sends a heartbeat interval that we need to use for heartbeating this._discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received HELLO (OP8)"); this._heartbeatInterval = opp["heartbeat_interval"].ToObject(); break; @@ -1214,18 +1211,21 @@ private async Task HandleDispatch(JObject jo) this._discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received CLIENT_CONNECTED (OP12)"); var ujpd = opp.ToObject(); var usrj = await this._discord.GetUserAsync(ujpd.UserId, true).ConfigureAwait(false); + { + var opus = this._opus.CreateDecoder(); + var vtx = new AudioSender(ujpd.Ssrc, opus) { - var opus = this._opus.CreateDecoder(); - var vtx = new AudioSender(ujpd.Ssrc, opus) - { - User = usrj - }; + User = usrj + }; - if (!this._transmittingSsrCs.TryAdd(vtx.Ssrc, vtx)) - this._opus.DestroyDecoder(opus); - } + if (!this._transmittingSsrCs.TryAdd(vtx.Ssrc, vtx)) + this._opus.DestroyDecoder(opus); + } - await this._userJoined.InvokeAsync(this, new VoiceUserJoinEventArgs(this._discord.ServiceProvider) { User = usrj, Ssrc = ujpd.Ssrc }).ConfigureAwait(false); + await this._userJoined.InvokeAsync(this, new(this._discord.ServiceProvider) + { + User = usrj, Ssrc = ujpd.Ssrc + }).ConfigureAwait(false); break; case 13: // CLIENT_DISCONNECTED @@ -1239,10 +1239,9 @@ private async Task HandleDispatch(JObject jo) } var usrl = await this._discord.GetUserAsync(ulpd.UserId, true).ConfigureAwait(false); - await this._userLeft.InvokeAsync(this, new VoiceUserLeaveEventArgs(this._discord.ServiceProvider) + await this._userLeft.InvokeAsync(this, new(this._discord.ServiceProvider) { - User = usrl, - Ssrc = txssrc.Key + User = usrl, Ssrc = txssrc.Key }).ConfigureAwait(false); break; @@ -1273,7 +1272,7 @@ private async Task VoiceWS_SocketClosed(IWebSocketClient client, SocketCloseEven if (!this._isDisposed) { this._tokenSource.Cancel(); - this._tokenSource = new CancellationTokenSource(); + this._tokenSource = new(); this._voiceWs = this._discord.Configuration.WebSocketClientFactory(this._discord.Configuration.Proxy, this._discord.ServiceProvider); this._voiceWs.Disconnected += this.VoiceWS_SocketClosed; this._voiceWs.MessageReceived += this.VoiceWS_SocketMessage; @@ -1318,7 +1317,10 @@ private Task VoiceWS_SocketOpened(IWebSocketClient client, SocketEventArgs e) /// The e. /// A Task. private Task VoiceWs_SocketException(IWebSocketClient client, SocketErrorEventArgs e) - => this._voiceSocketError.InvokeAsync(this, new SocketErrorEventArgs(this._discord.ServiceProvider) { Exception = e.Exception }); + => this._voiceSocketError.InvokeAsync(this, new(this._discord.ServiceProvider) + { + Exception = e.Exception + }); /// /// Ws the send async. diff --git a/DisCatSharp.VoiceNext/VoiceNextExtension.cs b/DisCatSharp.VoiceNext/VoiceNextExtension.cs index 55a1cd9137..9a6a4173a8 100644 --- a/DisCatSharp.VoiceNext/VoiceNextExtension.cs +++ b/DisCatSharp.VoiceNext/VoiceNextExtension.cs @@ -48,12 +48,12 @@ public sealed class VoiceNextExtension : BaseExtension /// The config. internal VoiceNextExtension(VoiceNextConfiguration config) { - this._configuration = new VoiceNextConfiguration(config); + this._configuration = new(config); this.IsIncomingEnabled = config.EnableIncoming; - this._activeConnections = new ConcurrentDictionary(); - this._voiceStateUpdates = new ConcurrentDictionary>(); - this._voiceServerUpdates = new ConcurrentDictionary>(); + this._activeConnections = new(); + this._voiceStateUpdates = new(); + this._voiceServerUpdates = new(); } /// @@ -102,10 +102,7 @@ public async Task ConnectAsync(DiscordChannel channel) OpCode = 4, Payload = new VoiceStateUpdatePayload { - GuildId = gld.Id, - ChannelId = channel.Id, - Deafened = false, - Muted = false + GuildId = gld.Id, ChannelId = channel.Id, Deafened = false, Muted = false } }; var vsj = JsonConvert.SerializeObject(vsd, Formatting.None); @@ -114,15 +111,12 @@ public async Task ConnectAsync(DiscordChannel channel) var vstu = await vstut.Task.ConfigureAwait(false); var vstup = new VoiceStateUpdatePayload { - SessionId = vstu.SessionId, - UserId = vstu.User.Id + SessionId = vstu.SessionId, UserId = vstu.User.Id }; var vsru = await vsrut.Task.ConfigureAwait(false); var vsrup = new VoiceServerUpdatePayload { - Endpoint = vsru.Endpoint, - GuildId = vsru.Guild.Id, - Token = vsru.VoiceToken + Endpoint = vsru.Endpoint, GuildId = vsru.Guild.Id, Token = vsru.VoiceToken }; var vnc = new VoiceNextConnection(this.Client, gld, channel, this._configuration, vsrup, vstup); @@ -156,8 +150,7 @@ private async Task Vnc_VoiceDisconnected(DiscordGuild guild) OpCode = 4, Payload = new VoiceStateUpdatePayload { - GuildId = guild.Id, - ChannelId = null + GuildId = guild.Id, ChannelId = null } }; var vsj = JsonConvert.SerializeObject(vsd, Formatting.None); @@ -208,11 +201,9 @@ private async Task Client_VoiceServerUpdate(DiscordClient client, VoiceServerUpd if (this._activeConnections.TryGetValue(e.Guild.Id, out var vnc)) { - vnc.ServerData = new VoiceServerUpdatePayload + vnc.ServerData = new() { - Endpoint = e.Endpoint, - GuildId = e.Guild.Id, - Token = e.VoiceToken + Endpoint = e.Endpoint, GuildId = e.Guild.Id, Token = e.VoiceToken }; var eps = e.Endpoint; @@ -225,10 +216,12 @@ private async Task Client_VoiceServerUpdate(DiscordClient client, VoiceServerUpd epp = int.Parse(eps[(epi + 1)..]); } else - { eph = eps; - } - vnc.WebSocketEndpoint = new ConnectionEndpoint { Hostname = eph, Port = epp }; + + vnc.WebSocketEndpoint = new() + { + Hostname = eph, Port = epp + }; vnc.Resume = false; await vnc.ReconnectAsync().ConfigureAwait(false); diff --git a/DisCatSharp.VoiceNext/VoiceTransmitSink.cs b/DisCatSharp.VoiceNext/VoiceTransmitSink.cs index 8c94c04918..e1fd980d04 100644 --- a/DisCatSharp.VoiceNext/VoiceTransmitSink.cs +++ b/DisCatSharp.VoiceNext/VoiceTransmitSink.cs @@ -41,6 +41,7 @@ public double VolumeModifier this._volume = value; } } + private double _volume = 1.0; /// @@ -85,8 +86,8 @@ internal VoiceTransmitSink(VoiceNextConnection vnc, int pcmBufferDuration) this._pcmBuffer = new byte[vnc.AudioFormat.CalculateSampleSize(pcmBufferDuration)]; this._pcmMemory = this._pcmBuffer.AsMemory(); this._pcmBufferLength = 0; - this._writeSemaphore = new SemaphoreSlim(1, 1); - this._filters = new List(); + this._writeSemaphore = new(1, 1); + this._filters = new(); } /// @@ -96,7 +97,7 @@ internal VoiceTransmitSink(VoiceNextConnection vnc, int pcmBufferDuration) /// Start of the data in the buffer. /// Number of bytes from the buffer. /// The token to monitor for cancellation requests. - public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default) => await this.WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).ConfigureAwait(false); + public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default) => await this.WriteAsync(new(buffer, offset, count), cancellationToken).ConfigureAwait(false); /// /// Writes PCM data to the sink. The data is prepared for transmission, and enqueued. @@ -135,7 +136,7 @@ public async Task WriteAsync(ReadOnlyMemory buffer, CancellationToken canc var packetMemory = packet.AsMemory()[..this._pcmMemory.Length]; this._pcmMemory.CopyTo(packetMemory); - await this._connection.EnqueuePacketAsync(new RawVoicePacket(packetMemory, this.SampleDuration, false, packet), cancellationToken).ConfigureAwait(false); + await this._connection.EnqueuePacketAsync(new(packetMemory, this.SampleDuration, false, packet), cancellationToken).ConfigureAwait(false); } } } @@ -160,7 +161,7 @@ public async Task FlushAsync(CancellationToken cancellationToken = default) var packetMemory = packet.AsMemory()[..pcm.Length]; pcm.CopyTo(packetMemory); - await this._connection.EnqueuePacketAsync(new RawVoicePacket(packetMemory, this.SampleDuration, false, packet), cancellationToken).ConfigureAwait(false); + await this._connection.EnqueuePacketAsync(new(packetMemory, this.SampleDuration, false, packet), cancellationToken).ConfigureAwait(false); } /// @@ -236,20 +237,14 @@ private void ApplyFiltersSync(Memory pcmSpan) // pass through any filters, if applicable lock (this._filters) - { if (this._filters.Any()) - { foreach (var filter in this._filters) filter.Transform(pcm16, this._connection.AudioFormat, this.SampleDuration); - } - } if (this.VolumeModifier != 1) - { // alter volume for (var i = 0; i < pcm16.Length; i++) pcm16[i] = (short)(pcm16[i] * this.VolumeModifier); - } } /// diff --git a/DisCatSharp/BaseExtension.cs b/DisCatSharp/BaseExtension.cs index 882c6644c1..352c46b832 100644 --- a/DisCatSharp/BaseExtension.cs +++ b/DisCatSharp/BaseExtension.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp; /// diff --git a/DisCatSharp/Clients/BaseDiscordClient.cs b/DisCatSharp/Clients/BaseDiscordClient.cs index fbbefc9178..7d599fc55f 100644 --- a/DisCatSharp/Clients/BaseDiscordClient.cs +++ b/DisCatSharp/Clients/BaseDiscordClient.cs @@ -1,4 +1,3 @@ - #pragma warning disable CS0618 using System; using System.Collections.Concurrent; @@ -33,7 +32,7 @@ public abstract class BaseDiscordClient : IDisposable /// /// Gets the api client. /// - internal protected DiscordApiClient ApiClient { get; } + protected internal DiscordApiClient ApiClient { get; } /// /// Gets the sentry client. @@ -48,7 +47,7 @@ public abstract class BaseDiscordClient : IDisposable /// /// Gets the configuration. /// - internal protected DiscordConfiguration Configuration { get; } + protected internal DiscordConfiguration Configuration { get; } /// /// Gets the instance of the logger for this client. @@ -108,6 +107,7 @@ public IReadOnlyDictionary VoiceRegions /// Gets the list of available voice regions. This property is meant as a way to modify . /// protected internal ConcurrentDictionary InternalVoiceRegions { get; set; } + internal Lazy> VoiceRegionsLazy; /// @@ -138,9 +138,11 @@ protected BaseDiscordClient(DiscordConfiguration config) x.Format = ConsoleLoggerFormat.Default; x.TimestampFormat = this.Configuration.LogTimestampFormat; x.LogToStandardErrorThreshold = this.Configuration.MinimumLogLevel; - }); - var optionsFactory = new OptionsFactory(new[] { configureNamedOptions }, Enumerable.Empty>()); + var optionsFactory = new OptionsFactory(new[] + { + configureNamedOptions + }, Enumerable.Empty>()); var optionsMonitor = new OptionsMonitor(optionsFactory, Enumerable.Empty>(), new OptionsCache()); var l = new ConsoleLoggerProvider(optionsMonitor); @@ -161,7 +163,6 @@ protected BaseDiscordClient(DiscordConfiguration config) if (!this.Configuration.HasShardLogger) if (this.Configuration.LoggerFactory != null && this.Configuration.EnableSentry) - { this.Configuration.LoggerFactory.AddSentry(o => { o.InitializeSdk = true; @@ -203,15 +204,18 @@ protected BaseDiscordClient(DiscordConfiguration config) Id = this.CurrentUser.Id.ToString(), Username = this.CurrentUser.UsernameWithDiscriminator, Other = new Dictionary() - { - { "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" }, - { "email", this.Configuration.FeedbackEmail ?? "not_given" } - } + { + { + "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" + }, + { + "email", this.Configuration.FeedbackEmail ?? "not_given" + } + } }; return e; }; }); - } if (this.Configuration.EnableSentry) this.Sentry = new(new() @@ -251,10 +255,14 @@ protected BaseDiscordClient(DiscordConfiguration config) Id = this.CurrentUser.Id.ToString(), Username = this.CurrentUser.UsernameWithDiscriminator, Other = new Dictionary() + { + { + "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" + }, { - { "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" }, - { "email", this.Configuration.FeedbackEmail ?? "not_given" } + "email", this.Configuration.FeedbackEmail ?? "not_given" } + } }; if (!e.Extra.ContainsKey("Found Fields")) @@ -282,9 +290,7 @@ protected BaseDiscordClient(DiscordConfiguration config) var iv = a.GetCustomAttribute(); if (iv != null) - { this.VersionString = iv.InformationalVersion; - } else { var v = a.GetName().Version; @@ -325,17 +331,23 @@ public async Task GetCurrentApplicationAsync() if (tapp.Team == null) { - app.Members = new(new[] { new DiscordUser(tapp.Owner) }); + app.Members = new(new[] + { + new DiscordUser(tapp.Owner) + }); app.Team = null; app.TeamName = null; - app.Owner = new DiscordUser(tapp.Owner); + app.Owner = new(tapp.Owner); } else { app.Team = new(tapp.Team); var members = tapp.Team.Members - .Select(x => new DiscordTeamMember(x) { TeamId = app.Team.Id, TeamName = app.Team.Name, User = new(x.User) }) + .Select(x => new DiscordTeamMember(x) + { + TeamId = app.Team.Id, TeamName = app.Team.Name, User = new(x.User) + }) .ToArray(); foreach (var member in members) @@ -384,15 +396,22 @@ public async Task GetCurrentApplicationAsync() /// The updated application. public async Task UpdateCurrentApplicationInfoAsync( Optional description, - Optional interactionsEndpointUrl, Optional roleConnectionsVerificationUrl, Optional customInstallUrl, - Optional?> tags, Optional icon, Optional coverImage, - Optional flags, Optional installParams) + Optional interactionsEndpointUrl, + Optional roleConnectionsVerificationUrl, + Optional customInstallUrl, + Optional?> tags, + Optional icon, + Optional coverImage, + Optional flags, + Optional installParams + ) { var iconb64 = ImageTool.Base64FromStream(icon); var coverImageb64 = ImageTool.Base64FromStream(coverImage); if (tags != null && tags.HasValue && tags.Value != null) if (tags.Value.Any(x => x.Length > 20)) throw new InvalidOperationException("Tags can not exceed 20 chars."); + _ = await this.ApiClient.ModifyCurrentApplicationInfoAsync(description, interactionsEndpointUrl, roleConnectionsVerificationUrl, customInstallUrl, tags, iconb64, coverImageb64, flags, installParams).ConfigureAwait(false); // We use GetCurrentApplicationAsync because modify returns internal data not meant for developers. var app = await this.GetCurrentApplicationAsync().ConfigureAwait(false); @@ -435,8 +454,12 @@ public virtual async Task InitializeAsync() Username = this.CurrentUser.UsernameWithDiscriminator, Other = new Dictionary() { - { "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" }, - { "email", this.Configuration.FeedbackEmail ?? "not_given" } + { + "developer", this.Configuration.DeveloperUserId?.ToString() ?? "not_given" + }, + { + "email", this.Configuration.FeedbackEmail ?? "not_given" + } } }); } @@ -496,7 +519,10 @@ internal bool TryGetCachedUserInternal(ulong userId, out DiscordUser user) if (this.UserCache.TryGetValue(userId, out user)) return true; - user = new() { Id = userId, Discord = this }; + user = new() + { + Id = userId, Discord = this + }; return false; } diff --git a/DisCatSharp/Clients/DiscordClient.Dispatch.cs b/DisCatSharp/Clients/DiscordClient.Dispatch.cs index 922fedae98..01d3283701 100644 --- a/DisCatSharp/Clients/DiscordClient.Dispatch.cs +++ b/DisCatSharp/Clients/DiscordClient.Dispatch.cs @@ -23,11 +23,11 @@ namespace DisCatSharp; /// -/// Represents a discord Logger.ent.L +/// A Discord API wrapper. /// public sealed partial class DiscordClient { - #region Private Fields +#region Private Fields private string _resumeGatewayUrl; private string _sessionId; @@ -76,9 +76,9 @@ internal TimeoutHandler(DiscordMember mbr, DiscordGuild guild, DateTime? too, Da } } - #endregion +#endregion - #region Dispatch Handler +#region Dispatch Handler /// /// Handles the dispatch payloads. @@ -95,11 +95,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) if ((this.Configuration?.EnableLibraryDeveloperMode ?? false) || (this.Configuration?.EnablePayloadReceivedEvent ?? false)) await this._payloadReceived.InvokeAsync(this, new(this.ServiceProvider) { - EventName = payload.EventName, - PayloadObject = dat + EventName = payload.EventName, PayloadObject = dat }).ConfigureAwait(false); - #region Default objects var payloadString = dat.ToString(); @@ -120,11 +118,12 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) DiscordEntitlement ent = default; JToken rawMbr = default; var rawRefMsg = dat["referenced_message"]; // TODO: Can we remove this? - #endregion + +#endregion switch (payload.EventName.ToLowerInvariant()) { - #region Gateway Status +#region Gateway Status case "ready": var glds = (JArray)dat["guilds"]!; @@ -135,9 +134,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnResumedAsync().ConfigureAwait(false); break; - #endregion +#endregion - #region Channel +#region Channel case "channel_create": chn = DiscordJson.DeserializeObject(payloadString, this); @@ -170,9 +169,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) // It's fired incorrectly. break; - #endregion +#endregion - #region Guild +#region Guild case "guild_create": await this.OnGuildCreateEventAsync(dat.ToDiscordObject(), (JArray)dat["members"]!, dat["presences"]!.ToDiscordObject>()).ConfigureAwait(false); @@ -218,9 +217,11 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildIntegrationsUpdateEventAsync(this.GuildsInternal[gid]).ConfigureAwait(false); break; - #endregion - #region Guild Automod +#endregion + +#region Guild Automod + case "auto_moderation_rule_create": await this.OnAutomodRuleCreated(dat.ToDiscordObject()).ConfigureAwait(false); break; @@ -234,9 +235,10 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) gid = (ulong)dat["guild_id"]!; await this.OnAutomodActionExecuted(this.GuildsInternal[gid], dat).ConfigureAwait(false); break; - #endregion - #region Guild Ban +#endregion + +#region Guild Ban case "guild_ban_add": usr = DiscordJson.DeserializeObject(dat["user"]!.ToString(), this); @@ -250,9 +252,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildBanRemoveEventAsync(usr, this.GuildsInternal[gid]).ConfigureAwait(false); break; - #endregion +#endregion - #region Guild Event +#region Guild Event case "guild_scheduled_event_create": gse = DiscordJson.DeserializeObject(payloadString, this); @@ -284,9 +286,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildScheduledEventUserRemovedEventAsync((ulong)dat["guild_scheduled_event_id"]!, uid, this.GuildsInternal[gid]).ConfigureAwait(false); break; - #endregion +#endregion - #region Guild Integration +#region Guild Integration case "integration_create": gid = (ulong)dat["guild_id"]!; @@ -319,9 +321,10 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildIntegrationDeleteEventAsync(this.GuildsInternal[gid], (ulong)dat["id"], (ulong?)dat["application_id"]).ConfigureAwait(false); break; - #endregion - #region Guild Member +#endregion + +#region Guild Member case "guild_member_add": gid = (ulong)dat["guild_id"]!; @@ -352,9 +355,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildMembersChunkEventAsync(dat).ConfigureAwait(false); break; - #endregion +#endregion - #region Guild Role +#region Guild Role case "guild_role_create": gid = (ulong)dat["guild_id"]!; @@ -371,9 +374,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnGuildRoleDeleteEventAsync((ulong)dat["role_id"]!, this.GuildsInternal[gid]).ConfigureAwait(false); break; - #endregion +#endregion - #region Invite +#region Invite case "invite_create": gid = (ulong)dat["guild_id"]!; @@ -387,9 +390,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnInviteDeleteEventAsync(cid, gid, dat).ConfigureAwait(false); break; - #endregion +#endregion - #region Message +#region Message case "message_ack": cid = (ulong)dat["channel_id"]!; @@ -409,8 +412,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) refUsr = DiscordJson.DeserializeObject(rawRefMsg.SelectToken("author")!.ToString(), this); if (rawRefMsg.SelectToken("member") != null) - refMbr = DiscordJson.DeserializeObject(json: rawRefMsg.SelectToken("member")!.ToString(), this); + refMbr = DiscordJson.DeserializeObject(rawRefMsg.SelectToken("member")!.ToString(), this); } + await this.OnMessageCreateEventAsync(dat.ToDiscordObject(), dat["author"].ToObject(), mbr, refUsr, refMbr).ConfigureAwait(false); break; @@ -426,7 +430,7 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) refUsr = DiscordJson.DeserializeObject(rawRefMsg.SelectToken("author")!.ToString(), this); if (rawRefMsg.SelectToken("member") != null) - refMbr = DiscordJson.DeserializeObject(json: rawRefMsg.SelectToken("member")!.ToString(), this); + refMbr = DiscordJson.DeserializeObject(rawRefMsg.SelectToken("member")!.ToString(), this); } await this.OnMessageUpdateEventAsync(DiscordJson.DeserializeObject(payloadString, this), dat["author"] != null ? DiscordJson.DeserializeObject(dat["author"]!.ToString(), this) : null, mbr!, refUsr!, refMbr!).ConfigureAwait(false); @@ -441,9 +445,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnMessageBulkDeleteEventAsync(dat["ids"]!.ToObject()!, (ulong)dat["channel_id"]!, (ulong?)dat["guild_id"]).ConfigureAwait(false); break; - #endregion +#endregion - #region Message Reaction +#region Message Reaction case "message_reaction_add": rawMbr = dat["member"]!; @@ -466,9 +470,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnMessageReactionRemoveEmojiAsync((ulong)dat["message_id"]!, (ulong)dat["channel_id"]!, (ulong)dat["guild_id"]!, DiscordJson.DeserializeObject(dat["emoji"]!.ToString(), this)).ConfigureAwait(false); break; - #endregion +#endregion - #region Stage Instance +#region Stage Instance case "stage_instance_create": stg = DiscordJson.DeserializeObject(payloadString, this); @@ -485,9 +489,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnStageInstanceDeleteEventAsync(stg).ConfigureAwait(false); break; - #endregion +#endregion - #region Thread +#region Thread case "thread_create": trd = DiscordJson.DeserializeObject(payloadString, this); @@ -522,17 +526,19 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnThreadMembersUpdateEventAsync(this.GuildsInternal[gid], (ulong)dat["id"]!, (JArray)dat["added_members"]!, (JArray)dat["removed_member_ids"]!, (int)dat["member_count"]!).ConfigureAwait(false); break; - #endregion +#endregion + +#region Activities - #region Activities case "embedded_activity_update": gid = (ulong)dat["guild_id"]!; cid = (ulong)dat["channel_id"]!; await this.OnEmbeddedActivityUpdateAsync((JObject)dat["embedded_activity"]!, this.GuildsInternal[gid], cid, (JArray)dat["users"]!, (ulong)dat["embedded_activity"]["application_id"]!).ConfigureAwait(false); break; - #endregion - #region User/Presence Update +#endregion + +#region User/Presence Update case "presence_update": await this.OnPresenceUpdateEventAsync(dat, (JObject)dat["user"]!).ConfigureAwait(false); @@ -548,9 +554,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnUserUpdateEventAsync(usr).ConfigureAwait(false); break; - #endregion +#endregion - #region Voice +#region Voice case "voice_state_update": await this.OnVoiceStateUpdateEventAsync(dat).ConfigureAwait(false); @@ -561,9 +567,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnVoiceServerUpdateEventAsync((string)dat["endpoint"]!, (string)dat["token"]!, this.GuildsInternal[gid]).ConfigureAwait(false); break; - #endregion +#endregion - #region Interaction/Integration/Application +#region Interaction/Integration/Application case "interaction_create": rawMbr = dat["member"]!; @@ -615,9 +621,9 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) await this.OnApplicationCommandPermissionsUpdateAsync(pms, (ulong)dat["id"]!, gid, aid).ConfigureAwait(false); break; - #endregion +#endregion - #region Misc +#region Misc case "gift_code_update": //Not supposed to be dispatched to bots break; @@ -661,15 +667,15 @@ internal async Task HandleDispatchAsync(GatewayPayload payload) this.Logger.LogWarning(LoggerEvents.WebSocketReceive, "Unknown event: {name}\npayload: {payload}", payload.EventName, dat.ToString(Formatting.Indented)); break; - #endregion +#endregion } } - #endregion +#endregion - #region Events +#region Events - #region Gateway +#region Gateway /// /// Handles the ready event. @@ -725,7 +731,6 @@ internal async Task OnReadyEventAsync(ReadyPayload ready, JArray rawGuilds) guild.MembersInternal = new(); if (rawMembers != null) - { foreach (var xj in rawMembers) { var xtm = xj.ToObject(); @@ -749,9 +754,11 @@ internal async Task OnReadyEventAsync(ReadyPayload ready, JArray rawGuilds) return old; }); - guild.MembersInternal[xtm.User.Id] = new(xtm) { Discord = this, GuildId = guild.Id }; + guild.MembersInternal[xtm.User.Id] = new(xtm) + { + Discord = this, GuildId = guild.Id + }; } - } guild.EmojisInternal ??= new(); @@ -798,9 +805,9 @@ internal Task OnResumedAsync() return this._resumed.InvokeAsync(this, new(this.ServiceProvider)); } - #endregion +#endregion - #region Channel +#region Channel /// /// Handles the channel create event. @@ -817,7 +824,10 @@ internal async Task OnChannelCreateEventAsync(DiscordChannel channel) await this.RefreshChannelsAsync(channel.Guild.Id); }*/ - await this._channelCreated.InvokeAsync(this, new(this.ServiceProvider) { Channel = channel, Guild = channel.Guild }).ConfigureAwait(false); + await this._channelCreated.InvokeAsync(this, new(this.ServiceProvider) + { + Channel = channel, Guild = channel.Guild + }).ConfigureAwait(false); } /// @@ -856,7 +866,7 @@ internal async Task OnChannelUpdateEventAsync(DiscordChannel channel) PerUserRateLimit = channelNew.PerUserRateLimit, RtcRegionId = channelNew.RtcRegionId, QualityMode = channelNew.QualityMode, - DefaultAutoArchiveDuration = channelNew.DefaultAutoArchiveDuration, + DefaultAutoArchiveDuration = channelNew.DefaultAutoArchiveDuration }; channelNew.Bitrate = channel.Bitrate; @@ -878,7 +888,6 @@ internal async Task OnChannelUpdateEventAsync(DiscordChannel channel) channelNew.PermissionOverwritesInternal.AddRange(channel.PermissionOverwritesInternal); - if (channel.Type == ChannelType.Forum) { channelOld.PostCreateUserRateLimit = channelNew.PostCreateUserRateLimit; @@ -912,25 +921,25 @@ internal async Task OnChannelUpdateEventAsync(DiscordChannel channel) channelNew.DefaultReactionEmoji = null; channelNew.DefaultSortOrder = null; } + channelOld.Initialize(this); channelNew.Initialize(this); if (this.Configuration.AutoRefreshChannelCache && gld != null) - { await this.RefreshChannelsAsync(channel.Guild.Id).ConfigureAwait(false); - } } else if (gld != null) { gld.ChannelsInternal[channel.Id] = channel; if (this.Configuration.AutoRefreshChannelCache) - { await this.RefreshChannelsAsync(channel.Guild.Id).ConfigureAwait(false); - } } - await this._channelUpdated.InvokeAsync(this, new(this.ServiceProvider) { ChannelAfter = channelNew, Guild = gld, ChannelBefore = channelOld }).ConfigureAwait(false); + await this._channelUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + ChannelAfter = channelNew, Guild = gld, ChannelBefore = channelOld + }).ConfigureAwait(false); } /// @@ -949,7 +958,10 @@ internal async Task OnChannelDeleteEventAsync(DiscordChannel channel) { var dmChannel = channel as DiscordDmChannel; - await this._dmChannelDeleted.InvokeAsync(this, new(this.ServiceProvider) { Channel = dmChannel }).ConfigureAwait(false); + await this._dmChannelDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + Channel = dmChannel + }).ConfigureAwait(false); } else { @@ -958,11 +970,12 @@ internal async Task OnChannelDeleteEventAsync(DiscordChannel channel) if (gld.ChannelsInternal.TryRemove(channel.Id, out var cachedChannel)) channel = cachedChannel; if (this.Configuration.AutoRefreshChannelCache) - { await this.RefreshChannelsAsync(channel.Guild.Id).ConfigureAwait(false); - } - await this._channelDeleted.InvokeAsync(this, new(this.ServiceProvider) { Channel = channel, Guild = gld }).ConfigureAwait(false); + await this._channelDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + Channel = channel, Guild = gld + }).ConfigureAwait(false); } } @@ -995,9 +1008,7 @@ internal async Task OnChannelPinsUpdateAsync(ulong? guildId, ulong channelId, Da var ea = new ChannelPinsUpdateEventArgs(this.ServiceProvider) { - Guild = guild, - Channel = channel, - LastPinTimestamp = lastPinTimestamp + Guild = guild, Channel = channel, LastPinTimestamp = lastPinTimestamp }; await this._channelPinsUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -1015,16 +1026,14 @@ internal async Task OnVoiceChannelStatusUpdateAsync(ulong guildId, ulong channel var ea = new VoiceChannelStatusUpdateEventArgs(this.ServiceProvider) { - Guild = guild, - Channel = channel, - Status = status + Guild = guild, Channel = channel, Status = status }; await this._voiceChannelStatusUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Guild +#region Guild /// /// Handles the guild create event. @@ -1035,20 +1044,16 @@ internal async Task OnVoiceChannelStatusUpdateAsync(ulong guildId, ulong channel internal async Task OnGuildCreateEventAsync(DiscordGuild guild, JArray rawMembers, IEnumerable presences) { if (presences != null) - { foreach (var xp in presences) { xp.Discord = this; xp.GuildId = guild.Id; xp.Activity = new(xp.RawActivity); if (xp.RawActivities != null) - { xp.InternalActivities = xp.RawActivities .Select(x => new DiscordActivity(x)).ToArray(); - } this.PresencesInternal[xp.InternalUser.Id] = xp; } - } var exists = this.GuildsInternal.TryGetValue(guild.Id, out var foundGuild); @@ -1095,11 +1100,13 @@ internal async Task OnGuildCreateEventAsync(DiscordGuild guild, JArray rawMember xc.GuildId = guild.Id; xc.Initialize(this); } + foreach (var xt in guild.ThreadsInternal.Values) { xt.GuildId = guild.Id; xt.Discord = this; } + foreach (var xe in guild.EmojisInternal.Values) xe.Discord = this; foreach (var xs in guild.StickersInternal.Values) @@ -1111,11 +1118,13 @@ internal async Task OnGuildCreateEventAsync(DiscordGuild guild, JArray rawMember xsi.Discord = this; xsi.GuildId = guild.Id; } + foreach (var xr in guild.RolesInternal.Values) { xr.Discord = this; xr.GuildId = guild.Id; } + foreach (var xse in guild.ScheduledEventsInternal.Values) { xse.Discord = this; @@ -1129,9 +1138,15 @@ internal async Task OnGuildCreateEventAsync(DiscordGuild guild, JArray rawMember Volatile.Write(ref this._guildDownloadCompleted, dcompl); if (exists) - await this._guildAvailable.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild }).ConfigureAwait(false); + await this._guildAvailable.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild + }).ConfigureAwait(false); else - await this._guildCreated.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild }).ConfigureAwait(false); + await this._guildCreated.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild + }).ConfigureAwait(false); if (dcompl && !old) await this._guildDownloadCompletedEv.InvokeAsync(this, new(this.Guilds, this.ServiceProvider)).ConfigureAwait(false); @@ -1239,11 +1254,13 @@ internal async Task OnGuildUpdateEventAsync(DiscordGuild guild, JArray rawMember xc.GuildId = guild.Id; xc.Initialize(this); } + foreach (var xc in guild.ThreadsInternal.Values) { xc.GuildId = guild.Id; xc.Discord = this; } + foreach (var xe in guild.EmojisInternal.Values) xe.Discord = this; foreach (var xs in guild.StickersInternal.Values) @@ -1255,11 +1272,13 @@ internal async Task OnGuildUpdateEventAsync(DiscordGuild guild, JArray rawMember xr.Discord = this; xr.GuildId = guild.Id; } + foreach (var xsi in guild.StageInstancesInternal.Values) { xsi.Discord = this; xsi.GuildId = guild.Id; } + foreach (var xse in guild.ScheduledEventsInternal.Values) { xse.Discord = this; @@ -1268,7 +1287,10 @@ internal async Task OnGuildUpdateEventAsync(DiscordGuild guild, JArray rawMember xse.Creator.Discord = this; } - await this._guildUpdated.InvokeAsync(this, new(this.ServiceProvider) { GuildBefore = oldGuild, GuildAfter = guild }).ConfigureAwait(false); + await this._guildUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + GuildBefore = oldGuild, GuildAfter = guild + }).ConfigureAwait(false); } /// @@ -1284,14 +1306,20 @@ internal async Task OnGuildDeleteEventAsync(DiscordGuild guild) gld.IsUnavailable = true; - await this._guildUnavailable.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild, Unavailable = true }).ConfigureAwait(false); + await this._guildUnavailable.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild, Unavailable = true + }).ConfigureAwait(false); } else { if (!this.GuildsInternal.TryRemove(guild.Id, out var gld)) return; - await this._guildDeleted.InvokeAsync(this, new(this.ServiceProvider) { Guild = gld }).ConfigureAwait(false); + await this._guildDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = gld + }).ConfigureAwait(false); } } @@ -1304,7 +1332,7 @@ internal async Task OnGuildAuditLogEntryCreateEventAsync(DiscordGuild guild, JOb { try { - var auditLogAction = DiscordJson.ToDiscordObject(auditLogCreateEntry); + /*var auditLogAction = DiscordJson.ToDiscordObject(auditLogCreateEntry); List workaroundAuditLogEntryList = new() { new() @@ -1314,11 +1342,14 @@ internal async Task OnGuildAuditLogEntryCreateEventAsync(DiscordGuild guild, JOb auditLogAction } } - }; + };*/ - var dataList = await guild.ProcessAuditLog(workaroundAuditLogEntryList).ConfigureAwait(false); + //var dataList = await guild.ProcessAuditLog(workaroundAuditLogEntryList).ConfigureAwait(false); - await this._guildAuditLogEntryCreated.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild, AuditLogEntry = dataList[0] }).ConfigureAwait(false); + await this._guildAuditLogEntryCreated.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild, AuditLogEntry = null + }).ConfigureAwait(false); } catch (Exception) { } @@ -1333,7 +1364,12 @@ internal async Task OnGuildAuditLogEntryCreateEventAsync(DiscordGuild guild, JOb /// The presences. internal async Task OnGuildSyncEventAsync(DiscordGuild guild, bool isLarge, JArray rawMembers, IEnumerable presences) { - presences = presences.Select(xp => { xp.Discord = this; xp.Activity = new(xp.RawActivity); return xp; }); + presences = presences.Select(xp => + { + xp.Discord = this; + xp.Activity = new(xp.RawActivity); + return xp; + }); foreach (var xp in presences) this.PresencesInternal[xp.InternalUser.Id] = xp; @@ -1342,7 +1378,10 @@ internal async Task OnGuildSyncEventAsync(DiscordGuild guild, bool isLarge, JArr this.UpdateCachedGuild(guild, rawMembers); - await this._guildAvailable.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild }).ConfigureAwait(false); + await this._guildAvailable.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild + }).ConfigureAwait(false); } /// @@ -1363,9 +1402,7 @@ internal async Task OnGuildEmojisUpdateEventAsync(DiscordGuild guild, IEnumerabl var ea = new GuildEmojisUpdateEventArgs(this.ServiceProvider) { - Guild = guild, - EmojisAfter = guild.Emojis, - EmojisBefore = new ReadOnlyConcurrentDictionary(oldEmojis) + Guild = guild, EmojisAfter = guild.Emojis, EmojisBefore = new ReadOnlyConcurrentDictionary(oldEmojis) }; await this._guildEmojisUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -1388,6 +1425,7 @@ internal async Task OnStickersUpdatedAsync(IEnumerable newSticke nst.User.Discord = this; this.UserCache.AddOrUpdate(nst.User.Id, nst.User, (old, @new) => @new); } + nst.Discord = this; guild.StickersInternal[nst.Id] = nst; @@ -1395,9 +1433,7 @@ internal async Task OnStickersUpdatedAsync(IEnumerable newSticke var sea = new GuildStickersUpdateEventArgs(this.ServiceProvider) { - Guild = guild, - StickersBefore = oldStickers, - StickersAfter = guild.Stickers + Guild = guild, StickersBefore = oldStickers, StickersAfter = guild.Stickers }; await this._guildStickersUpdated.InvokeAsync(this, sea).ConfigureAwait(false); @@ -1459,7 +1495,7 @@ internal async Task OnAutomodActionExecuted(DiscordGuild guild, JObject rawPaylo var channelId = rawPayload.TryGetValue("channel_id", out var value) ? (ulong?)value : null; var messageId = rawPayload.TryGetValue("message_id", out var value1) ? (ulong?)value1 : null; var alertMessageId = rawPayload.TryGetValue("alert_system_message_id", out var value2) ? (ulong?)value2 : null; - var content = rawPayload.TryGetValue("content", out var value3) ?(string?)value3 : null; + var content = rawPayload.TryGetValue("content", out var value3) ? (string?)value3 : null; var matchedKeyword = rawPayload.TryGetValue("matched_keyword", out var value4) ? (string?)value4 : null; var matchedContent = rawPayload.TryGetValue("matched_content", out var value5) ? (string?)value5 : null; @@ -1481,9 +1517,9 @@ internal async Task OnAutomodActionExecuted(DiscordGuild guild, JObject rawPaylo await this._automodActionExecuted.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Guild Ban +#region Guild Ban /// /// Handles the guild ban add event. @@ -1492,7 +1528,10 @@ internal async Task OnAutomodActionExecuted(DiscordGuild guild, JObject rawPaylo /// The guild. internal async Task OnGuildBanAddEventAsync(TransportUser user, DiscordGuild guild) { - var usr = new DiscordUser(user) { Discord = this }; + var usr = new DiscordUser(user) + { + Discord = this + }; usr = this.UserCache.AddOrUpdate(user.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1503,11 +1542,13 @@ internal async Task OnGuildBanAddEventAsync(TransportUser user, DiscordGuild gui }); if (!guild.Members.TryGetValue(user.Id, out var mbr)) - mbr = new(usr) { Discord = this, GuildId = guild.Id }; + mbr = new(usr) + { + Discord = this, GuildId = guild.Id + }; var ea = new GuildBanAddEventArgs(this.ServiceProvider) { - Guild = guild, - Member = mbr + Guild = guild, Member = mbr }; await this._guildBanAdded.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -1519,7 +1560,10 @@ internal async Task OnGuildBanAddEventAsync(TransportUser user, DiscordGuild gui /// The guild. internal async Task OnGuildBanRemoveEventAsync(TransportUser user, DiscordGuild guild) { - var usr = new DiscordUser(user) { Discord = this }; + var usr = new DiscordUser(user) + { + Discord = this + }; usr = this.UserCache.AddOrUpdate(user.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1530,18 +1574,20 @@ internal async Task OnGuildBanRemoveEventAsync(TransportUser user, DiscordGuild }); if (!guild.Members.TryGetValue(user.Id, out var mbr)) - mbr = new(usr) { Discord = this, GuildId = guild.Id }; + mbr = new(usr) + { + Discord = this, GuildId = guild.Id + }; var ea = new GuildBanRemoveEventArgs(this.ServiceProvider) { - Guild = guild, - Member = mbr + Guild = guild, Member = mbr }; await this._guildBanRemoved.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Guild Scheduled Event +#region Guild Scheduled Event /// /// Handles the scheduled event create event. @@ -1568,7 +1614,10 @@ internal async Task OnGuildScheduledEventCreateEventAsync(DiscordScheduledEvent }); } - await this._guildScheduledEventCreated.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = scheduledEvent.Guild }).ConfigureAwait(false); + await this._guildScheduledEventCreated.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = scheduledEvent.Guild + }).ConfigureAwait(false); } /// @@ -1583,9 +1632,7 @@ internal async Task OnGuildScheduledEventUpdateEventAsync(DiscordScheduledEvent DiscordScheduledEvent oldEvent; if (!guild.ScheduledEventsInternal.ContainsKey(scheduledEvent.Id)) - { oldEvent = null; - } else { var ev = guild.ScheduledEventsInternal[scheduledEvent.Id]; @@ -1608,8 +1655,8 @@ internal async Task OnGuildScheduledEventUpdateEventAsync(DiscordScheduledEvent UserCount = ev.UserCount, CoverImageHash = ev.CoverImageHash }; - } + if (scheduledEvent.Creator != null) { scheduledEvent.Creator.Discord = this; @@ -1627,18 +1674,27 @@ internal async Task OnGuildScheduledEventUpdateEventAsync(DiscordScheduledEvent if (scheduledEvent.Status == ScheduledEventStatus.Completed) { guild.ScheduledEventsInternal.TryRemove(scheduledEvent.Id, out var deletedEvent); - await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = guild, Reason = ScheduledEventStatus.Completed }).ConfigureAwait(false); + await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = guild, Reason = ScheduledEventStatus.Completed + }).ConfigureAwait(false); } else if (scheduledEvent.Status == ScheduledEventStatus.Canceled) { guild.ScheduledEventsInternal.TryRemove(scheduledEvent.Id, out var deletedEvent); scheduledEvent.Status = ScheduledEventStatus.Canceled; - await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = guild, Reason = ScheduledEventStatus.Canceled }).ConfigureAwait(false); + await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = guild, Reason = ScheduledEventStatus.Canceled + }).ConfigureAwait(false); } else { this.UpdateScheduledEvent(scheduledEvent, guild); - await this._guildScheduledEventUpdated.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEventBefore = oldEvent, ScheduledEventAfter = scheduledEvent, Guild = guild }).ConfigureAwait(false); + await this._guildScheduledEventUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEventBefore = oldEvent, ScheduledEventAfter = scheduledEvent, Guild = guild + }).ConfigureAwait(false); } } @@ -1668,7 +1724,10 @@ internal async Task OnGuildScheduledEventDeleteEventAsync(DiscordScheduledEvent }); } - await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = scheduledEvent.Guild, Reason = scheduledEvent.Status }).ConfigureAwait(false); + await this._guildScheduledEventDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = scheduledEvent.Guild, Reason = scheduledEvent.Status + }).ConfigureAwait(false); guild.ScheduledEventsInternal.TryRemove(scheduledEvent.Id, out var deletedEvent); } @@ -1682,10 +1741,7 @@ internal async Task OnGuildScheduledEventUserAddedEventAsync(ulong guildSchedule { var scheduledEvent = this.InternalGetCachedScheduledEvent(guildScheduledEventId) ?? this.UpdateScheduledEvent(new() { - Id = guildScheduledEventId, - GuildId = guild.Id, - Discord = this, - UserCount = 0 + Id = guildScheduledEventId, GuildId = guild.Id, Discord = this, UserCount = 0 }, guild); scheduledEvent.UserCount++; @@ -1697,7 +1753,10 @@ internal async Task OnGuildScheduledEventUserAddedEventAsync(ulong guildSchedule var member = guild.Members.TryGetValue(userId, out var mem) ? mem : guild.GetMemberAsync(userId).Result; member.Discord = this; - await this._guildScheduledEventUserAdded.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = guild, User = user, Member = member }).ConfigureAwait(false); + await this._guildScheduledEventUserAdded.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = guild, User = user, Member = member + }).ConfigureAwait(false); } /// @@ -1710,10 +1769,7 @@ internal async Task OnGuildScheduledEventUserRemovedEventAsync(ulong guildSchedu { var scheduledEvent = this.InternalGetCachedScheduledEvent(guildScheduledEventId) ?? this.UpdateScheduledEvent(new() { - Id = guildScheduledEventId, - GuildId = guild.Id, - Discord = this, - UserCount = 0 + Id = guildScheduledEventId, GuildId = guild.Id, Discord = this, UserCount = 0 }, guild); scheduledEvent.UserCount = scheduledEvent.UserCount == 0 ? 0 : scheduledEvent.UserCount - 1; @@ -1725,12 +1781,15 @@ internal async Task OnGuildScheduledEventUserRemovedEventAsync(ulong guildSchedu var member = guild.Members.TryGetValue(userId, out var mem) ? mem : guild.GetMemberAsync(userId).Result; member.Discord = this; - await this._guildScheduledEventUserRemoved.InvokeAsync(this, new(this.ServiceProvider) { ScheduledEvent = scheduledEvent, Guild = guild, User = user, Member = member }).ConfigureAwait(false); + await this._guildScheduledEventUserRemoved.InvokeAsync(this, new(this.ServiceProvider) + { + ScheduledEvent = scheduledEvent, Guild = guild, User = user, Member = member + }).ConfigureAwait(false); } - #endregion +#endregion - #region Guild Integration +#region Guild Integration /// /// Handles the guild integration create event. @@ -1741,7 +1800,10 @@ internal async Task OnGuildIntegrationCreateEventAsync(DiscordGuild guild, Disco { integration.Discord = this; - await this._guildIntegrationCreated.InvokeAsync(this, new(this.ServiceProvider) { Integration = integration, Guild = guild }).ConfigureAwait(false); + await this._guildIntegrationCreated.InvokeAsync(this, new(this.ServiceProvider) + { + Integration = integration, Guild = guild + }).ConfigureAwait(false); } /// @@ -1753,7 +1815,10 @@ internal async Task OnGuildIntegrationUpdateEventAsync(DiscordGuild guild, Disco { integration.Discord = this; - await this._guildIntegrationUpdated.InvokeAsync(this, new(this.ServiceProvider) { Integration = integration, Guild = guild }).ConfigureAwait(false); + await this._guildIntegrationUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + Integration = integration, Guild = guild + }).ConfigureAwait(false); } /// @@ -1776,11 +1841,14 @@ internal async Task OnGuildIntegrationsUpdateEventAsync(DiscordGuild guild) /// The integration id. /// The optional application id. internal async Task OnGuildIntegrationDeleteEventAsync(DiscordGuild guild, ulong integrationId, ulong? applicationId) - => await this._guildIntegrationDeleted.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild, IntegrationId = integrationId, ApplicationId = applicationId }).ConfigureAwait(false); + => await this._guildIntegrationDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild, IntegrationId = integrationId, ApplicationId = applicationId + }).ConfigureAwait(false); - #endregion +#endregion - #region Guild Member +#region Guild Member /// /// Handles the guild member add event. @@ -1789,7 +1857,10 @@ internal async Task OnGuildIntegrationDeleteEventAsync(DiscordGuild guild, ulong /// The guild. internal async Task OnGuildMemberAddEventAsync(TransportMember member, DiscordGuild guild) { - var usr = new DiscordUser(member.User) { Discord = this }; + var usr = new DiscordUser(member.User) + { + Discord = this + }; usr = this.UserCache.AddOrUpdate(member.User.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1807,8 +1878,7 @@ internal async Task OnGuildMemberAddEventAsync(TransportMember member, DiscordGu var mbr = new DiscordMember(member) { - Discord = this, - GuildId = guild.Id + Discord = this, GuildId = guild.Id }; guild.MembersInternal[mbr.Id] = mbr; @@ -1816,8 +1886,7 @@ internal async Task OnGuildMemberAddEventAsync(TransportMember member, DiscordGu var ea = new GuildMemberAddEventArgs(this.ServiceProvider) { - Guild = guild, - Member = mbr + Guild = guild, Member = mbr }; await this._guildMemberAdded.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -1832,15 +1901,17 @@ internal async Task OnGuildMemberRemoveEventAsync(TransportUser user, DiscordGui var usr = new DiscordUser(user); if (!guild.MembersInternal.TryRemove(user.Id, out var mbr)) - mbr = new(usr) { Discord = this, GuildId = guild.Id }; + mbr = new(usr) + { + Discord = this, GuildId = guild.Id + }; guild.MemberCount--; _ = this.UserCache.AddOrUpdate(user.Id, usr, (old, @new) => @new); var ea = new GuildMemberRemoveEventArgs(this.ServiceProvider) { - Guild = guild, - Member = mbr + Guild = guild, Member = mbr }; await this._guildMemberRemoved.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -1855,7 +1926,10 @@ internal async Task OnGuildMemberRemoveEventAsync(TransportUser user, DiscordGui /// Whether the member is pending. internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, DiscordGuild guild, IEnumerable roles, string nick, bool? pending) { - var usr = new DiscordUser(member.User) { Discord = this }; + var usr = new DiscordUser(member.User) + { + Discord = this + }; usr = this.UserCache.AddOrUpdate(usr.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1872,7 +1946,10 @@ internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, Discor }); if (!guild.Members.TryGetValue(member.User.Id, out var mbr)) - mbr = new(usr) { Discord = this, GuildId = guild.Id }; + mbr = new(usr) + { + Discord = this, GuildId = guild.Id + }; var old = mbr; var gAvOld = old.GuildAvatarHash; @@ -1931,7 +2008,6 @@ internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, Discor { Guild = guild, Member = mbr, - NicknameAfter = mbr.Nickname, RolesAfter = new ReadOnlyCollection(new List(mbr.Roles)), PendingAfter = mbr.IsPending, @@ -1939,7 +2015,6 @@ internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, Discor AvatarHashAfter = mbr.AvatarHash, GuildAvatarHashAfter = mbr.GuildAvatarHash, UnusualDmActivityAfter = mbr.UnusualDmActivityUntil, - NicknameBefore = nickOld, RolesBefore = rolesOld, PendingBefore = pendingOld, @@ -1951,7 +2026,7 @@ internal async Task OnGuildMemberUpdateEventAsync(TransportMember member, Discor await this._guildMemberUpdated.InvokeAsync(this, eargs).ConfigureAwait(false); } - /// + /*/// /// Handles timeout events. /// /// Internally used as uid for the timer data. @@ -2055,7 +2130,7 @@ private async void TimeoutTimer(object state) this.Logger.LogTrace("Removing timeout event."); await timer.DisposeAsync().ConfigureAwait(false); this._tempTimers.Remove(tid); - } + }*/ /// /// Handles the guild members chunk event. @@ -2075,10 +2150,16 @@ internal async Task OnGuildMembersChunkEventAsync(JObject dat) foreach (var member in members) { - var mbr = new DiscordMember(member) { Discord = this, GuildId = guild.Id }; + var mbr = new DiscordMember(member) + { + Discord = this, GuildId = guild.Id + }; if (!this.UserCache.ContainsKey(mbr.Id)) - this.UserCache[mbr.Id] = new(member.User) { Discord = this }; + this.UserCache[mbr.Id] = new(member.User) + { + Discord = this + }; guild.MembersInternal[mbr.Id] = mbr; @@ -2093,7 +2174,7 @@ internal async Task OnGuildMembersChunkEventAsync(JObject dat) Members = new ReadOnlySet(mbrs), ChunkIndex = chunkIndex, ChunkCount = chunkCount, - Nonce = nonce, + Nonce = nonce }; if (dat["presences"] != null) @@ -2107,10 +2188,8 @@ internal async Task OnGuildMembersChunkEventAsync(JObject dat) presence.Activity = new(presence.RawActivity); if (presence.RawActivities != null) - { presence.InternalActivities = presence.RawActivities .Select(x => new DiscordActivity(x)).ToArray(); - } pres.Add(presence); } @@ -2127,9 +2206,9 @@ internal async Task OnGuildMembersChunkEventAsync(JObject dat) await this._guildMembersChunked.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Guild Role +#region Guild Role /// /// Handles the guild role create event. @@ -2145,8 +2224,7 @@ internal async Task OnGuildRoleCreateEventAsync(DiscordRole role, DiscordGuild g var ea = new GuildRoleCreateEventArgs(this.ServiceProvider) { - Guild = guild, - Role = role + Guild = guild, Role = role }; await this._guildRoleCreated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -2190,9 +2268,7 @@ internal async Task OnGuildRoleUpdateEventAsync(DiscordRole role, DiscordGuild g var ea = new GuildRoleUpdateEventArgs(this.ServiceProvider) { - Guild = guild, - RoleAfter = newRole, - RoleBefore = oldRole + Guild = guild, RoleAfter = newRole, RoleBefore = oldRole }; await this._guildRoleUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -2209,15 +2285,14 @@ internal async Task OnGuildRoleDeleteEventAsync(ulong roleId, DiscordGuild guild var ea = new GuildRoleDeleteEventArgs(this.ServiceProvider) { - Guild = guild, - Role = role + Guild = guild, Role = role }; await this._guildRoleDeleted.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Invite +#region Invite /// /// Handles the invite create event. @@ -2242,9 +2317,7 @@ internal async Task OnInviteCreateEventAsync(ulong channelId, ulong guildId, Dis var ea = new InviteCreateEventArgs(this.ServiceProvider) { - Channel = channel, - Guild = guild, - Invite = invite + Channel = channel, Guild = guild, Invite = invite }; await this._inviteCreated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -2270,16 +2343,14 @@ internal async Task OnInviteDeleteEventAsync(ulong channelId, ulong guildId, JTo var ea = new InviteDeleteEventArgs(this.ServiceProvider) { - Channel = channel, - Guild = guild, - Invite = invite + Channel = channel, Guild = guild, Invite = invite }; await this._inviteDeleted.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Message +#region Message /// /// Handles the message acknowledge event. @@ -2289,16 +2360,15 @@ internal async Task OnInviteDeleteEventAsync(ulong channelId, ulong guildId, JTo internal async Task OnMessageAckEventAsync(DiscordChannel chn, ulong messageId) { if (this.MessageCache == null || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == chn.Id, out var msg)) - { msg = new() { - Id = messageId, - ChannelId = chn.Id, - Discord = this, + Id = messageId, ChannelId = chn.Id, Discord = this }; - } - await this._messageAcknowledged.InvokeAsync(this, new(this.ServiceProvider) { Message = msg }).ConfigureAwait(false); + await this._messageAcknowledged.InvokeAsync(this, new(this.ServiceProvider) + { + Message = msg + }).ConfigureAwait(false); } /// @@ -2330,11 +2400,7 @@ internal async Task OnMessageCreateEventAsync(DiscordMessage message, TransportU var ea = new MessageCreateEventArgs(this.ServiceProvider) { - Message = message, - - MentionedUsers = new ReadOnlyCollection(message.MentionedUsersInternal), - MentionedRoles = message.MentionedRolesInternal != null ? new ReadOnlyCollection(message.MentionedRolesInternal) : null, - MentionedChannels = message.MentionedChannelsInternal != null ? new ReadOnlyCollection(message.MentionedChannelsInternal) : null + Message = message, MentionedUsers = new ReadOnlyCollection(message.MentionedUsersInternal), MentionedRoles = message.MentionedRolesInternal != null ? new ReadOnlyCollection(message.MentionedRolesInternal) : null, MentionedChannels = message.MentionedChannelsInternal != null ? new ReadOnlyCollection(message.MentionedChannelsInternal) : null }; await this._messageCreated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -2356,8 +2422,8 @@ internal async Task OnMessageUpdateEventAsync(DiscordMessage message, TransportU DiscordMessage oldmsg = null; if (this.Configuration.MessageCacheSize == 0 - || this.MessageCache == null - || !this.MessageCache.TryGet(xm => xm.Id == eventMessage.Id && xm.ChannelId == eventMessage.ChannelId, out message)) + || this.MessageCache == null + || !this.MessageCache.TryGet(xm => xm.Id == eventMessage.Id && xm.ChannelId == eventMessage.ChannelId, out message)) { message = eventMessage; this.PopulateMessageReactionsAndCache(message, author, member); @@ -2409,27 +2475,20 @@ internal async Task OnMessageDeleteEventAsync(ulong messageId, ulong channelId, var guild = this.InternalGetCachedGuild(guildId); if (channel == null - || this.Configuration.MessageCacheSize == 0 - || this.MessageCache == null - || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) - { + || this.Configuration.MessageCacheSize == 0 + || this.MessageCache == null + || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) msg = new() { - - Id = messageId, - ChannelId = channelId, - Discord = this, + Id = messageId, ChannelId = channelId, Discord = this }; - } if (this.Configuration.MessageCacheSize > 0) this.MessageCache?.Remove(xm => xm.Id == msg.Id && xm.ChannelId == channelId); var ea = new MessageDeleteEventArgs(this.ServiceProvider) { - Channel = channel, - Message = msg, - Guild = guild + Channel = channel, Message = msg, Guild = guild }; await this._messageDeleted.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -2448,17 +2507,13 @@ internal async Task OnMessageBulkDeleteEventAsync(ulong[] messageIds, ulong chan foreach (var messageId in messageIds) { if (channel == null - || this.Configuration.MessageCacheSize == 0 - || this.MessageCache == null - || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) - { + || this.Configuration.MessageCacheSize == 0 + || this.MessageCache == null + || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) msg = new() { - Id = messageId, - ChannelId = channelId, - Discord = this, + Id = messageId, ChannelId = channelId, Discord = this }; - } if (this.Configuration.MessageCacheSize > 0) this.MessageCache?.Remove(xm => xm.Id == msg.Id && xm.ChannelId == channelId); msgs.Add(msg); @@ -2468,16 +2523,14 @@ internal async Task OnMessageBulkDeleteEventAsync(ulong[] messageIds, ulong chan var ea = new MessageBulkDeleteEventArgs(this.ServiceProvider) { - Channel = channel, - Messages = new ReadOnlyCollection(msgs), - Guild = guild + Channel = channel, Messages = new ReadOnlyCollection(msgs), Guild = guild }; await this._messagesBulkDeleted.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Message Reaction +#region Message Reaction /// /// Handles the message reaction add event. @@ -2495,7 +2548,10 @@ internal async Task OnMessageReactionAddAsync(ulong userId, ulong messageId, ulo var guild = this.InternalGetCachedGuild(guildId); emoji.Discord = this; - var usr = this.UpdateUser(new() { Id = userId, Discord = this }, guildId, guild, mbr); + var usr = this.UpdateUser(new() + { + Id = userId, Discord = this + }, guildId, guild, mbr); DiscordMessage? msg = null; @@ -2504,22 +2560,15 @@ internal async Task OnMessageReactionAddAsync(ulong userId, ulong messageId, ulo msg ??= new() { - Id = messageId, - ChannelId = channelId, - Discord = this, - ReactionsInternal = new() + Id = messageId, ChannelId = channelId, Discord = this, ReactionsInternal = new() }; var react = msg.ReactionsInternal.FirstOrDefault(xr => xr.Emoji == emoji); if (react == null) - { msg.ReactionsInternal.Add(react = new() { - Count = 1, - Emoji = emoji, - IsMe = this.CurrentUser.Id == userId + Count = 1, Emoji = emoji, IsMe = this.CurrentUser.Id == userId }); - } else { react.Count++; @@ -2552,21 +2601,24 @@ internal async Task OnMessageReactionRemoveAsync(ulong userId, ulong messageId, { var channel = this.InternalGetCachedChannel(channelId) ?? this.InternalGetCachedThread(channelId) ?? new DiscordChannel() { - Type = ChannelType.Unknown, - Id = channelId, - GuildId = guildId, - Discord = this + Type = ChannelType.Unknown, Id = channelId, GuildId = guildId, Discord = this }; emoji.Discord = this; if (!this.UserCache.TryGetValue(userId, out var usr)) - usr = new() { Id = userId, Discord = this }; + usr = new() + { + Id = userId, Discord = this + }; if (channel?.Guild != null) usr = channel.Guild.Members.TryGetValue(userId, out var member) ? member - : new(usr) { Discord = this, GuildId = channel.GuildId.Value }; + : new(usr) + { + Discord = this, GuildId = channel.GuildId.Value + }; DiscordMessage? msg = null; @@ -2575,9 +2627,7 @@ internal async Task OnMessageReactionRemoveAsync(ulong userId, ulong messageId, msg ??= new() { - Id = messageId, - ChannelId = channelId, - Discord = this + Id = messageId, ChannelId = channelId, Discord = this }; var react = msg.ReactionsInternal?.FirstOrDefault(xr => xr.Emoji == emoji); @@ -2616,24 +2666,17 @@ internal async Task OnMessageReactionRemoveAllAsync(ulong messageId, ulong chann { var channel = this.InternalGetCachedChannel(channelId) ?? this.InternalGetCachedThread(channelId) ?? new DiscordChannel() { - Type = ChannelType.Unknown, - Id = channelId, - GuildId = guildId, - Discord = this + Type = ChannelType.Unknown, Id = channelId, GuildId = guildId, Discord = this }; if (channel == null - || this.Configuration.MessageCacheSize == 0 - || this.MessageCache == null - || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) - { + || this.Configuration.MessageCacheSize == 0 + || this.MessageCache == null + || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) msg = new() { - Id = messageId, - ChannelId = channelId, - Discord = this + Id = messageId, ChannelId = channelId, Discord = this }; - } msg.ReactionsInternal?.Clear(); @@ -2661,17 +2704,13 @@ internal async Task OnMessageReactionRemoveEmojiAsync(ulong messageId, ulong cha var channel = this.InternalGetCachedChannel(channelId) ?? this.InternalGetCachedThread(channelId); if (channel == null - || this.Configuration.MessageCacheSize == 0 - || this.MessageCache == null - || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) - { + || this.Configuration.MessageCacheSize == 0 + || this.MessageCache == null + || !this.MessageCache.TryGet(xm => xm.Id == messageId && xm.ChannelId == channelId, out var msg)) msg = new() { - Id = messageId, - ChannelId = channelId, - Discord = this + Id = messageId, ChannelId = channelId, Discord = this }; - } if (!guild.EmojisInternal.TryGetValue(partialEmoji.Id, out var emoji)) { @@ -2683,18 +2722,15 @@ internal async Task OnMessageReactionRemoveEmojiAsync(ulong messageId, ulong cha var ea = new MessageReactionRemoveEmojiEventArgs(this.ServiceProvider) { - Channel = channel, - Guild = guild, - Message = msg, - Emoji = emoji + Channel = channel, Guild = guild, Message = msg, Emoji = emoji }; await this._messageReactionRemovedEmoji.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Stage Instance +#region Stage Instance /// /// Handles the stage instance create event. @@ -2707,7 +2743,10 @@ internal async Task OnStageInstanceCreateEventAsync(DiscordStageInstance stage) var guild = this.InternalGetCachedGuild(stage.GuildId); guild.StageInstancesInternal[stage.Id] = stage; - await this._stageInstanceCreated.InvokeAsync(this, new(this.ServiceProvider) { StageInstance = stage, Guild = stage.Guild }).ConfigureAwait(false); + await this._stageInstanceCreated.InvokeAsync(this, new(this.ServiceProvider) + { + StageInstance = stage, Guild = stage.Guild + }).ConfigureAwait(false); } /// @@ -2720,7 +2759,10 @@ internal async Task OnStageInstanceUpdateEventAsync(DiscordStageInstance stage) var guild = this.InternalGetCachedGuild(stage.GuildId); guild.StageInstancesInternal[stage.Id] = stage; - await this._stageInstanceUpdated.InvokeAsync(this, new(this.ServiceProvider) { StageInstance = stage, Guild = stage.Guild }).ConfigureAwait(false); + await this._stageInstanceUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + StageInstance = stage, Guild = stage.Guild + }).ConfigureAwait(false); } /// @@ -2733,12 +2775,15 @@ internal async Task OnStageInstanceDeleteEventAsync(DiscordStageInstance stage) var guild = this.InternalGetCachedGuild(stage.GuildId); guild.StageInstancesInternal[stage.Id] = stage; - await this._stageInstanceDeleted.InvokeAsync(this, new(this.ServiceProvider) { StageInstance = stage, Guild = stage.Guild }).ConfigureAwait(false); + await this._stageInstanceDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + StageInstance = stage, Guild = stage.Guild + }).ConfigureAwait(false); } - #endregion +#endregion - #region Thread +#region Thread /// /// Handles the thread create event. @@ -2749,7 +2794,10 @@ internal async Task OnThreadCreateEventAsync(DiscordThreadChannel thread) thread.Discord = this; this.InternalGetCachedGuild(thread.GuildId).ThreadsInternal.AddOrUpdate(thread.Id, thread, (oldThread, newThread) => newThread); - await this._threadCreated.InvokeAsync(this, new(this.ServiceProvider) { Thread = thread, Guild = thread.Guild, Parent = thread.Parent }).ConfigureAwait(false); + await this._threadCreated.InvokeAsync(this, new(this.ServiceProvider) + { + Thread = thread, Guild = thread.Guild, Parent = thread.Parent + }).ConfigureAwait(false); } /// @@ -2821,19 +2869,14 @@ internal async Task OnThreadUpdateEventAsync(DiscordThreadChannel thread) updateEvent = new(this.ServiceProvider) { - ThreadAfter = thread, - ThreadBefore = threadOld, - Guild = thread.Guild, - Parent = thread.Parent + ThreadAfter = thread, ThreadBefore = threadOld, Guild = thread.Guild, Parent = thread.Parent }; } else { updateEvent = new(this.ServiceProvider) { - ThreadAfter = thread, - Guild = thread.Guild, - Parent = thread.Parent + ThreadAfter = thread, Guild = thread.Guild, Parent = thread.Parent }; guild.ThreadsInternal[thread.Id] = thread; } @@ -2856,7 +2899,10 @@ internal async Task OnThreadDeleteEventAsync(DiscordThreadChannel thread) if (gld.ThreadsInternal.TryRemove(thread.Id, out var cachedThread)) thread = cachedThread; - await this._threadDeleted.InvokeAsync(this, new(this.ServiceProvider) { Thread = thread, Guild = thread.Guild, Parent = thread.Parent, Type = thread.Type }).ConfigureAwait(false); + await this._threadDeleted.InvokeAsync(this, new(this.ServiceProvider) + { + Thread = thread, Guild = thread.Guild, Parent = thread.Parent, Type = thread.Type + }).ConfigureAwait(false); } /// @@ -2872,12 +2918,13 @@ internal async Task OnThreadListSyncEventAsync(DiscordGuild guild, IReadOnlyList var channels = channelIds.Select(x => guild.GetChannel(x.Value)); //getting channel objects foreach (var chan in channels) - { chan.Discord = this; - } _ = threads.Select(x => x.Discord = this); - await this._threadListSynced.InvokeAsync(this, new(this.ServiceProvider) { Guild = guild, Channels = channels.ToList().AsReadOnly(), Threads = threads, Members = members.ToList().AsReadOnly() }).ConfigureAwait(false); + await this._threadListSynced.InvokeAsync(this, new(this.ServiceProvider) + { + Guild = guild, Channels = channels.ToList().AsReadOnly(), Threads = threads, Members = members.ToList().AsReadOnly() + }).ConfigureAwait(false); } /// @@ -2897,8 +2944,10 @@ internal async Task OnThreadMemberUpdateEventAsync(DiscordThreadChannelMember me thread.CurrentMember = member; thread.Guild.ThreadsInternal.AddOrUpdate(member.Id, thread, (oldThread, newThread) => newThread); - - await this._threadMemberUpdated.InvokeAsync(this, new(this.ServiceProvider) { ThreadMember = member, Thread = thread }).ConfigureAwait(false); + await this._threadMemberUpdated.InvokeAsync(this, new(this.ServiceProvider) + { + ThreadMember = member, Thread = thread + }).ConfigureAwait(false); } /// @@ -2924,7 +2973,6 @@ internal async Task OnThreadMembersUpdateEventAsync(DiscordGuild guild, ulong th List removedMemberIds = new(); if (membersAdded != null) - { foreach (var xj in membersAdded) { var xtm = xj.ToDiscordObject(); @@ -2936,16 +2984,16 @@ internal async Task OnThreadMembersUpdateEventAsync(DiscordGuild guild, ulong th if (xtm.Id == this.CurrentUser.Id) thread.CurrentMember = xtm; } - } var removedMembers = new List(); if (membersRemoved != null) - { foreach (var removedId in membersRemoved) - { - removedMembers.Add(guild.MembersInternal.TryGetValue((ulong)removedId, out var member) ? member : new() { Id = (ulong)removedId, GuildId = guild.Id, Discord = this }); - } - } + removedMembers.Add(guild.MembersInternal.TryGetValue((ulong)removedId, out var member) + ? member + : new() + { + Id = (ulong)removedId, GuildId = guild.Id, Discord = this + }); if (removedMemberIds.Contains(this.CurrentUser.Id)) //indicates the bot was removed from the thread thread.CurrentMember = null; @@ -2964,9 +3012,10 @@ internal async Task OnThreadMembersUpdateEventAsync(DiscordGuild guild, ulong th await this._threadMembersUpdated.InvokeAsync(this, threadMembersUpdateArg).ConfigureAwait(false); } - #endregion +#endregion + +#region Activities - #region Activities /// /// Dispatches the event. /// @@ -3026,16 +3075,15 @@ internal async Task OnEmbeddedActivityUpdateAsync(JObject trActivity, DiscordGui } }*/ - #endregion +#endregion - #region User/Presence Update +#region User/Presence Update /// /// Handles the presence update event. /// /// The raw presence. /// The raw user. - internal async Task OnPresenceUpdateEventAsync(JObject rawPresence, JObject rawUser) { var uid = (ulong)rawUser["id"]!; @@ -3048,7 +3096,8 @@ internal async Task OnPresenceUpdateEventAsync(JObject rawPresence, JObject rawU } else { - presence = DiscordJson.DeserializeObject(rawPresence.ToString(), this); ; + presence = DiscordJson.DeserializeObject(rawPresence.ToString(), this); + ; presence.Discord = this; presence.Activity = new(presence.RawActivity); this.PresencesInternal[presence.InternalUser.Id] = presence; @@ -3056,9 +3105,7 @@ internal async Task OnPresenceUpdateEventAsync(JObject rawPresence, JObject rawU // reuse arrays / avoid linq (this is a hot zone) if (presence.Activities == null || rawPresence["activities"] == null) - { presence.InternalActivities = Array.Empty(); - } else { if (presence.InternalActivities.Length != presence.RawActivities.Length) @@ -3093,10 +3140,12 @@ internal async Task OnPresenceUpdateEventAsync(JObject rawPresence, JObject rawU /// Handles the user settings update event. /// /// The transport user. - internal async Task OnUserSettingsUpdateEventAsync(TransportUser user) { - var usr = new DiscordUser(user) { Discord = this }; + var usr = new DiscordUser(user) + { + Discord = this + }; var ea = new UserSettingsUpdateEventArgs(this.ServiceProvider) { @@ -3109,7 +3158,6 @@ internal async Task OnUserSettingsUpdateEventAsync(TransportUser user) /// Handles the user update event. /// /// The transport user. - internal async Task OnUserUpdateEventAsync(TransportUser user) { var usrOld = new DiscordUser @@ -3136,21 +3184,19 @@ internal async Task OnUserUpdateEventAsync(TransportUser user) var ea = new UserUpdateEventArgs(this.ServiceProvider) { - UserAfter = this.CurrentUser, - UserBefore = usrOld + UserAfter = this.CurrentUser, UserBefore = usrOld }; await this._userUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Voice +#region Voice /// /// Handles the voice state update event. /// /// The raw voice state update object. - internal async Task OnVoiceStateUpdateEventAsync(JObject raw) { var gid = (ulong)raw["guild_id"]; @@ -3163,9 +3209,7 @@ internal async Task OnVoiceStateUpdateEventAsync(JObject raw) gld.VoiceStatesInternal.TryRemove(uid, out var vstateOld); if (vstateNew.Channel != null) - { gld.VoiceStatesInternal[vstateNew.UserId] = vstateNew; - } if (gld.MembersInternal.TryGetValue(uid, out var mbr)) { @@ -3175,7 +3219,10 @@ internal async Task OnVoiceStateUpdateEventAsync(JObject raw) else { var transportMbr = vstateNew.TransportMember; - this.UpdateUser(new(transportMbr.User) { Discord = this }, gid, gld, transportMbr); + this.UpdateUser(new(transportMbr.User) + { + Discord = this + }, gid, gld, transportMbr); } var ea = new VoiceStateUpdateEventArgs(this.ServiceProvider) @@ -3184,7 +3231,6 @@ internal async Task OnVoiceStateUpdateEventAsync(JObject raw) Channel = vstateNew.Channel, User = vstateNew.User, SessionId = vstateNew.SessionId, - Before = vstateOld, After = vstateNew }; @@ -3197,28 +3243,24 @@ internal async Task OnVoiceStateUpdateEventAsync(JObject raw) /// The new endpoint. /// The new token. /// The guild. - internal async Task OnVoiceServerUpdateEventAsync(string endpoint, string token, DiscordGuild guild) { var ea = new VoiceServerUpdateEventArgs(this.ServiceProvider) { - Endpoint = endpoint, - VoiceToken = token, - Guild = guild + Endpoint = endpoint, VoiceToken = token, Guild = guild }; await this._voiceServerUpdated.InvokeAsync(this, ea).ConfigureAwait(false); } - #endregion +#endregion - #region Commands +#region Commands /// /// Handles the application command create event. /// /// The application command. /// The optional guild id. - internal async Task OnApplicationCommandCreateAsync(DiscordApplicationCommand cmd, ulong? guildId) { cmd.Discord = this; @@ -3226,18 +3268,14 @@ internal async Task OnApplicationCommandCreateAsync(DiscordApplicationCommand cm var guild = this.InternalGetCachedGuild(guildId); if (guild == null && guildId.HasValue) - { guild = new() { - Id = guildId.Value, - Discord = this + Id = guildId.Value, Discord = this }; - } var ea = new ApplicationCommandEventArgs(this.ServiceProvider) { - Guild = guild, - Command = cmd + Guild = guild, Command = cmd }; await this._applicationCommandCreated.InvokeAsync(this, ea).ConfigureAwait(false); @@ -3248,7 +3286,6 @@ internal async Task OnApplicationCommandCreateAsync(DiscordApplicationCommand cm /// /// The application command. /// The optional guild id. - internal async Task OnApplicationCommandUpdateAsync(DiscordApplicationCommand cmd, ulong? guildId) { cmd.Discord = this; @@ -3256,18 +3293,14 @@ internal async Task OnApplicationCommandUpdateAsync(DiscordApplicationCommand cm var guild = this.InternalGetCachedGuild(guildId); if (guild == null && guildId.HasValue) - { guild = new() { - Id = guildId.Value, - Discord = this + Id = guildId.Value, Discord = this }; - } var ea = new ApplicationCommandEventArgs(this.ServiceProvider) { - Guild = guild, - Command = cmd + Guild = guild, Command = cmd }; await this._applicationCommandUpdated.InvokeAsync(this, ea).ConfigureAwait(false); @@ -3278,7 +3311,6 @@ internal async Task OnApplicationCommandUpdateAsync(DiscordApplicationCommand cm /// /// The application command. /// The optional guild id. - internal async Task OnApplicationCommandDeleteAsync(DiscordApplicationCommand cmd, ulong? guildId) { cmd.Discord = this; @@ -3286,18 +3318,14 @@ internal async Task OnApplicationCommandDeleteAsync(DiscordApplicationCommand cm var guild = this.InternalGetCachedGuild(guildId); if (guild == null && guildId.HasValue) - { guild = new() { - Id = guildId.Value, - Discord = this + Id = guildId.Value, Discord = this }; - } var ea = new ApplicationCommandEventArgs(this.ServiceProvider) { - Guild = guild, - Command = cmd + Guild = guild, Command = cmd }; await this._applicationCommandDeleted.InvokeAsync(this, ea).ConfigureAwait(false); @@ -3315,15 +3343,11 @@ internal async Task OnGuildApplicationCommandCountsUpdateAsync(int chatInputComm { var guild = this.InternalGetCachedGuild(guildId) ?? new DiscordGuild { - Id = guildId, - Discord = this + Id = guildId, Discord = this }; var ea = new GuildApplicationCommandCountEventArgs(this.ServiceProvider) { - SlashCommands = chatInputCommandCount, - UserContextMenuCommands = userContextMenuCommandCount, - MessageContextMenuCommands = messageContextMenuCount, - Guild = guild + SlashCommands = chatInputCommandCount, UserContextMenuCommands = userContextMenuCommandCount, MessageContextMenuCommands = messageContextMenuCount, Guild = guild }; await this._guildApplicationCommandCountUpdated.InvokeAsync(this, ea).ConfigureAwait(false); @@ -3354,28 +3378,22 @@ internal async Task OnApplicationCommandPermissionsUpdateAsync(IEnumerable /// Handles the interaction create event. @@ -3394,7 +3412,11 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr //this.Logger.LogDebug("Interaction from {guild} on shard {shard}", guildId.HasValue ? guildId.Value : "dm", this.ShardId); //this.Logger.LogDebug("Interaction: {interaction}", rawInteraction); } - var usr = new DiscordUser(user) { Discord = this }; + + var usr = new DiscordUser(user) + { + Discord = this + }; interaction.ChannelId = channelId; interaction.GuildId = guildId; @@ -3403,13 +3425,14 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr if (member != null) { - usr = new DiscordMember(member) { GuildId = guildId.Value, Discord = this }; + usr = new DiscordMember(member) + { + GuildId = guildId.Value, Discord = this + }; this.UpdateUser(usr, guildId, interaction.Guild, member); } else - { this.UserCache.AddOrUpdate(usr.Id, usr, (old, @new) => @new); - } usr.Locale = interaction.Locale; interaction.User = usr; @@ -3418,16 +3441,13 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr if (resolved != null) { if (resolved.Users != null) - { foreach (var c in resolved.Users) { c.Value.Discord = this; this.UserCache.AddOrUpdate(c.Value.Id, c.Value, (old, @new) => @new); } - } if (resolved.Members != null) - { foreach (var c in resolved.Members) { c.Value.Discord = this; @@ -3436,10 +3456,8 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr c.Value.User.Discord = this; this.UserCache.AddOrUpdate(c.Value.User.Id, c.Value.User, (old, @new) => @new); } - } if (resolved.Channels != null) - { foreach (var c in resolved.Channels) { c.Value.Discord = this; @@ -3456,10 +3474,8 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr catch (Exception) { } } } - } if (resolved.Roles != null) - { foreach (var c in resolved.Roles) { c.Value.Discord = this; @@ -3467,11 +3483,8 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr if (guildId.HasValue) c.Value.GuildId = guildId.Value; } - } - if (resolved.Messages != null) - { foreach (var m in resolved.Messages) { m.Value.Discord = this; @@ -3479,8 +3492,6 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr if (guildId.HasValue) m.Value.GuildId = guildId.Value; } - } - if (resolved.Attachments != null) foreach (var a in resolved.Attachments) @@ -3494,10 +3505,10 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr interaction.Message.Discord = this; interaction.Message.ChannelId = interaction.ChannelId; } + var cea = new ComponentInteractionCreateEventArgs(this.ServiceProvider) { - Message = interaction.Message, - Interaction = interaction + Message = interaction.Message, Interaction = interaction }; await this._componentInteractionCreated.InvokeAsync(this, cea).ConfigureAwait(false); @@ -3517,10 +3528,7 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr var ea = new ContextMenuInteractionCreateEventArgs(this.ServiceProvider) { - Interaction = interaction, - TargetUser = targetMember ?? targetUser, - TargetMessage = targetMessage, - Type = interaction.Data.Type + Interaction = interaction, TargetUser = targetMember ?? targetUser, TargetMessage = targetMessage, Type = interaction.Data.Type }; await this._contextMenuInteractionCreated.InvokeAsync(this, ea).ConfigureAwait(false); } @@ -3536,9 +3544,9 @@ internal async Task OnInteractionCreateAsync(ulong? guildId, ulong channelId, Tr } } - #endregion +#endregion - #region Misc +#region Misc /// /// Handles the entitlement create event. @@ -3579,65 +3587,63 @@ internal async Task OnEntitlementDeleteAsync(DiscordEntitlement entitlement) await this._entitlementDeleted.InvokeAsync(this, ea).ConfigureAwait(false); } - /// - /// Handles the typing start event. - /// - /// The user id. - /// The channel id. - /// The channel. - /// The optional guild id. - /// The time when the user started typing. - /// The transport member. - internal async Task OnTypingStartEventAsync(ulong userId, ulong channelId, DiscordChannel channel, ulong? guildId, DateTimeOffset started, TransportMember mbr) - { - if (channel == null) - { - channel = new() - { - Discord = this, - Id = channelId, - GuildId = guildId ?? default, - }; - } - - var guild = this.InternalGetCachedGuild(guildId); - var usr = this.UpdateUser(new() { Id = userId, Discord = this }, guildId, guild, mbr); - var ea = new TypingStartEventArgs(this.ServiceProvider) + /// + /// Handles the typing start event. + /// + /// The user id. + /// The channel id. + /// The channel. + /// The optional guild id. + /// The time when the user started typing. + /// The transport member. + internal async Task OnTypingStartEventAsync(ulong userId, ulong channelId, DiscordChannel channel, ulong? guildId, DateTimeOffset started, TransportMember mbr) + { + if (channel == null) + channel = new() { - Channel = channel, - User = usr, - Guild = guild, - StartedAt = started + Discord = this, Id = channelId, GuildId = guildId ?? default }; - await this._typingStarted.InvokeAsync(this, ea).ConfigureAwait(false); - } - /// - /// Handles the webhooks update. - /// - /// The channel. - /// The guild. - internal async Task OnWebhooksUpdateAsync(DiscordChannel channel, DiscordGuild guild) + var guild = this.InternalGetCachedGuild(guildId); + var usr = this.UpdateUser(new() { - var ea = new WebhooksUpdateEventArgs(this.ServiceProvider) - { - Channel = channel, - Guild = guild - }; - await this._webhooksUpdated.InvokeAsync(this, ea).ConfigureAwait(false); - } + Id = userId, Discord = this + }, guildId, guild, mbr); + var ea = new TypingStartEventArgs(this.ServiceProvider) + { + Channel = channel, User = usr, Guild = guild, StartedAt = started + }; + await this._typingStarted.InvokeAsync(this, ea).ConfigureAwait(false); + } - /// - /// Handles all unknown events. - /// - /// The payload. - internal async Task OnUnknownEventAsync(GatewayPayload payload) + /// + /// Handles the webhooks update. + /// + /// The channel. + /// The guild. + internal async Task OnWebhooksUpdateAsync(DiscordChannel channel, DiscordGuild guild) + { + var ea = new WebhooksUpdateEventArgs(this.ServiceProvider) { - var ea = new UnknownEventArgs(this.ServiceProvider) { EventName = payload.EventName, Json = (payload.Data as JObject)?.ToString() }; - await this._unknownEvent.InvokeAsync(this, ea).ConfigureAwait(false); - } + Channel = channel, Guild = guild + }; + await this._webhooksUpdated.InvokeAsync(this, ea).ConfigureAwait(false); + } + + /// + /// Handles all unknown events. + /// + /// The payload. + internal async Task OnUnknownEventAsync(GatewayPayload payload) + { + var ea = new UnknownEventArgs(this.ServiceProvider) + { + EventName = payload.EventName, Json = (payload.Data as JObject)?.ToString() + }; + await this._unknownEvent.InvokeAsync(this, ea).ConfigureAwait(false); + } - #endregion +#endregion - #endregion +#endregion } diff --git a/DisCatSharp/Clients/DiscordClient.EventHandlers.cs b/DisCatSharp/Clients/DiscordClient.EventHandlers.cs index bd9af03bd1..555f88b634 100644 --- a/DisCatSharp/Clients/DiscordClient.EventHandlers.cs +++ b/DisCatSharp/Clients/DiscordClient.EventHandlers.cs @@ -1,4 +1,3 @@ - #nullable enable using System; using System.Collections.Generic; @@ -55,7 +54,7 @@ public void RegisterEventHandler(Type type) { var anon = ActivatorUtilities.CreateInstance(this.Configuration.ServiceProvider, type); - this._typeToAnonymousHandlers[type] = this._typeToAnonymousHandlers.TryGetValue(type, out var anonObjs) ? anonObjs : (anonObjs = new()); + this._typeToAnonymousHandlers[type] = this._typeToAnonymousHandlers.TryGetValue(type, out var anonObjs) ? anonObjs : anonObjs = new(); anonObjs.Add(anon); @@ -154,7 +153,6 @@ private static IEnumerable GetEventHandlersFromAssembly(Assembly assembly) /// The event handler object. /// The type. /// Whether it considereded static methods. - private void UnregisterEventHandlerImpl(object? handler, Type type, bool wasRegisteredWithStatic = true) { if (!this._registrationToDelegate.TryGetValue((handler, type, wasRegisteredWithStatic), out var delegateLists) || delegateLists.Count == 0) @@ -179,19 +177,19 @@ private void RegisterEventHandlerImpl(object? handler, Type type, bool registerS var delegates = ( from method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) let attribute = method.GetCustomAttribute() - where attribute is not null && ((registerStatic && method.IsStatic) || handler is not null) + where attribute is not null && (registerStatic && method.IsStatic || handler is not null) let eventName = attribute.EventName ?? method.Name let eventInfo = this.GetType().GetEvent(eventName) - ?? throw new ArgumentException($"Tried to register handler to non-existent event \"{eventName}\"") + ?? throw new ArgumentException($"Tried to register handler to non-existent event \"{eventName}\"") let eventHandlerType = eventInfo.EventHandlerType let dlgt = (method.IsStatic - ? Delegate.CreateDelegate(eventHandlerType, method, false) - : Delegate.CreateDelegate(eventHandlerType, handler, method, false)) - ?? throw new ArgumentException($"Method \"{method}\" does not adhere to event specification \"{eventHandlerType}\"") + ? Delegate.CreateDelegate(eventHandlerType, method, false) + : Delegate.CreateDelegate(eventHandlerType, handler, method, false)) + ?? throw new ArgumentException($"Method \"{method}\" does not adhere to event specification \"{eventHandlerType}\"") select (eventInfo, dlgt) - ).ToArray(); + ).ToArray(); - this._registrationToDelegate[(handler, type, registerStatic)] = this._registrationToDelegate.TryGetValue((handler, type, registerStatic), out var delList) ? delList : (delList = new()); + this._registrationToDelegate[(handler, type, registerStatic)] = this._registrationToDelegate.TryGetValue((handler, type, registerStatic), out var delList) ? delList : delList = new(); delList.Add(delegates); diff --git a/DisCatSharp/Clients/DiscordClient.Events.cs b/DisCatSharp/Clients/DiscordClient.Events.cs index e21217d054..4d1e609550 100644 --- a/DisCatSharp/Clients/DiscordClient.Events.cs +++ b/DisCatSharp/Clients/DiscordClient.Events.cs @@ -9,7 +9,7 @@ namespace DisCatSharp; /// -/// Represents a discord client. +/// A Discord API wrapper. /// public sealed partial class DiscordClient { @@ -18,7 +18,7 @@ public sealed partial class DiscordClient /// internal static TimeSpan EventExecutionLimit { get; } = TimeSpan.FromSeconds(1); - #region WebSocket +#region WebSocket /// /// Fired whenever a WebSocket error occurs within the client. @@ -28,6 +28,7 @@ public event AsyncEventHandler SocketErrore add => this._socketErrored.Register(value); remove => this._socketErrored.Unregister(value); } + private AsyncEvent _socketErrored; /// @@ -38,6 +39,7 @@ public event AsyncEventHandler SocketOpened add => this._socketOpened.Register(value); remove => this._socketOpened.Unregister(value); } + private AsyncEvent _socketOpened; /// @@ -48,6 +50,7 @@ public event AsyncEventHandler SocketClosed add => this._socketClosed.Register(value); remove => this._socketClosed.Unregister(value); } + private AsyncEvent _socketClosed; /// @@ -58,6 +61,7 @@ public event AsyncEventHandler Ready add => this._ready.Register(value); remove => this._ready.Unregister(value); } + private AsyncEvent _ready; /// @@ -68,6 +72,7 @@ public event AsyncEventHandler Resumed add => this._resumed.Register(value); remove => this._resumed.Unregister(value); } + private AsyncEvent _resumed; /// @@ -78,11 +83,12 @@ public event AsyncEventHandler Heartbeated add => this._heartbeated.Register(value); remove => this._heartbeated.Unregister(value); } + private AsyncEvent _heartbeated; - #endregion +#endregion - #region Channel +#region Channel /// /// Fired when a new channel is created. @@ -93,6 +99,7 @@ public event AsyncEventHandler ChannelCre add => this._channelCreated.Register(value); remove => this._channelCreated.Unregister(value); } + private AsyncEvent _channelCreated; /// @@ -104,6 +111,7 @@ public event AsyncEventHandler ChannelUpd add => this._channelUpdated.Register(value); remove => this._channelUpdated.Unregister(value); } + private AsyncEvent _channelUpdated; /// @@ -115,6 +123,7 @@ public event AsyncEventHandler ChannelDel add => this._channelDeleted.Register(value); remove => this._channelDeleted.Unregister(value); } + private AsyncEvent _channelDeleted; /// @@ -126,6 +135,7 @@ public event AsyncEventHandler DmChanne add => this._dmChannelDeleted.Register(value); remove => this._dmChannelDeleted.Unregister(value); } + private AsyncEvent _dmChannelDeleted; /// @@ -137,6 +147,7 @@ public event AsyncEventHandler Channe add => this._channelPinsUpdated.Register(value); remove => this._channelPinsUpdated.Unregister(value); } + private AsyncEvent _channelPinsUpdated; /// @@ -148,11 +159,12 @@ public event AsyncEventHandler add => this._voiceChannelStatusUpdated.Register(value); remove => this._voiceChannelStatusUpdated.Unregister(value); } + private AsyncEvent _voiceChannelStatusUpdated; - #endregion +#endregion - #region Guild +#region Guild /// /// Fired when the user joins a new guild. @@ -164,6 +176,7 @@ public event AsyncEventHandler GuildCreated add => this._guildCreated.Register(value); remove => this._guildCreated.Unregister(value); } + private AsyncEvent _guildCreated; /// @@ -175,6 +188,7 @@ public event AsyncEventHandler GuildAvailab add => this._guildAvailable.Register(value); remove => this._guildAvailable.Unregister(value); } + private AsyncEvent _guildAvailable; /// @@ -186,6 +200,7 @@ public event AsyncEventHandler GuildUpdated add => this._guildUpdated.Register(value); remove => this._guildUpdated.Unregister(value); } + private AsyncEvent _guildUpdated; /// @@ -197,6 +212,7 @@ public event AsyncEventHandler GuildDeleted add => this._guildDeleted.Register(value); remove => this._guildDeleted.Unregister(value); } + private AsyncEvent _guildDeleted; /// @@ -207,6 +223,7 @@ public event AsyncEventHandler GuildUnavail add => this._guildUnavailable.Register(value); remove => this._guildUnavailable.Unregister(value); } + private AsyncEvent _guildUnavailable; /// @@ -217,6 +234,7 @@ public event AsyncEventHandler G add => this._guildDownloadCompletedEv.Register(value); remove => this._guildDownloadCompletedEv.Unregister(value); } + private AsyncEvent _guildDownloadCompletedEv; /// @@ -228,6 +246,7 @@ public event AsyncEventHandler GuildE add => this._guildEmojisUpdated.Register(value); remove => this._guildEmojisUpdated.Unregister(value); } + private AsyncEvent _guildEmojisUpdated; /// @@ -239,6 +258,7 @@ public event AsyncEventHandler Guil add => this._guildStickersUpdated.Register(value); remove => this._guildStickersUpdated.Unregister(value); } + private AsyncEvent _guildStickersUpdated; /// @@ -249,6 +269,7 @@ public event AsyncEventHandler add => this._guildIntegrationsUpdated.Register(value); remove => this._guildIntegrationsUpdated.Unregister(value); } + private AsyncEvent _guildIntegrationsUpdated; /// @@ -260,12 +281,13 @@ public event AsyncEventHandler add => this._guildAuditLogEntryCreated.Register(value); remove => this._guildAuditLogEntryCreated.Unregister(value); } + private AsyncEvent _guildAuditLogEntryCreated; +#endregion - #endregion +#region Automod - #region Automod /// /// Fired when an auto mod rule gets created. /// @@ -274,6 +296,7 @@ public event AsyncEventHandler Automo add => this._automodRuleCreated.Register(value); remove => this._automodRuleCreated.Unregister(value); } + private AsyncEvent _automodRuleCreated; /// @@ -284,6 +307,7 @@ public event AsyncEventHandler Automo add => this._automodRuleUpdated.Register(value); remove => this._automodRuleUpdated.Unregister(value); } + private AsyncEvent _automodRuleUpdated; /// @@ -294,6 +318,7 @@ public event AsyncEventHandler Automo add => this._automodRuleDeleted.Register(value); remove => this._automodRuleDeleted.Unregister(value); } + private AsyncEvent _automodRuleDeleted; /// @@ -304,11 +329,12 @@ public event AsyncEventHandler Au add => this._automodActionExecuted.Register(value); remove => this._automodActionExecuted.Unregister(value); } + private AsyncEvent _automodActionExecuted; - #endregion +#endregion - #region Guild Ban +#region Guild Ban /// /// Fired when a guild ban gets added @@ -319,6 +345,7 @@ public event AsyncEventHandler GuildBanAdde add => this._guildBanAdded.Register(value); remove => this._guildBanAdded.Unregister(value); } + private AsyncEvent _guildBanAdded; /// @@ -330,11 +357,12 @@ public event AsyncEventHandler GuildBanR add => this._guildBanRemoved.Register(value); remove => this._guildBanRemoved.Unregister(value); } + private AsyncEvent _guildBanRemoved; - #endregion +#endregion - #region Guild Timeout +#region Guild Timeout /// /// Fired when a guild member timeout gets added. @@ -345,6 +373,7 @@ public event AsyncEventHandler Gu add => this._guildMemberTimeoutAdded.Register(value); remove => this._guildMemberTimeoutAdded.Unregister(value); } + private AsyncEvent _guildMemberTimeoutAdded; /// @@ -356,8 +385,8 @@ public event AsyncEventHandler add => this._guildMemberTimeoutChanged.Register(value); remove => this._guildMemberTimeoutChanged.Unregister(value); } - private AsyncEvent _guildMemberTimeoutChanged; + private AsyncEvent _guildMemberTimeoutChanged; /// /// Fired when a guild member timeout gets removed. @@ -368,11 +397,12 @@ public event AsyncEventHandler add => this._guildMemberTimeoutRemoved.Register(value); remove => this._guildMemberTimeoutRemoved.Unregister(value); } + private AsyncEvent _guildMemberTimeoutRemoved; - #endregion +#endregion - #region Guild Scheduled Event +#region Guild Scheduled Event /// /// Fired when a scheduled Event is created. @@ -383,6 +413,7 @@ public event AsyncEventHandler this._guildScheduledEventCreated.Register(value); remove => this._guildScheduledEventCreated.Unregister(value); } + private AsyncEvent _guildScheduledEventCreated; /// @@ -394,6 +425,7 @@ public event AsyncEventHandler this._guildScheduledEventUpdated.Register(value); remove => this._guildScheduledEventUpdated.Unregister(value); } + private AsyncEvent _guildScheduledEventUpdated; /// @@ -405,6 +437,7 @@ public event AsyncEventHandler this._guildScheduledEventDeleted.Register(value); remove => this._guildScheduledEventDeleted.Unregister(value); } + private AsyncEvent _guildScheduledEventDeleted; /// @@ -416,6 +449,7 @@ public event AsyncEventHandler this._guildScheduledEventUserAdded.Register(value); remove => this._guildScheduledEventUserAdded.Unregister(value); } + private AsyncEvent _guildScheduledEventUserAdded; /// @@ -427,11 +461,12 @@ public event AsyncEventHandler this._guildScheduledEventUserRemoved.Register(value); remove => this._guildScheduledEventUserRemoved.Unregister(value); } + private AsyncEvent _guildScheduledEventUserRemoved; - #endregion +#endregion - #region Guild Integration +#region Guild Integration /// /// Fired when a guild integration is created. @@ -442,6 +477,7 @@ public event AsyncEventHandler G add => this._guildIntegrationCreated.Register(value); remove => this._guildIntegrationCreated.Unregister(value); } + private AsyncEvent _guildIntegrationCreated; /// @@ -453,6 +489,7 @@ public event AsyncEventHandler G add => this._guildIntegrationUpdated.Register(value); remove => this._guildIntegrationUpdated.Unregister(value); } + private AsyncEvent _guildIntegrationUpdated; /// @@ -464,11 +501,12 @@ public event AsyncEventHandler G add => this._guildIntegrationDeleted.Register(value); remove => this._guildIntegrationDeleted.Unregister(value); } + private AsyncEvent _guildIntegrationDeleted; - #endregion +#endregion - #region Guild Member +#region Guild Member /// /// Fired when a new user joins a guild. @@ -479,6 +517,7 @@ public event AsyncEventHandler GuildMemb add => this._guildMemberAdded.Register(value); remove => this._guildMemberAdded.Unregister(value); } + private AsyncEvent _guildMemberAdded; /// @@ -490,6 +529,7 @@ public event AsyncEventHandler GuildM add => this._guildMemberRemoved.Register(value); remove => this._guildMemberRemoved.Unregister(value); } + private AsyncEvent _guildMemberRemoved; /// @@ -501,6 +541,7 @@ public event AsyncEventHandler GuildM add => this._guildMemberUpdated.Register(value); remove => this._guildMemberUpdated.Unregister(value); } + private AsyncEvent _guildMemberUpdated; /// @@ -511,11 +552,12 @@ public event AsyncEventHandler GuildM add => this._guildMembersChunked.Register(value); remove => this._guildMembersChunked.Unregister(value); } + private AsyncEvent _guildMembersChunked; - #endregion +#endregion - #region Guild Role +#region Guild Role /// /// Fired when a guild role is created. @@ -526,6 +568,7 @@ public event AsyncEventHandler GuildRol add => this._guildRoleCreated.Register(value); remove => this._guildRoleCreated.Unregister(value); } + private AsyncEvent _guildRoleCreated; /// @@ -537,6 +580,7 @@ public event AsyncEventHandler GuildRol add => this._guildRoleUpdated.Register(value); remove => this._guildRoleUpdated.Unregister(value); } + private AsyncEvent _guildRoleUpdated; /// @@ -548,11 +592,12 @@ public event AsyncEventHandler GuildRol add => this._guildRoleDeleted.Register(value); remove => this._guildRoleDeleted.Unregister(value); } + private AsyncEvent _guildRoleDeleted; - #endregion +#endregion - #region Invite +#region Invite /// /// Fired when an invite is created. @@ -563,6 +608,7 @@ public event AsyncEventHandler InviteCreat add => this._inviteCreated.Register(value); remove => this._inviteCreated.Unregister(value); } + private AsyncEvent _inviteCreated; /// @@ -574,11 +620,12 @@ public event AsyncEventHandler InviteDelet add => this._inviteDeleted.Register(value); remove => this._inviteDeleted.Unregister(value); } + private AsyncEvent _inviteDeleted; - #endregion +#endregion - #region Message +#region Message /// /// Fired when a message is created. @@ -589,6 +636,7 @@ public event AsyncEventHandler MessageCre add => this._messageCreated.Register(value); remove => this._messageCreated.Unregister(value); } + private AsyncEvent _messageCreated; /// @@ -600,6 +648,7 @@ public event AsyncEventHandler Messa add => this._messageAcknowledged.Register(value); remove => this._messageAcknowledged.Unregister(value); } + private AsyncEvent _messageAcknowledged; /// @@ -611,6 +660,7 @@ public event AsyncEventHandler MessageUpd add => this._messageUpdated.Register(value); remove => this._messageUpdated.Unregister(value); } + private AsyncEvent _messageUpdated; /// @@ -622,6 +672,7 @@ public event AsyncEventHandler MessageDel add => this._messageDeleted.Register(value); remove => this._messageDeleted.Unregister(value); } + private AsyncEvent _messageDeleted; /// @@ -633,11 +684,12 @@ public event AsyncEventHandler Messag add => this._messagesBulkDeleted.Register(value); remove => this._messagesBulkDeleted.Unregister(value); } + private AsyncEvent _messagesBulkDeleted; - #endregion +#endregion - #region Message Reaction +#region Message Reaction /// /// Fired when a reaction gets added to a message. @@ -648,6 +700,7 @@ public event AsyncEventHandler Messa add => this._messageReactionAdded.Register(value); remove => this._messageReactionAdded.Unregister(value); } + private AsyncEvent _messageReactionAdded; /// @@ -659,6 +712,7 @@ public event AsyncEventHandler Me add => this._messageReactionRemoved.Register(value); remove => this._messageReactionRemoved.Unregister(value); } + private AsyncEvent _messageReactionRemoved; /// @@ -670,6 +724,7 @@ public event AsyncEventHandler Me add => this._messageReactionsCleared.Register(value); remove => this._messageReactionsCleared.Unregister(value); } + private AsyncEvent _messageReactionsCleared; /// @@ -681,11 +736,12 @@ public event AsyncEventHandler this._messageReactionRemovedEmoji.Register(value); remove => this._messageReactionRemovedEmoji.Unregister(value); } + private AsyncEvent _messageReactionRemovedEmoji; - #endregion +#endregion - #region Activities +#region Activities /// /// Fired when a embedded activity has been updated. @@ -695,11 +751,12 @@ public event AsyncEventHandler E add => this._embeddedActivityUpdated.Register(value); remove => this._embeddedActivityUpdated.Unregister(value); } + private AsyncEvent _embeddedActivityUpdated; - #endregion +#endregion - #region Presence/User Update +#region Presence/User Update /// /// Fired when a presence has been updated. @@ -710,8 +767,8 @@ public event AsyncEventHandler PresenceU add => this._presenceUpdated.Register(value); remove => this._presenceUpdated.Unregister(value); } - private AsyncEvent _presenceUpdated; + private AsyncEvent _presenceUpdated; /// /// Fired when the current user updates their settings. @@ -722,6 +779,7 @@ public event AsyncEventHandler UserS add => this._userSettingsUpdated.Register(value); remove => this._userSettingsUpdated.Unregister(value); } + private AsyncEvent _userSettingsUpdated; /// @@ -736,11 +794,12 @@ public event AsyncEventHandler UserUpdated add => this._userUpdated.Register(value); remove => this._userUpdated.Unregister(value); } + private AsyncEvent _userUpdated; - #endregion +#endregion - #region Stage Instance +#region Stage Instance /// /// Fired when a Stage Instance is created. @@ -751,6 +810,7 @@ public event AsyncEventHandler Stag add => this._stageInstanceCreated.Register(value); remove => this._stageInstanceCreated.Unregister(value); } + private AsyncEvent _stageInstanceCreated; /// @@ -762,6 +822,7 @@ public event AsyncEventHandler Stag add => this._stageInstanceUpdated.Register(value); remove => this._stageInstanceUpdated.Unregister(value); } + private AsyncEvent _stageInstanceUpdated; /// @@ -773,11 +834,12 @@ public event AsyncEventHandler Stag add => this._stageInstanceDeleted.Register(value); remove => this._stageInstanceDeleted.Unregister(value); } + private AsyncEvent _stageInstanceDeleted; - #endregion +#endregion - #region Thread +#region Thread /// /// Fired when a thread is created. @@ -788,6 +850,7 @@ public event AsyncEventHandler ThreadCreat add => this._threadCreated.Register(value); remove => this._threadCreated.Unregister(value); } + private AsyncEvent _threadCreated; /// @@ -799,6 +862,7 @@ public event AsyncEventHandler ThreadUpdat add => this._threadUpdated.Register(value); remove => this._threadUpdated.Unregister(value); } + private AsyncEvent _threadUpdated; /// @@ -810,6 +874,7 @@ public event AsyncEventHandler ThreadDelet add => this._threadDeleted.Register(value); remove => this._threadDeleted.Unregister(value); } + private AsyncEvent _threadDeleted; /// @@ -821,6 +886,7 @@ public event AsyncEventHandler ThreadLis add => this._threadListSynced.Register(value); remove => this._threadListSynced.Unregister(value); } + private AsyncEvent _threadListSynced; /// @@ -832,6 +898,7 @@ public event AsyncEventHandler Threa add => this._threadMemberUpdated.Register(value); remove => this._threadMemberUpdated.Unregister(value); } + private AsyncEvent _threadMemberUpdated; /// @@ -843,11 +910,12 @@ public event AsyncEventHandler Thre add => this._threadMembersUpdated.Register(value); remove => this._threadMembersUpdated.Unregister(value); } + private AsyncEvent _threadMembersUpdated; - #endregion +#endregion - #region Voice +#region Voice /// /// Fired when someone joins/leaves/moves voice channels. @@ -858,6 +926,7 @@ public event AsyncEventHandler VoiceSt add => this._voiceStateUpdated.Register(value); remove => this._voiceStateUpdated.Unregister(value); } + private AsyncEvent _voiceStateUpdated; /// @@ -869,11 +938,12 @@ public event AsyncEventHandler VoiceS add => this._voiceServerUpdated.Register(value); remove => this._voiceServerUpdated.Unregister(value); } + private AsyncEvent _voiceServerUpdated; - #endregion +#endregion - #region Application +#region Application /// /// Fired when a new application command is registered. @@ -883,6 +953,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandCreated.Register(value); remove => this._applicationCommandCreated.Unregister(value); } + private AsyncEvent _applicationCommandCreated; /// @@ -893,6 +964,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandUpdated.Register(value); remove => this._applicationCommandUpdated.Unregister(value); } + private AsyncEvent _applicationCommandUpdated; /// @@ -903,6 +975,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandDeleted.Register(value); remove => this._applicationCommandDeleted.Unregister(value); } + private AsyncEvent _applicationCommandDeleted; /// @@ -913,6 +986,7 @@ public event AsyncEventHandler this._guildApplicationCommandCountUpdated.Register(value); remove => this._guildApplicationCommandCountUpdated.Unregister(value); } + private AsyncEvent _guildApplicationCommandCountUpdated; /// @@ -937,9 +1011,9 @@ public event AsyncEventHandler _applicationCommandPermissionsUpdated; - #endregion +#endregion - #region Misc +#region Misc /// /// Fired when an interaction is invoked. @@ -949,6 +1023,7 @@ public event AsyncEventHandler Intera add => this._interactionCreated.Register(value); remove => this._interactionCreated.Unregister(value); } + private AsyncEvent _interactionCreated; /// @@ -959,6 +1034,7 @@ public event AsyncEventHandler this._componentInteractionCreated.Register(value); remove => this._componentInteractionCreated.Unregister(value); } + private AsyncEvent _componentInteractionCreated; /// @@ -969,6 +1045,7 @@ public event AsyncEventHandler Entitl add => this._entitlementCreated.Register(value); remove => this._entitlementCreated.Unregister(value); } + private AsyncEvent _entitlementCreated; /// @@ -979,6 +1056,7 @@ public event AsyncEventHandler Entitl add => this._entitlementUpdated.Register(value); remove => this._entitlementUpdated.Unregister(value); } + private AsyncEvent _entitlementUpdated; /// @@ -1000,6 +1078,7 @@ public event AsyncEventHandler TypingStarte add => this._typingStarted.Register(value); remove => this._typingStarted.Unregister(value); } + private AsyncEvent _typingStarted; /// @@ -1010,6 +1089,7 @@ public event AsyncEventHandler UnknownEvent add => this._unknownEvent.Register(value); remove => this._unknownEvent.Unregister(value); } + private AsyncEvent _unknownEvent; /// @@ -1020,6 +1100,7 @@ public event AsyncEventHandler WebhooksU add => this._webhooksUpdated.Register(value); remove => this._webhooksUpdated.Unregister(value); } + private AsyncEvent _webhooksUpdated; /// @@ -1030,10 +1111,12 @@ public event AsyncEventHandler ClientErrore add => this._clientErrored.Register(value); remove => this._clientErrored.Unregister(value); } + private AsyncEvent _clientErrored; - #endregion - #region Error Handling +#endregion + +#region Error Handling /// /// Handles event errors. @@ -1053,7 +1136,10 @@ internal void EventErrorHandler(AsyncEvent async } this.Logger.LogError(LoggerEvents.EventHandlerException, ex, "Event handler exception for event {0} thrown from {1} (defined in {2})", asyncEvent.Name, handler.Method, handler.Method.DeclaringType); - this._clientErrored.InvokeAsync(this, new(this.ServiceProvider) { EventName = asyncEvent.Name, Exception = ex }).ConfigureAwait(false).GetAwaiter().GetResult(); + this._clientErrored.InvokeAsync(this, new(this.ServiceProvider) + { + EventName = asyncEvent.Name, Exception = ex + }).ConfigureAwait(false).GetAwaiter().GetResult(); } /// @@ -1064,6 +1150,7 @@ public event AsyncEventHandler RateL add => this.RateLimitHitInternal.Register(value); remove => this.RateLimitHitInternal.Unregister(value); } + internal AsyncEvent RateLimitHitInternal; /// @@ -1074,6 +1161,7 @@ public event AsyncEventHandler Zombied add => this._zombied.Register(value); remove => this._zombied.Unregister(value); } + private AsyncEvent _zombied; /// @@ -1085,6 +1173,7 @@ public event AsyncEventHandler PayloadR add => this._payloadReceived.Register(value); remove => this._payloadReceived.Unregister(value); } + private AsyncEvent _payloadReceived; /// @@ -1098,5 +1187,5 @@ public event AsyncEventHandler PayloadR private void Goof(AsyncEvent asyncEvent, Exception ex, AsyncEventHandler handler, TSender sender, TArgs eventArgs) where TArgs : AsyncEventArgs => this.Logger.LogCritical(LoggerEvents.EventHandlerException, ex, "Exception event handler {0} (defined in {1}) threw an exception", handler.Method, handler.Method.DeclaringType); - #endregion +#endregion } diff --git a/DisCatSharp/Clients/DiscordClient.WebSocket.cs b/DisCatSharp/Clients/DiscordClient.WebSocket.cs index ae5d4ca4b7..20bb1455ea 100644 --- a/DisCatSharp/Clients/DiscordClient.WebSocket.cs +++ b/DisCatSharp/Clients/DiscordClient.WebSocket.cs @@ -20,11 +20,11 @@ namespace DisCatSharp; /// -/// Represents a discord websocket client. +/// A Discord API wrapper. /// public sealed partial class DiscordClient { - #region Private Fields +#region Private Fields private int _heartbeatInterval; private DateTimeOffset _lastHeartbeat; @@ -41,9 +41,9 @@ public sealed partial class DiscordClient private CancellationTokenSource _cancelTokenSource; private CancellationToken _cancelToken; - #endregion +#endregion - #region Connection Semaphore +#region Connection Semaphore /// /// Gets the socket locks. @@ -53,11 +53,11 @@ public sealed partial class DiscordClient /// /// Gets the session lock. /// - private readonly ManualResetEventSlim _sessionLock = new(true); + private readonly ManualResetEventSlim _sessionLock = new(true); - #endregion +#endregion - #region Internal Connection Methods +#region Internal Connection Methods /// /// Reconnects the websocket client. @@ -96,7 +96,6 @@ internal async Task InternalConnectAsync() } if (!this.Presences.ContainsKey(this.CurrentUser.Id)) - { this.PresencesInternal[this.CurrentUser.Id] = new() { Discord = this, @@ -108,7 +107,6 @@ internal async Task InternalConnectAsync() Id = this.CurrentUser.Id } }; - } else { var pr = this.PresencesInternal[this.CurrentUser.Id]; @@ -143,8 +141,6 @@ internal async Task InternalConnectAsync() await this.WebSocketClient.ConnectAsync(gwuri.Build()).ConfigureAwait(false); - - Task SocketOnConnect(IWebSocketClient sender, SocketEventArgs e) => this._socketOpened.InvokeAsync(this, e); @@ -152,9 +148,7 @@ async Task SocketOnMessage(IWebSocketClient sender, SocketMessageEventArgs e) { string msg = null; if (e is SocketTextMessageEventArgs etext) - { msg = etext.Message; - } else if (e is SocketBinaryMessageEventArgs ebin) { using var ms = new MemoryStream(); @@ -197,7 +191,6 @@ async Task SocketOnDisconnect(IWebSocketClient sender, SocketCloseEventArgs e) this.Logger.LogDebug(LoggerEvents.ConnectionClose, "Connection closed ({0}, '{1}')", e.CloseCode, e.CloseMessage); await this._socketClosed.InvokeAsync(this, e).ConfigureAwait(false); - // TODO: We might need to include more 400X codes if (this.Configuration.AutoReconnect && (e.CloseCode < 4001 || e.CloseCode >= 5000)) { @@ -205,22 +198,19 @@ async Task SocketOnDisconnect(IWebSocketClient sender, SocketCloseEventArgs e) if (this._status == null) await this.ConnectAsync().ConfigureAwait(false); - else - if (this._status.IdleSince.HasValue) + else if (this._status.IdleSince.HasValue) await this.ConnectAsync(this._status.ActivityInternal, this._status.Status, Utilities.GetDateTimeOffsetFromMilliseconds(this._status.IdleSince.Value)).ConfigureAwait(false); else await this.ConnectAsync(this._status.ActivityInternal, this._status.Status).ConfigureAwait(false); } else - { this.Logger.LogCritical(LoggerEvents.ConnectionClose, "Connection terminated ({0}, '{1}')", e.CloseCode, e.CloseMessage); - } } } - #endregion +#endregion - #region WebSocket (Events) +#region WebSocket (Events) /// /// Handles the socket message. @@ -354,8 +344,7 @@ internal async Task OnHeartbeatAckAsync() var args = new HeartbeatEventArgs(this.ServiceProvider) { - Ping = this.Ping, - Timestamp = DateTimeOffset.Now + Ping = this.Ping, Timestamp = DateTimeOffset.Now }; await this._heartbeated.InvokeAsync(this, args).ConfigureAwait(false); @@ -380,9 +369,9 @@ internal async Task HeartbeatLoopAsync() catch (OperationCanceledException) { } } - #endregion +#endregion - #region Internal Gateway Methods +#region Internal Gateway Methods /// /// Updates the status. @@ -400,18 +389,14 @@ internal async Task InternalUpdateStatusAsync(DiscordActivity activity, UserStat var status = new StatusUpdate { - Activity = new(act), - IdleSince = sinceUnix, - IsAfk = idleSince != null, - Status = userStatus ?? UserStatus.Online + Activity = new(act), IdleSince = sinceUnix, IsAfk = idleSince != null, Status = userStatus ?? UserStatus.Online }; // Solution to have status persist between sessions this._status = status; var statusUpdate = new GatewayPayload { - OpCode = GatewayOpCode.StatusUpdate, - Data = status + OpCode = GatewayOpCode.StatusUpdate, Data = status }; var statusstr = JsonConvert.SerializeObject(statusUpdate); @@ -419,15 +404,16 @@ internal async Task InternalUpdateStatusAsync(DiscordActivity activity, UserStat await this.WsSendAsync(statusstr).ConfigureAwait(false); if (!this.PresencesInternal.ContainsKey(this.CurrentUser.Id)) - { this.PresencesInternal[this.CurrentUser.Id] = new() { Discord = this, Activity = act, Status = userStatus ?? UserStatus.Online, - InternalUser = new() { Id = this.CurrentUser.Id } + InternalUser = new() + { + Id = this.CurrentUser.Id + } }; - } else { var pr = this.PresencesInternal[this.CurrentUser.Id]; @@ -450,8 +436,7 @@ internal async Task SendHeartbeatAsync(long seq) var args = new ZombiedEventArgs(this.ServiceProvider) { - Failures = Volatile.Read(ref this._skippedHeartbeats), - GuildDownloadCompleted = true + Failures = Volatile.Read(ref this._skippedHeartbeats), GuildDownloadCompleted = true }; await this._zombied.InvokeAsync(this, args).ConfigureAwait(false); @@ -462,8 +447,7 @@ internal async Task SendHeartbeatAsync(long seq) { var args = new ZombiedEventArgs(this.ServiceProvider) { - Failures = Volatile.Read(ref this._skippedHeartbeats), - GuildDownloadCompleted = false + Failures = Volatile.Read(ref this._skippedHeartbeats), GuildDownloadCompleted = false }; await this._zombied.InvokeAsync(this, args).ConfigureAwait(false); @@ -474,8 +458,7 @@ internal async Task SendHeartbeatAsync(long seq) this.Logger.LogTrace(LoggerEvents.Heartbeat, "Sending heartbeat"); var heartbeat = new GatewayPayload { - OpCode = GatewayOpCode.Heartbeat, - Data = seq + OpCode = GatewayOpCode.Heartbeat, Data = seq }; var heartbeatStr = JsonConvert.SerializeObject(heartbeat); await this.WsSendAsync(heartbeatStr).ConfigureAwait(false); @@ -498,8 +481,7 @@ internal async Task SendIdentifyAsync(StatusUpdate status) LargeThreshold = this.Configuration.LargeThreshold, ShardInfo = new() { - ShardId = this.Configuration.ShardId, - ShardCount = this.Configuration.ShardCount + ShardId = this.Configuration.ShardId, ShardCount = this.Configuration.ShardCount }, Presence = status, Intents = this.Configuration.Intents, @@ -507,8 +489,7 @@ internal async Task SendIdentifyAsync(StatusUpdate status) }; var payload = new GatewayPayload { - OpCode = GatewayOpCode.Identify, - Data = identify + OpCode = GatewayOpCode.Identify, Data = identify }; var payloadstr = JsonConvert.SerializeObject(payload); await this.WsSendAsync(payloadstr).ConfigureAwait(false); @@ -523,20 +504,18 @@ internal async Task SendResumeAsync() { var resume = new GatewayResume { - Token = Utilities.GetFormattedToken(this), - SessionId = this._sessionId, - SequenceNumber = Volatile.Read(ref this._lastSequence) + Token = Utilities.GetFormattedToken(this), SessionId = this._sessionId, SequenceNumber = Volatile.Read(ref this._lastSequence) }; var resumePayload = new GatewayPayload { - OpCode = GatewayOpCode.Resume, - Data = resume + OpCode = GatewayOpCode.Resume, Data = resume }; var resumestr = JsonConvert.SerializeObject(resumePayload); this.GatewayUri = new(this._resumeGatewayUrl); this.Logger.LogDebug(LoggerEvents.ConnectionClose, "Request to resume via {gw}", this.GatewayUri.AbsoluteUri); await this.WsSendAsync(resumestr).ConfigureAwait(false); } + /// /// Internals the update gateway async. /// @@ -558,9 +537,9 @@ internal async Task WsSendAsync(string payload) await this.WebSocketClient.SendMessageAsync(payload).ConfigureAwait(false); } - #endregion +#endregion - #region Semaphore Methods +#region Semaphore Methods /// /// Gets the socket lock. @@ -569,5 +548,5 @@ internal async Task WsSendAsync(string payload) private SocketLock GetSocketLock() => s_socketLocks.GetOrAdd(this.CurrentApplication.Id, appId => new(appId, this.GatewayInfo.SessionBucket.MaxConcurrency)); - #endregion +#endregion } diff --git a/DisCatSharp/Clients/DiscordClient.cs b/DisCatSharp/Clients/DiscordClient.cs index 51b7470142..da031fbf96 100644 --- a/DisCatSharp/Clients/DiscordClient.cs +++ b/DisCatSharp/Clients/DiscordClient.cs @@ -30,7 +30,7 @@ namespace DisCatSharp; /// public sealed partial class DiscordClient : BaseDiscordClient { - #region Internal Fields/Properties +#region Internal Fields/Properties internal bool IsShard = false; @@ -47,9 +47,10 @@ public sealed partial class DiscordClient : BaseDiscordClient /// private readonly ManualResetEventSlim _connectionLock = new(true); - #endregion +#endregion + +#region Public Fields/Properties - #region Public Fields/Properties /// /// Gets the gateway protocol version. /// @@ -90,6 +91,7 @@ public DiscordIntents Intents /// or events haven't been fired yet) /// public override IReadOnlyDictionary Guilds { get; } + internal ConcurrentDictionary GuildsInternal = new(); /// @@ -117,9 +119,10 @@ public IReadOnlyDictionary EmbeddedActivities internal Dictionary EmbeddedActivitiesInternal = new(); private Lazy> _embeddedActivitiesLazy; - #endregion - #region Constructor/Internal Setup +#endregion + +#region Constructor/Internal Setup /// /// Initializes a new instance of . @@ -132,8 +135,8 @@ public DiscordClient(DiscordConfiguration config) { var intents = this.Configuration.Intents; this.MessageCache = intents.HasIntent(DiscordIntents.GuildMessages) || intents.HasIntent(DiscordIntents.DirectMessages) - ? new RingBuffer(this.Configuration.MessageCacheSize) - : null; + ? new RingBuffer(this.Configuration.MessageCacheSize) + : null; } this.InternalSetup(); @@ -243,9 +246,9 @@ internal void InternalSetup() this._embeddedActivitiesLazy = new(() => new ReadOnlyDictionary(this.EmbeddedActivitiesInternal)); } - #endregion +#endregion - #region Client Extension Methods +#region Client Extension Methods /// /// Registers an extension with this client. @@ -265,9 +268,9 @@ public void AddExtension(BaseExtension ext) public T GetExtension() where T : BaseExtension => this._extensions.FirstOrDefault(x => x.GetType() == typeof(T)) as T; - #endregion +#endregion - #region Public Connection Methods +#region Public Connection Methods /// /// Connects to the gateway. @@ -283,6 +286,7 @@ public async Task ConnectAsync(DiscordActivity activity = null, UserStatus? stat // Check if connection lock is already set, and set it if it isn't if (!this._connectionLock.Wait(0)) throw new InvalidOperationException("This client is already connected."); + this._connectionLock.Set(); var w = 7500; @@ -313,7 +317,6 @@ public async Task ConnectAsync(DiscordActivity activity = null, UserStatus? stat } while (i-- > 0 || this.Configuration.ReconnectIndefinitely) - { try { await this.InternalConnectAsync().ConfigureAwait(false); @@ -348,7 +351,6 @@ public async Task ConnectAsync(DiscordActivity activity = null, UserStatus? stat if (i > 0) w *= 2; } - } if (!s && cex != null) { @@ -377,7 +379,7 @@ static void FailConnection(ManualResetEventSlim cl) => /// /// Whether to start a new session. public Task ReconnectAsync(bool startNewSession = true) - => this.InternalReconnectAsync(startNewSession, code: startNewSession ? 1000 : 4002); + => this.InternalReconnectAsync(startNewSession, startNewSession ? 1000 : 4002); /// /// Disconnects from the gateway. @@ -389,9 +391,9 @@ public async Task DisconnectAsync() await this.WebSocketClient.DisconnectAsync().ConfigureAwait(false); } - #endregion +#endregion - #region Public REST Methods +#region Public REST Methods /// /// Gets a user. @@ -549,14 +551,14 @@ public async Task DeleteTestEntitlementsAsync(ulong entitlementId) /// /// A list of metadata records or . public async Task> GetRoleConnectionMetadata() - => await this.ApiClient.GetRoleConnectionMetadataRecords(this.CurrentApplication.Id).ConfigureAwait(false); + => await this.ApiClient.GetRoleConnectionMetadataRecords(this.CurrentApplication.Id).ConfigureAwait(false); /// /// Updates the applications role connection metadata. /// /// A list of metadata objects. Max 5. public async Task> UpdateRoleConnectionMetadata(IEnumerable metadata) - => await this.ApiClient.UpdateRoleConnectionMetadataRecords(this.CurrentApplication.Id, metadata).ConfigureAwait(false); + => await this.ApiClient.UpdateRoleConnectionMetadataRecords(this.CurrentApplication.Id, metadata).ConfigureAwait(false); /// /// Removes all global application commands. @@ -655,7 +657,7 @@ public bool TryGetThread(ulong id, out DiscordThreadChannel thread, bool fetch = /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task SendMessageAsync(DiscordChannel channel, string content) - => this.ApiClient.CreateMessageAsync(channel.Id, content, embeds: null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + => this.ApiClient.CreateMessageAsync(channel.Id, content, null, null, null, false, false); /// /// Sends a message with an embed. @@ -668,7 +670,12 @@ public Task SendMessageAsync(DiscordChannel channel, string cont /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task SendMessageAsync(DiscordChannel channel, DiscordEmbed embed) - => this.ApiClient.CreateMessageAsync(channel.Id, null, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + => this.ApiClient.CreateMessageAsync(channel.Id, null, embed != null + ? new[] + { + embed + } + : null, null, null, false, false); /// /// Sends a message with content and an embed. @@ -682,7 +689,12 @@ public Task SendMessageAsync(DiscordChannel channel, DiscordEmbe /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task SendMessageAsync(DiscordChannel channel, string content, DiscordEmbed embed) - => this.ApiClient.CreateMessageAsync(channel.Id, content, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + => this.ApiClient.CreateMessageAsync(channel.Id, content, embed != null + ? new[] + { + embed + } + : null, null, null, false, false); /// /// Sends a message with the . @@ -728,8 +740,14 @@ public Task SendMessageAsync(DiscordChannel channel, ActionThrown when the channel does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public Task CreateGuildAsync(string name, string region = null, Optional icon = default, VerificationLevel? verificationLevel = null, - DefaultMessageNotifications? defaultMessageNotifications = null, SystemChannelFlags? systemChannelFlags = null) + public Task CreateGuildAsync( + string name, + string region = null, + Optional icon = default, + VerificationLevel? verificationLevel = null, + DefaultMessageNotifications? defaultMessageNotifications = null, + SystemChannelFlags? systemChannelFlags = null + ) { var iconb64 = ImageTool.Base64FromStream(icon); return this.ApiClient.CreateGuildAsync(name, region, iconb64, verificationLevel, defaultMessageNotifications, systemChannelFlags); @@ -992,6 +1010,7 @@ public Uri GenerateInAppOauthFor(DiscordUser bot, Permissions permissions = Perm { if (!bot.IsBot) throw new ArgumentException("The user must be a bot.", nameof(bot)); + permissions &= PermissionMethods.FullPerms; return new(new QueryUriBuilder($"{DiscordDomain.GetDomain(CoreDomain.Discord).Url}{Endpoints.OAUTH2}{Endpoints.AUTHORIZE}") .AddParameter("client_id", bot.Id.ToString(CultureInfo.InvariantCulture)) @@ -1199,7 +1218,7 @@ public Task CreateGuildApplicationCommandAsync(ulong /// The id of the command to get. /// The command with the id. public Task GetGuildApplicationCommandAsync(ulong guildId, ulong commandId) => - this.ApiClient.GetGuildApplicationCommandAsync(this.CurrentApplication.Id, guildId, commandId); + this.ApiClient.GetGuildApplicationCommandAsync(this.CurrentApplication.Id, guildId, commandId); /// /// Edits a application command in a guild. @@ -1241,9 +1260,10 @@ public Task> GetGuildApp public Task GetApplicationCommandPermissionAsync(ulong guildId, ulong commandId) => null; - #endregion +#endregion + +#region Internal Caching Methods - #region Internal Caching Methods /// /// Gets the internal cached threads. /// @@ -1261,7 +1281,6 @@ internal DiscordThreadChannel InternalGetCachedThread(ulong threadId) return null; } - /// /// Gets the internal cached scheduled event. /// @@ -1309,10 +1328,8 @@ internal DiscordChannel InternalGetCachedChannel(ulong channelId, ulong? guildId internal DiscordGuild InternalGetCachedGuild(ulong? guildId) { if (this.GuildsInternal != null && guildId.HasValue) - { if (this.GuildsInternal.TryGetValue(guildId.Value, out var guild)) return guild; - } return null; } @@ -1328,7 +1345,10 @@ private void UpdateMessage(DiscordMessage message, TransportUser author, Discord { if (author != null) { - var usr = new DiscordUser(author) { Discord = this }; + var usr = new DiscordUser(author) + { + Discord = this + }; if (member != null) member.User = author; @@ -1343,14 +1363,11 @@ private void UpdateMessage(DiscordMessage message, TransportUser author, Discord channel = !message.GuildId.HasValue ? new DiscordDmChannel { - Id = message.ChannelId, - Discord = this, - Type = ChannelType.Private + Id = message.ChannelId, Discord = this, Type = ChannelType.Private } : new DiscordChannel { - Id = message.ChannelId, - Discord = this + Id = message.ChannelId, Discord = this }; message.Channel = channel; @@ -1365,7 +1382,6 @@ private void UpdateMessage(DiscordMessage message, TransportUser author, Discord private DiscordScheduledEvent UpdateScheduledEvent(DiscordScheduledEvent scheduledEvent, DiscordGuild guild) { if (scheduledEvent != null) - { _ = guild.ScheduledEventsInternal.AddOrUpdate(scheduledEvent.Id, scheduledEvent, (id, old) => { old.Discord = this; @@ -1381,7 +1397,6 @@ private DiscordScheduledEvent UpdateScheduledEvent(DiscordScheduledEvent schedul old.ScheduledEndTimeRaw = scheduledEvent.ScheduledEndTimeRaw; return old; }); - } return scheduledEvent; } @@ -1400,7 +1415,10 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild gui { if (mbr.User != null) { - usr = new(mbr.User) { Discord = this }; + usr = new(mbr.User) + { + Discord = this + }; _ = this.UserCache.AddOrUpdate(usr.Id, usr, (id, old) => { @@ -1417,7 +1435,10 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild gui return old; }); - usr = new DiscordMember(mbr) { Discord = this, GuildId = guildId.Value }; + usr = new DiscordMember(mbr) + { + Discord = this, GuildId = guildId.Value + }; } var intents = this.Configuration.Intents; @@ -1429,21 +1450,14 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild gui if (guild?.MembersInternal.TryGetValue(usr.Id, out member) == false) { if (intents.HasIntent(DiscordIntents.GuildMembers) || this.Configuration.AlwaysCacheMembers) // member can be updated by events, so cache it - { guild.MembersInternal.TryAdd(usr.Id, (DiscordMember)usr); - } } else if (intents.HasIntent(DiscordIntents.GuildPresences) || this.Configuration.AlwaysCacheMembers) // we can attempt to update it if it's already in cache. - { if (!intents.HasIntent(DiscordIntents.GuildMembers)) // no need to update if we already have the member events - { _ = guild.MembersInternal.TryUpdate(usr.Id, (DiscordMember)usr, member); - } - } } } else if (usr.Username != null) // check if not a skeleton user - { _ = this.UserCache.AddOrUpdate(usr.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1458,7 +1472,6 @@ private DiscordUser UpdateUser(DiscordUser usr, ulong? guildId, DiscordGuild gui old.GlobalName = usr.GlobalName; return old; }); - } return usr; } @@ -1504,7 +1517,6 @@ private void UpdateCachedGuild(DiscordGuild newGuild, JArray rawMembers) var guild = this.GuildsInternal[newGuild.Id]; if (newGuild.ChannelsInternal != null && !newGuild.ChannelsInternal.IsEmpty) - { foreach (var channel in newGuild.ChannelsInternal.Values) { if (guild.ChannelsInternal.TryGetValue(channel.Id, out _)) continue; @@ -1513,27 +1525,22 @@ private void UpdateCachedGuild(DiscordGuild newGuild, JArray rawMembers) guild.ChannelsInternal[channel.Id] = channel; } - } if (newGuild.ThreadsInternal != null && !newGuild.ThreadsInternal.IsEmpty) - { foreach (var thread in newGuild.ThreadsInternal.Values) { if (guild.ThreadsInternal.TryGetValue(thread.Id, out _)) continue; guild.ThreadsInternal[thread.Id] = thread; } - } if (newGuild.ScheduledEventsInternal != null && !newGuild.ScheduledEventsInternal.IsEmpty) - { foreach (var @event in newGuild.ScheduledEventsInternal.Values) { if (guild.ScheduledEventsInternal.TryGetValue(@event.Id, out _)) continue; guild.ScheduledEventsInternal[@event.Id] = @event; } - } foreach (var newEmoji in newGuild.EmojisInternal.Values) _ = guild.EmojisInternal.GetOrAdd(newEmoji.Id, _ => newEmoji); @@ -1552,7 +1559,10 @@ private void UpdateCachedGuild(DiscordGuild newGuild, JArray rawMembers) { var xtm = xj.ToDiscordObject(); - var usr = new DiscordUser(xtm.User) { Discord = this }; + var usr = new DiscordUser(xtm.User) + { + Discord = this + }; _ = this.UserCache.AddOrUpdate(xtm.User.Id, usr, (id, old) => { old.Username = usr.Username; @@ -1568,7 +1578,10 @@ private void UpdateCachedGuild(DiscordGuild newGuild, JArray rawMembers) return old; }); - guild.MembersInternal[xtm.User.Id] = new(xtm) { Discord = this, GuildId = guild.Id }; + guild.MembersInternal[xtm.User.Id] = new(xtm) + { + Discord = this, GuildId = guild.Id + }; } } @@ -1642,10 +1655,9 @@ private void PopulateMessageReactionsAndCache(DiscordMessage message, TransportU this.MessageCache?.Add(message); } +#endregion - #endregion - - #region Disposal +#region Disposal ~DiscordClient() { @@ -1655,7 +1667,6 @@ private void PopulateMessageReactionsAndCache(DiscordMessage message, TransportU /// /// Whether the client is disposed. /// - private bool _disposed; /// @@ -1693,5 +1704,5 @@ public override void Dispose() SentrySdk.EndSession(); } - #endregion +#endregion } diff --git a/DisCatSharp/Clients/DiscordOAuth2Client.cs b/DisCatSharp/Clients/DiscordOAuth2Client.cs index 1c257375ad..9ba42f007c 100644 --- a/DisCatSharp/Clients/DiscordOAuth2Client.cs +++ b/DisCatSharp/Clients/DiscordOAuth2Client.cs @@ -97,8 +97,18 @@ public string BotLibrary /// The optional logging factory to use for this client. Defaults to null. /// The minimum logging level for messages. Defaults to information. /// The timestamp format to use for the logger. - public DiscordOAuth2Client(ulong clientId, string clientSecret, string redirectUri, IServiceProvider provider = null!, IWebProxy proxy = null!, TimeSpan? timeout = null, bool useRelativeRateLimit = true, - ILoggerFactory loggerFactory = null!, LogLevel minimumLogLevel = LogLevel.Information, string logTimestampFormat = "yyyy-MM-dd HH:mm:ss zzz") + public DiscordOAuth2Client( + ulong clientId, + string clientSecret, + string redirectUri, + IServiceProvider provider = null!, + IWebProxy proxy = null!, + TimeSpan? timeout = null, + bool useRelativeRateLimit = true, + ILoggerFactory loggerFactory = null!, + LogLevel minimumLogLevel = LogLevel.Information, + string logTimestampFormat = "yyyy-MM-dd HH:mm:ss zzz" + ) { this.MinimumLogLevel = minimumLogLevel; this.LogTimestampFormat = logTimestampFormat; @@ -119,7 +129,6 @@ public DiscordOAuth2Client(ulong clientId, string clientSecret, string redirectU this.ApiClient = new(this, proxy!, parsedTimeout, useRelativeRateLimit, this.Logger); - this.ApiClient.Rest.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("client_id", this.ClientId.ToString()); this.ApiClient.Rest.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("client_secret", this.ClientSecret); @@ -197,9 +206,9 @@ public bool ValidateState(Uri requestUrl, Uri responseUrl, bool secure = false) var responseState = responseQueryDictionary.GetValues("state")?.First(); if (!secure) return requestState is not null && responseState is not null && - int.Parse(requestState.Split("::")[1]) == this.ClientId.GetHashCode() && - int.Parse(responseState.Split("::")[1]) == this.ClientId.GetHashCode() && - requestState == responseState; + int.Parse(requestState.Split("::")[1]) == this.ClientId.GetHashCode() && + int.Parse(responseState.Split("::")[1]) == this.ClientId.GetHashCode() && + requestState == responseState; if (requestState is null || responseState is null) throw new NullReferenceException("State was null"); @@ -314,7 +323,6 @@ public Task GetCurrentUserApplicationRoleConne public Task UpdateCurrentUserApplicationRoleConnectionAsync(DiscordAccessToken accessToken, string platformName, string platformUsername, ApplicationRoleConnectionMetadata metadata) => accessToken.Scope.Split(' ').Any(x => x == "role_connections.write") ? this.ApiClient.ModifyCurrentUserApplicationRoleConnectionAsync(accessToken.AccessToken, platformName, platformUsername, metadata) : throw new AccessViolationException("Access token does not include role_connections.write scope"); - /// /// Fired whenever an error occurs within an event handler. /// @@ -347,7 +355,10 @@ internal void EventErrorHandler(AsyncEvent async } this.Logger.LogError(LoggerEvents.EventHandlerException, ex, "Event handler exception for event {Name} thrown from {Method} (defined in {Type})", asyncEvent.Name, handler.Method, handler.Method.DeclaringType); - this.OAuth2ClientErroredInternal.InvokeAsync(this, new(this.ServiceProvider) { EventName = asyncEvent.Name, Exception = ex }).ConfigureAwait(false).GetAwaiter().GetResult(); + this.OAuth2ClientErroredInternal.InvokeAsync(this, new(this.ServiceProvider) + { + EventName = asyncEvent.Name, Exception = ex + }).ConfigureAwait(false).GetAwaiter().GetResult(); } /// diff --git a/DisCatSharp/Clients/DiscordShardedClient.Events.cs b/DisCatSharp/Clients/DiscordShardedClient.Events.cs index 633cdd3b9f..3dd56bc8ad 100644 --- a/DisCatSharp/Clients/DiscordShardedClient.Events.cs +++ b/DisCatSharp/Clients/DiscordShardedClient.Events.cs @@ -14,7 +14,7 @@ namespace DisCatSharp; /// public sealed partial class DiscordShardedClient { - #region WebSocket +#region WebSocket /// /// Fired whenever a WebSocket error occurs within the client. @@ -24,6 +24,7 @@ public event AsyncEventHandler SocketErrore add => this._socketErrored.Register(value); remove => this._socketErrored.Unregister(value); } + private AsyncEvent _socketErrored; /// @@ -34,6 +35,7 @@ public event AsyncEventHandler SocketOpened add => this._socketOpened.Register(value); remove => this._socketOpened.Unregister(value); } + private AsyncEvent _socketOpened; /// @@ -44,6 +46,7 @@ public event AsyncEventHandler SocketClosed add => this._socketClosed.Register(value); remove => this._socketClosed.Unregister(value); } + private AsyncEvent _socketClosed; /// @@ -54,6 +57,7 @@ public event AsyncEventHandler Ready add => this._ready.Register(value); remove => this._ready.Unregister(value); } + private AsyncEvent _ready; /// @@ -64,6 +68,7 @@ public event AsyncEventHandler Resumed add => this._resumed.Register(value); remove => this._resumed.Unregister(value); } + private AsyncEvent _resumed; /// @@ -74,11 +79,12 @@ public event AsyncEventHandler Heartbeated add => this._heartbeated.Register(value); remove => this._heartbeated.Unregister(value); } + private AsyncEvent _heartbeated; - #endregion +#endregion - #region Channel +#region Channel /// /// Fired when a new channel is created. @@ -89,6 +95,7 @@ public event AsyncEventHandler ChannelCre add => this._channelCreated.Register(value); remove => this._channelCreated.Unregister(value); } + private AsyncEvent _channelCreated; /// @@ -100,6 +107,7 @@ public event AsyncEventHandler ChannelUpd add => this._channelUpdated.Register(value); remove => this._channelUpdated.Unregister(value); } + private AsyncEvent _channelUpdated; /// @@ -111,6 +119,7 @@ public event AsyncEventHandler ChannelDel add => this._channelDeleted.Register(value); remove => this._channelDeleted.Unregister(value); } + private AsyncEvent _channelDeleted; /// @@ -122,6 +131,7 @@ public event AsyncEventHandler DmChanne add => this._dmChannelDeleted.Register(value); remove => this._dmChannelDeleted.Unregister(value); } + private AsyncEvent _dmChannelDeleted; /// @@ -133,6 +143,7 @@ public event AsyncEventHandler Channe add => this._channelPinsUpdated.Register(value); remove => this._channelPinsUpdated.Unregister(value); } + private AsyncEvent _channelPinsUpdated; /// @@ -144,11 +155,12 @@ public event AsyncEventHandler add => this._voiceChannelStatusUpdated.Register(value); remove => this._voiceChannelStatusUpdated.Unregister(value); } + private AsyncEvent _voiceChannelStatusUpdated; - #endregion +#endregion - #region Guild +#region Guild /// /// Fired when the user joins a new guild. @@ -160,6 +172,7 @@ public event AsyncEventHandler GuildCreated add => this._guildCreated.Register(value); remove => this._guildCreated.Unregister(value); } + private AsyncEvent _guildCreated; /// @@ -170,6 +183,7 @@ public event AsyncEventHandler GuildAvailab add => this._guildAvailable.Register(value); remove => this._guildAvailable.Unregister(value); } + private AsyncEvent _guildAvailable; /// @@ -181,6 +195,7 @@ public event AsyncEventHandler GuildUpdated add => this._guildUpdated.Register(value); remove => this._guildUpdated.Unregister(value); } + private AsyncEvent _guildUpdated; /// @@ -192,6 +207,7 @@ public event AsyncEventHandler GuildDeleted add => this._guildDeleted.Register(value); remove => this._guildDeleted.Unregister(value); } + private AsyncEvent _guildDeleted; /// @@ -202,6 +218,7 @@ public event AsyncEventHandler GuildUnavail add => this._guildUnavailable.Register(value); remove => this._guildUnavailable.Unregister(value); } + private AsyncEvent _guildUnavailable; /// @@ -212,6 +229,7 @@ public event AsyncEventHandler G add => this._guildDownloadCompleted.Register(value); remove => this._guildDownloadCompleted.Unregister(value); } + private AsyncEvent _guildDownloadCompleted; /// @@ -223,6 +241,7 @@ public event AsyncEventHandler GuildE add => this._guildEmojisUpdated.Register(value); remove => this._guildEmojisUpdated.Unregister(value); } + private AsyncEvent _guildEmojisUpdated; /// @@ -234,6 +253,7 @@ public event AsyncEventHandler Guil add => this._guildStickersUpdated.Register(value); remove => this._guildStickersUpdated.Unregister(value); } + private AsyncEvent _guildStickersUpdated; /// @@ -244,11 +264,13 @@ public event AsyncEventHandler add => this._guildIntegrationsUpdated.Register(value); remove => this._guildIntegrationsUpdated.Unregister(value); } + private AsyncEvent _guildIntegrationsUpdated; - #endregion +#endregion + +#region Automod - #region Automod /// /// Fired when an auto mod rule gets created. /// @@ -257,6 +279,7 @@ public event AsyncEventHandler Automo add => this._automodRuleCreated.Register(value); remove => this._automodRuleCreated.Unregister(value); } + private AsyncEvent _automodRuleCreated; /// @@ -267,6 +290,7 @@ public event AsyncEventHandler Automo add => this._automodRuleUpdated.Register(value); remove => this._automodRuleUpdated.Unregister(value); } + private AsyncEvent _automodRuleUpdated; /// @@ -277,6 +301,7 @@ public event AsyncEventHandler Automo add => this._automodRuleDeleted.Register(value); remove => this._automodRuleDeleted.Unregister(value); } + private AsyncEvent _automodRuleDeleted; /// @@ -287,6 +312,7 @@ public event AsyncEventHandler Au add => this._automodActionExecuted.Register(value); remove => this._automodActionExecuted.Unregister(value); } + private AsyncEvent _automodActionExecuted; /// @@ -297,10 +323,12 @@ public event AsyncEventHandler add => this._guildAuditLogEntryCreated.Register(value); remove => this._guildAuditLogEntryCreated.Unregister(value); } + private AsyncEvent _guildAuditLogEntryCreated; - #endregion - #region Guild Ban +#endregion + +#region Guild Ban /// /// Fired when a guild ban gets added @@ -311,6 +339,7 @@ public event AsyncEventHandler GuildBanAdde add => this._guildBanAdded.Register(value); remove => this._guildBanAdded.Unregister(value); } + private AsyncEvent _guildBanAdded; /// @@ -322,11 +351,12 @@ public event AsyncEventHandler GuildBanR add => this._guildBanRemoved.Register(value); remove => this._guildBanRemoved.Unregister(value); } + private AsyncEvent _guildBanRemoved; - #endregion +#endregion - #region Guild Timeout +#region Guild Timeout /// /// Fired when a guild member timeout gets added. @@ -337,6 +367,7 @@ public event AsyncEventHandler Gu add => this._guildMemberTimeoutAdded.Register(value); remove => this._guildMemberTimeoutAdded.Unregister(value); } + private AsyncEvent _guildMemberTimeoutAdded; /// @@ -348,8 +379,8 @@ public event AsyncEventHandler add => this._guildMemberTimeoutChanged.Register(value); remove => this._guildMemberTimeoutChanged.Unregister(value); } - private AsyncEvent _guildMemberTimeoutChanged; + private AsyncEvent _guildMemberTimeoutChanged; /// /// Fired when a guild member timeout gets removed. @@ -360,11 +391,12 @@ public event AsyncEventHandler add => this._guildMemberTimeoutRemoved.Register(value); remove => this._guildMemberTimeoutRemoved.Unregister(value); } + private AsyncEvent _guildMemberTimeoutRemoved; - #endregion +#endregion - #region Guild Event +#region Guild Event /// /// Fired when a scheduled event is created. @@ -375,6 +407,7 @@ public event AsyncEventHandler this._guildScheduledEventCreated.Register(value); remove => this._guildScheduledEventCreated.Unregister(value); } + private AsyncEvent _guildScheduledEventCreated; /// @@ -386,6 +419,7 @@ public event AsyncEventHandler this._guildScheduledEventUpdated.Register(value); remove => this._guildScheduledEventUpdated.Unregister(value); } + private AsyncEvent _guildScheduledEventUpdated; /// @@ -397,6 +431,7 @@ public event AsyncEventHandler this._guildScheduledEventDeleted.Register(value); remove => this._guildScheduledEventDeleted.Unregister(value); } + private AsyncEvent _guildScheduledEventDeleted; /// @@ -408,6 +443,7 @@ public event AsyncEventHandler this._guildScheduledEventUserAdded.Register(value); remove => this._guildScheduledEventUserAdded.Unregister(value); } + private AsyncEvent _guildScheduledEventUserAdded; /// @@ -419,11 +455,12 @@ public event AsyncEventHandler this._guildScheduledEventUserRemoved.Register(value); remove => this._guildScheduledEventUserRemoved.Unregister(value); } + private AsyncEvent _guildScheduledEventUserRemoved; - #endregion +#endregion - #region Guild Integration +#region Guild Integration /// /// Fired when a guild integration is created. @@ -434,6 +471,7 @@ public event AsyncEventHandler G add => this._guildIntegrationCreated.Register(value); remove => this._guildIntegrationCreated.Unregister(value); } + private AsyncEvent _guildIntegrationCreated; /// @@ -445,6 +483,7 @@ public event AsyncEventHandler G add => this._guildIntegrationUpdated.Register(value); remove => this._guildIntegrationUpdated.Unregister(value); } + private AsyncEvent _guildIntegrationUpdated; /// @@ -456,11 +495,12 @@ public event AsyncEventHandler G add => this._guildIntegrationDeleted.Register(value); remove => this._guildIntegrationDeleted.Unregister(value); } + private AsyncEvent _guildIntegrationDeleted; - #endregion +#endregion - #region Guild Member +#region Guild Member /// /// Fired when a new user joins a guild. @@ -471,6 +511,7 @@ public event AsyncEventHandler GuildMemb add => this._guildMemberAdded.Register(value); remove => this._guildMemberAdded.Unregister(value); } + private AsyncEvent _guildMemberAdded; /// @@ -482,6 +523,7 @@ public event AsyncEventHandler GuildM add => this._guildMemberRemoved.Register(value); remove => this._guildMemberRemoved.Unregister(value); } + private AsyncEvent _guildMemberRemoved; /// @@ -493,6 +535,7 @@ public event AsyncEventHandler GuildM add => this._guildMemberUpdated.Register(value); remove => this._guildMemberUpdated.Unregister(value); } + private AsyncEvent _guildMemberUpdated; /// @@ -503,11 +546,12 @@ public event AsyncEventHandler GuildM add => this._guildMembersChunk.Register(value); remove => this._guildMembersChunk.Unregister(value); } + private AsyncEvent _guildMembersChunk; - #endregion +#endregion - #region Guild Role +#region Guild Role /// /// Fired when a guild role is created. @@ -518,6 +562,7 @@ public event AsyncEventHandler GuildRol add => this._guildRoleCreated.Register(value); remove => this._guildRoleCreated.Unregister(value); } + private AsyncEvent _guildRoleCreated; /// @@ -529,6 +574,7 @@ public event AsyncEventHandler GuildRol add => this._guildRoleUpdated.Register(value); remove => this._guildRoleUpdated.Unregister(value); } + private AsyncEvent _guildRoleUpdated; /// @@ -540,11 +586,12 @@ public event AsyncEventHandler GuildRol add => this._guildRoleDeleted.Register(value); remove => this._guildRoleDeleted.Unregister(value); } + private AsyncEvent _guildRoleDeleted; - #endregion +#endregion - #region Invite +#region Invite /// /// Fired when an invite is created. @@ -555,6 +602,7 @@ public event AsyncEventHandler InviteCreat add => this._inviteCreated.Register(value); remove => this._inviteCreated.Unregister(value); } + private AsyncEvent _inviteCreated; /// @@ -566,11 +614,12 @@ public event AsyncEventHandler InviteDelet add => this._inviteDeleted.Register(value); remove => this._inviteDeleted.Unregister(value); } + private AsyncEvent _inviteDeleted; - #endregion +#endregion - #region Message +#region Message /// /// Fired when a message is created. @@ -581,6 +630,7 @@ public event AsyncEventHandler MessageCre add => this._messageCreated.Register(value); remove => this._messageCreated.Unregister(value); } + private AsyncEvent _messageCreated; /// @@ -592,6 +642,7 @@ public event AsyncEventHandler MessageUpd add => this._messageUpdated.Register(value); remove => this._messageUpdated.Unregister(value); } + private AsyncEvent _messageUpdated; /// @@ -603,6 +654,7 @@ public event AsyncEventHandler MessageDel add => this._messageDeleted.Register(value); remove => this._messageDeleted.Unregister(value); } + private AsyncEvent _messageDeleted; /// @@ -614,11 +666,12 @@ public event AsyncEventHandler Messag add => this._messageBulkDeleted.Register(value); remove => this._messageBulkDeleted.Unregister(value); } + private AsyncEvent _messageBulkDeleted; - #endregion +#endregion - #region Message Reaction +#region Message Reaction /// /// Fired when a reaction gets added to a message. @@ -629,6 +682,7 @@ public event AsyncEventHandler Messa add => this._messageReactionAdded.Register(value); remove => this._messageReactionAdded.Unregister(value); } + private AsyncEvent _messageReactionAdded; /// @@ -640,6 +694,7 @@ public event AsyncEventHandler Me add => this._messageReactionRemoved.Register(value); remove => this._messageReactionRemoved.Unregister(value); } + private AsyncEvent _messageReactionRemoved; /// @@ -651,6 +706,7 @@ public event AsyncEventHandler Me add => this._messageReactionsCleared.Register(value); remove => this._messageReactionsCleared.Unregister(value); } + private AsyncEvent _messageReactionsCleared; /// @@ -662,11 +718,12 @@ public event AsyncEventHandler this._messageReactionRemovedEmoji.Register(value); remove => this._messageReactionRemovedEmoji.Unregister(value); } + private AsyncEvent _messageReactionRemovedEmoji; - #endregion +#endregion - #region Stage Instance +#region Stage Instance /// /// Fired when a Stage Instance is created. @@ -677,6 +734,7 @@ public event AsyncEventHandler Stag add => this._stageInstanceCreated.Register(value); remove => this._stageInstanceCreated.Unregister(value); } + private AsyncEvent _stageInstanceCreated; /// @@ -688,6 +746,7 @@ public event AsyncEventHandler Stag add => this._stageInstanceUpdated.Register(value); remove => this._stageInstanceUpdated.Unregister(value); } + private AsyncEvent _stageInstanceUpdated; /// @@ -699,11 +758,12 @@ public event AsyncEventHandler Stag add => this._stageInstanceDeleted.Register(value); remove => this._stageInstanceDeleted.Unregister(value); } + private AsyncEvent _stageInstanceDeleted; - #endregion +#endregion - #region Thread +#region Thread /// /// Fired when a thread is created. @@ -714,6 +774,7 @@ public event AsyncEventHandler ThreadCreat add => this._threadCreated.Register(value); remove => this._threadCreated.Unregister(value); } + private AsyncEvent _threadCreated; /// @@ -725,6 +786,7 @@ public event AsyncEventHandler ThreadUpdat add => this._threadUpdated.Register(value); remove => this._threadUpdated.Unregister(value); } + private AsyncEvent _threadUpdated; /// @@ -736,6 +798,7 @@ public event AsyncEventHandler ThreadDelet add => this._threadDeleted.Register(value); remove => this._threadDeleted.Unregister(value); } + private AsyncEvent _threadDeleted; /// @@ -747,6 +810,7 @@ public event AsyncEventHandler ThreadLis add => this._threadListSynced.Register(value); remove => this._threadListSynced.Unregister(value); } + private AsyncEvent _threadListSynced; /// @@ -758,6 +822,7 @@ public event AsyncEventHandler Threa add => this._threadMemberUpdated.Register(value); remove => this._threadMemberUpdated.Unregister(value); } + private AsyncEvent _threadMemberUpdated; /// @@ -769,11 +834,12 @@ public event AsyncEventHandler Thre add => this._threadMembersUpdated.Register(value); remove => this._threadMembersUpdated.Unregister(value); } + private AsyncEvent _threadMembersUpdated; - #endregion +#endregion - #region Activities +#region Activities /// /// Fired when a embedded activity has been updated. @@ -783,11 +849,12 @@ public event AsyncEventHandler E add => this._embeddedActivityUpdated.Register(value); remove => this._embeddedActivityUpdated.Unregister(value); } + private AsyncEvent _embeddedActivityUpdated; - #endregion +#endregion - #region User/Presence Update +#region User/Presence Update /// /// Fired when a presence has been updated. @@ -798,8 +865,8 @@ public event AsyncEventHandler PresenceU add => this._presenceUpdated.Register(value); remove => this._presenceUpdated.Unregister(value); } - private AsyncEvent _presenceUpdated; + private AsyncEvent _presenceUpdated; /// /// Fired when the current user updates their settings. @@ -810,6 +877,7 @@ public event AsyncEventHandler UserS add => this._userSettingsUpdated.Register(value); remove => this._userSettingsUpdated.Unregister(value); } + private AsyncEvent _userSettingsUpdated; /// @@ -824,11 +892,12 @@ public event AsyncEventHandler UserUpdated add => this._userUpdated.Register(value); remove => this._userUpdated.Unregister(value); } + private AsyncEvent _userUpdated; - #endregion +#endregion - #region Voice +#region Voice /// /// Fired when someone joins/leaves/moves voice channels. @@ -839,6 +908,7 @@ public event AsyncEventHandler VoiceSt add => this._voiceStateUpdated.Register(value); remove => this._voiceStateUpdated.Unregister(value); } + private AsyncEvent _voiceStateUpdated; /// @@ -850,11 +920,12 @@ public event AsyncEventHandler VoiceS add => this._voiceServerUpdated.Register(value); remove => this._voiceServerUpdated.Unregister(value); } + private AsyncEvent _voiceServerUpdated; - #endregion +#endregion - #region Application +#region Application /// /// Fired when a new application command is registered. @@ -864,6 +935,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandCreated.Register(value); remove => this._applicationCommandCreated.Unregister(value); } + private AsyncEvent _applicationCommandCreated; /// @@ -874,6 +946,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandUpdated.Register(value); remove => this._applicationCommandUpdated.Unregister(value); } + private AsyncEvent _applicationCommandUpdated; /// @@ -884,6 +957,7 @@ public event AsyncEventHandler Appli add => this._applicationCommandDeleted.Register(value); remove => this._applicationCommandDeleted.Unregister(value); } + private AsyncEvent _applicationCommandDeleted; /// @@ -894,6 +968,7 @@ public event AsyncEventHandler this._guildApplicationCommandCountUpdated.Register(value); remove => this._guildApplicationCommandCountUpdated.Unregister(value); } + private AsyncEvent _guildApplicationCommandCountUpdated; /// @@ -918,10 +993,9 @@ public event AsyncEventHandler _applicationCommandPermissionsUpdated; +#endregion - #endregion - - #region Misc +#region Misc /// /// Fired when an interaction is invoked. @@ -931,6 +1005,7 @@ public event AsyncEventHandler Intera add => this._interactionCreated.Register(value); remove => this._interactionCreated.Unregister(value); } + private AsyncEvent _interactionCreated; /// @@ -941,6 +1016,7 @@ public event AsyncEventHandler this._componentInteractionCreated.Register(value); remove => this._componentInteractionCreated.Unregister(value); } + private AsyncEvent _componentInteractionCreated; /// @@ -951,6 +1027,7 @@ public event AsyncEventHandler Entitl add => this._entitlementCreated.Register(value); remove => this._entitlementCreated.Unregister(value); } + private AsyncEvent _entitlementCreated; /// @@ -961,6 +1038,7 @@ public event AsyncEventHandler Entitl add => this._entitlementUpdated.Register(value); remove => this._entitlementUpdated.Unregister(value); } + private AsyncEvent _entitlementUpdated; /// @@ -974,7 +1052,6 @@ public event AsyncEventHandler Entitl private AsyncEvent _entitlementDeleted; - /// /// Fired when a user starts typing in a channel. /// @@ -983,6 +1060,7 @@ public event AsyncEventHandler TypingStarte add => this._typingStarted.Register(value); remove => this._typingStarted.Unregister(value); } + private AsyncEvent _typingStarted; /// @@ -993,6 +1071,7 @@ public event AsyncEventHandler UnknownEvent add => this._unknownEvent.Register(value); remove => this._unknownEvent.Unregister(value); } + private AsyncEvent _unknownEvent; /// @@ -1003,6 +1082,7 @@ public event AsyncEventHandler WebhooksU add => this._webhooksUpdated.Register(value); remove => this._webhooksUpdated.Unregister(value); } + private AsyncEvent _webhooksUpdated; /// @@ -1013,11 +1093,12 @@ public event AsyncEventHandler ClientErrore add => this._clientErrored.Register(value); remove => this._clientErrored.Unregister(value); } + private AsyncEvent _clientErrored; - #endregion +#endregion - #region Error Handling +#region Error Handling /// /// Handles event errors. @@ -1037,10 +1118,12 @@ internal void EventErrorHandler(AsyncEvent asyncEve } this.Logger.LogError(LoggerEvents.EventHandlerException, ex, "Event handler exception for event {0} thrown from {1} (defined in {2})", asyncEvent.Name, handler.Method, handler.Method.DeclaringType); - this._clientErrored.InvokeAsync(sender, new(this.ShardClients[0].ServiceProvider) { EventName = asyncEvent.Name, Exception = ex }).ConfigureAwait(false).GetAwaiter().GetResult(); + this._clientErrored.InvokeAsync(sender, new(this.ShardClients[0].ServiceProvider) + { + EventName = asyncEvent.Name, Exception = ex + }).ConfigureAwait(false).GetAwaiter().GetResult(); } - /// /// Fired on heartbeat attempt cancellation due to too many failed heartbeats. /// @@ -1049,6 +1132,7 @@ public event AsyncEventHandler Zombied add => this._zombied.Register(value); remove => this._zombied.Unregister(value); } + private AsyncEvent _zombied; /// @@ -1059,6 +1143,7 @@ public event AsyncEventHandler PayloadR add => this._payloadReceived.Register(value); remove => this._payloadReceived.Unregister(value); } + private AsyncEvent _payloadReceived; /// @@ -1072,9 +1157,9 @@ public event AsyncEventHandler PayloadR private void Goof(AsyncEvent asyncEvent, Exception ex, AsyncEventHandler handler, DiscordClient sender, TArgs eventArgs) where TArgs : AsyncEventArgs => this.Logger.LogCritical(LoggerEvents.EventHandlerException, ex, "Exception event handler {0} (defined in {1}) threw an exception", handler.Method, handler.Method.DeclaringType); - #endregion +#endregion - #region Event Dispatchers +#region Event Dispatchers /// /// Handles the client zombied event. @@ -1580,7 +1665,6 @@ private Task Client_ApplicationCommandUpdated(DiscordClient client, ApplicationC private Task Client_ApplicationCommandDeleted(DiscordClient client, ApplicationCommandEventArgs e) => this._applicationCommandDeleted.InvokeAsync(client, e); - /// /// Handles the guild application command count updated event. /// @@ -1589,7 +1673,6 @@ private Task Client_ApplicationCommandDeleted(DiscordClient client, ApplicationC private Task Client_GuildApplicationCommandCountUpdated(DiscordClient client, GuildApplicationCommandCountEventArgs e) => this._guildApplicationCommandCountUpdated.InvokeAsync(client, e); - /// /// Handles the application command permissions updated event. /// @@ -1694,7 +1777,6 @@ private Task Client_ThreadMemberUpdated(DiscordClient client, ThreadMemberUpdate private Task Client_ThreadMembersUpdated(DiscordClient client, ThreadMembersUpdateEventArgs e) => this._threadMembersUpdated.InvokeAsync(client, e); - /// /// Handles the scheduled event created event. /// @@ -1783,5 +1865,5 @@ private Task Client_GuildAuditLogEntryCreated(DiscordClient client, GuildAuditLo private Task Client_VoiceChannelStatusUpdated(DiscordClient client, VoiceChannelStatusUpdateEventArgs e) => this._voiceChannelStatusUpdated.InvokeAsync(client, e); - #endregion +#endregion } diff --git a/DisCatSharp/Clients/DiscordWebhookClient.cs b/DisCatSharp/Clients/DiscordWebhookClient.cs index b54ad246a5..c84f8b0bc8 100644 --- a/DisCatSharp/Clients/DiscordWebhookClient.cs +++ b/DisCatSharp/Clients/DiscordWebhookClient.cs @@ -68,8 +68,14 @@ public DiscordWebhookClient() /// The optional logging factory to use for this client. Defaults to null. /// The minimum logging level for messages. Defaults to information. /// The timestamp format to use for the logger. - public DiscordWebhookClient(IWebProxy proxy = null!, TimeSpan? timeout = null, bool useRelativeRateLimit = true, - ILoggerFactory loggerFactory = null!, LogLevel minimumLogLevel = LogLevel.Information, string logTimestampFormat = "yyyy-MM-dd HH:mm:ss zzz") + public DiscordWebhookClient( + IWebProxy proxy = null!, + TimeSpan? timeout = null, + bool useRelativeRateLimit = true, + ILoggerFactory loggerFactory = null!, + LogLevel minimumLogLevel = LogLevel.Information, + string logTimestampFormat = "yyyy-MM-dd HH:mm:ss zzz" + ) { this.MinimumLogLevel = minimumLogLevel; this.LogTimestampFormat = logTimestampFormat; @@ -99,6 +105,7 @@ public async Task AddWebhookAsync(ulong id, string token) { if (string.IsNullOrWhiteSpace(token)) throw new ArgumentNullException(nameof(token)); + token = token.Trim(); if (this.Hooks.Any(x => x.Id == id)) @@ -207,7 +214,6 @@ public async Task> BroadcastMessageAs var messages = new Dictionary(); foreach (var hook in this.Hooks) - { try { if (this.Username != null) @@ -220,7 +226,6 @@ public async Task> BroadcastMessageAs { deadHooks.Add(hook); } - } // Removing dead webhooks from collection foreach (var xwh in deadHooks) diff --git a/DisCatSharp/DiscordConfiguration.cs b/DisCatSharp/DiscordConfiguration.cs index ae2a7a7a58..549a438e93 100644 --- a/DisCatSharp/DiscordConfiguration.cs +++ b/DisCatSharp/DiscordConfiguration.cs @@ -34,6 +34,7 @@ public string Token this._token = value.Trim(); } } + private string _token = ""; /// @@ -314,9 +315,10 @@ internal List TrackExceptions throw new AccessViolationException("Cannot set this as non-library-dev"); else if (value == null) this._exceptions.Clear(); - else this._exceptions = value.All(val => val.BaseType == typeof(DisCatSharpException)) - ? value - : throw new InvalidOperationException("Can only track exceptions who inherit from " + nameof(DisCatSharpException) + " and must be constructed with typeof(Type)"); + else + this._exceptions = value.All(val => val.BaseType == typeof(DisCatSharpException)) + ? value + : throw new InvalidOperationException("Can only track exceptions who inherit from " + nameof(DisCatSharpException) + " and must be constructed with typeof(Type)"); } } @@ -325,8 +327,7 @@ internal List TrackExceptions /// private List _exceptions = new() { - typeof(ServerErrorException), - typeof(BadRequestException) + typeof(ServerErrorException), typeof(BadRequestException) }; /// diff --git a/DisCatSharp/Entities/Application/DiscordApplication.cs b/DisCatSharp/Entities/Application/DiscordApplication.cs index 3440e8fdba..6f5f8e55d7 100644 --- a/DisCatSharp/Entities/Application/DiscordApplication.cs +++ b/DisCatSharp/Entities/Application/DiscordApplication.cs @@ -210,7 +210,7 @@ public string GetAvatarUrl(ImageFormat fmt, ushort size = 1024) ImageFormat.Jpeg => "jpg", ImageFormat.Auto or ImageFormat.Png => "png", ImageFormat.WebP => "webp", - _ => throw new ArgumentOutOfRangeException(nameof(fmt)), + _ => throw new ArgumentOutOfRangeException(nameof(fmt)) }; var ssize = size.ToString(CultureInfo.InvariantCulture); return !string.IsNullOrWhiteSpace(this.CoverImageHash) @@ -279,7 +279,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// @@ -390,7 +390,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Application/DiscordApplicationCommand.cs b/DisCatSharp/Entities/Application/DiscordApplicationCommand.cs index 5faf41dc34..640864edf7 100644 --- a/DisCatSharp/Entities/Application/DiscordApplicationCommand.cs +++ b/DisCatSharp/Entities/Application/DiscordApplicationCommand.cs @@ -127,13 +127,22 @@ public DiscordApplicationCommandLocalization DescriptionLocalizations /// Where the command can be used. /// The allowed integration types. public DiscordApplicationCommand( - string name, string description, + string name, + string description, IEnumerable? options = null, ApplicationCommandType type = ApplicationCommandType.ChatInput, - DiscordApplicationCommandLocalization? nameLocalizations = null, DiscordApplicationCommandLocalization? descriptionLocalizations = null, - Permissions? defaultMemberPermissions = null, bool? dmPermission = null, bool isNsfw = false, - List? allowedContexts = null, List? integrationTypes = null) - : base(new() { "guild_id" }) + DiscordApplicationCommandLocalization? nameLocalizations = null, + DiscordApplicationCommandLocalization? descriptionLocalizations = null, + Permissions? defaultMemberPermissions = null, + bool? dmPermission = null, + bool isNsfw = false, + List? allowedContexts = null, + List? integrationTypes = null + ) + : base(new() + { + "guild_id" + }) { if (type is ApplicationCommandType.ChatInput) { @@ -155,6 +164,7 @@ public DiscordApplicationCommand( throw new ArgumentException("Context menus do not support descriptions."); if (options?.Any() ?? false) throw new ArgumentException("Context menus do not support options."); + description = string.Empty; this.RawNameLocalizations = nameLocalizations?.GetKeyValuePairs(); @@ -177,7 +187,10 @@ public DiscordApplicationCommand( /// Creates a new empty Discord Application Command. /// internal DiscordApplicationCommand() - : base(new() { "name_localizations", "description_localizations" }) // Why tf is that so inconsistent?! + : base(new() + { + "name_localizations", "description_localizations" + }) // Why tf is that so inconsistent?! { } /// diff --git a/DisCatSharp/Entities/Application/DiscordApplicationCommandLocalization.cs b/DisCatSharp/Entities/Application/DiscordApplicationCommandLocalization.cs index 6c43b1fa77..ae70f73a5e 100644 --- a/DisCatSharp/Entities/Application/DiscordApplicationCommandLocalization.cs +++ b/DisCatSharp/Entities/Application/DiscordApplicationCommandLocalization.cs @@ -16,7 +16,39 @@ public sealed class DiscordApplicationCommandLocalization /// /// Gets valid [locales](xref:modules_application_commands_translations_reference#valid-locales) for Discord. /// - internal List ValidLocales = new() { "ru", "fi", "hr", "de", "hu", "sv-SE", "cs", "fr", "it", "en-GB", "pt-BR", "ja", "tr", "en-US", "es-ES", "uk", "hi", "th", "el", "no", "ro", "ko", "zh-TW", "vi", "zh-CN", "pl", "bg", "da", "nl", "lt" }; + internal List ValidLocales = new() + { + "ru", + "fi", + "hr", + "de", + "hu", + "sv-SE", + "cs", + "fr", + "it", + "en-GB", + "pt-BR", + "ja", + "tr", + "en-US", + "es-ES", + "uk", + "hi", + "th", + "el", + "no", + "ro", + "ko", + "zh-TW", + "vi", + "zh-CN", + "pl", + "bg", + "da", + "nl", + "lt" + }; /// /// Adds a localization. @@ -26,14 +58,10 @@ public sealed class DiscordApplicationCommandLocalization public void AddLocalization(string locale, string value) { if (this.Validate(locale)) - { this.Localizations.Add(locale, value); - } else - { throw new NotSupportedException($"The provided locale \"{locale}\" is not valid for Discord.\n" + $"Valid locales: {string.Join(", ", this.ValidLocales)}"); - } } /// @@ -55,14 +83,10 @@ public DiscordApplicationCommandLocalization() { } public DiscordApplicationCommandLocalization(Dictionary localizations) { if (localizations != null) - { foreach (var locale in localizations.Keys) - { if (!this.Validate(locale)) throw new NotSupportedException($"The provided locale \"{locale}\" is not valid for Discord.\n" + $"Valid locales: {string.Join(", ", this.ValidLocales)}"); - } - } this.Localizations = localizations; } diff --git a/DisCatSharp/Entities/Application/DiscordApplicationCommandOption.cs b/DisCatSharp/Entities/Application/DiscordApplicationCommandOption.cs index bad9e105da..e4b4a13956 100644 --- a/DisCatSharp/Entities/Application/DiscordApplicationCommandOption.cs +++ b/DisCatSharp/Entities/Application/DiscordApplicationCommandOption.cs @@ -129,7 +129,22 @@ public DiscordApplicationCommandLocalization DescriptionLocalizations /// The localizations of the parameter description. /// The minimum allowed length of the string. (Min 0) /// The maximum allowed length of the string. (Min 1) - public DiscordApplicationCommandOption(string name, string description, ApplicationCommandOptionType type, bool required = false, IEnumerable? choices = null, IEnumerable? options = null, IEnumerable? channelTypes = null, bool autocomplete = false, object minimumValue = null, object maximumValue = null, DiscordApplicationCommandLocalization nameLocalizations = null, DiscordApplicationCommandLocalization descriptionLocalizations = null, int? minimumLength = null, int? maximumLength = null) + public DiscordApplicationCommandOption( + string name, + string description, + ApplicationCommandOptionType type, + bool required = false, + IEnumerable? choices = null, + IEnumerable? options = null, + IEnumerable? channelTypes = null, + bool autocomplete = false, + object minimumValue = null, + object maximumValue = null, + DiscordApplicationCommandLocalization nameLocalizations = null, + DiscordApplicationCommandLocalization descriptionLocalizations = null, + int? minimumLength = null, + int? maximumLength = null + ) { if (!Utilities.IsValidSlashCommandName(name)) throw new ArgumentException("Invalid application command option name specified. It must be below 32 characters and not contain any whitespace.", nameof(name)); @@ -139,6 +154,7 @@ public DiscordApplicationCommandOption(string name, string description, Applicat throw new ArgumentException("Application command option description cannot exceed 100 characters.", nameof(description)); if (autocomplete && (choices?.Any() ?? false)) throw new InvalidOperationException("Auto-complete slash command options cannot provide choices."); + if (type == ApplicationCommandOptionType.SubCommand || type == ApplicationCommandOptionType.SubCommandGroup) if (string.IsNullOrWhiteSpace(description)) throw new ArgumentException("Slash commands need a description.", nameof(description)); diff --git a/DisCatSharp/Entities/Application/DiscordApplicationRoleConnectionMetadata.cs b/DisCatSharp/Entities/Application/DiscordApplicationRoleConnectionMetadata.cs index 845d9d5505..4a7f71b07f 100644 --- a/DisCatSharp/Entities/Application/DiscordApplicationRoleConnectionMetadata.cs +++ b/DisCatSharp/Entities/Application/DiscordApplicationRoleConnectionMetadata.cs @@ -67,8 +67,12 @@ public DiscordApplicationCommandLocalization DescriptionLocalizations /// Creates a new instance of a . /// public DiscordApplicationRoleConnectionMetadata( - ApplicationRoleConnectionMetadataType type, string key, string name, string description, - DiscordApplicationCommandLocalization nameLocalizations = null, DiscordApplicationCommandLocalization descriptionLocalizations = null + ApplicationRoleConnectionMetadataType type, + string key, + string name, + string description, + DiscordApplicationCommandLocalization nameLocalizations = null, + DiscordApplicationCommandLocalization descriptionLocalizations = null ) { this.Type = type; diff --git a/DisCatSharp/Entities/Application/DiscordRpcApplication.cs b/DisCatSharp/Entities/Application/DiscordRpcApplication.cs index 10e607f47e..be2304a744 100644 --- a/DisCatSharp/Entities/Application/DiscordRpcApplication.cs +++ b/DisCatSharp/Entities/Application/DiscordRpcApplication.cs @@ -25,8 +25,10 @@ public sealed class DiscordRpcApplication : SnowflakeObject, IEquatable diff --git a/DisCatSharp/Entities/Channel/DiscordChannel.cs b/DisCatSharp/Entities/Channel/DiscordChannel.cs index 830b3304ee..0fadf5a729 100644 --- a/DisCatSharp/Entities/Channel/DiscordChannel.cs +++ b/DisCatSharp/Entities/Channel/DiscordChannel.cs @@ -90,6 +90,7 @@ public DiscordChannel Parent /// [JsonProperty("theme_color", NullValueHandling = NullValueHandling.Ignore)] internal int? ThemeColorInt { get; set; } + [JsonIgnore] public DiscordColor? ThemeColor => this.ThemeColorInt.HasValue ? new DiscordColor(this.ThemeColorInt.Value) : null; @@ -164,6 +165,7 @@ public IReadOnlyList PermissionOverwrites [JsonProperty("permission_overwrites", NullValueHandling = NullValueHandling.Ignore)] internal List PermissionOverwritesInternal = new(); + [JsonIgnore] private readonly Lazy> _permissionOverwritesLazy; @@ -211,14 +213,12 @@ public IReadOnlyList PermissionOverwrites [JsonProperty("video_quality_mode", NullValueHandling = NullValueHandling.Ignore)] public VideoQualityMode? QualityMode { get; internal set; } - /// /// List of available tags for forum posts. /// [JsonIgnore] public IReadOnlyList AvailableTags => this.InternalAvailableTags; - /// /// List of available tags for forum posts. /// @@ -239,8 +239,7 @@ public IReadOnlyList PermissionOverwrites /// [JsonIgnore] public DateTimeOffset? LastPinTimestamp - => !string.IsNullOrWhiteSpace(this.LastPinTimestampRaw) && DateTimeOffset.TryParse(this.LastPinTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.LastPinTimestampRaw) && DateTimeOffset.TryParse(this.LastPinTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets when the last pinned message was pinned as raw string. @@ -300,7 +299,6 @@ public string Mention public DiscordVoiceRegion RtcRegion => this.RtcRegionId != null ? this.Discord.VoiceRegions[this.RtcRegionId] : null; - /// /// Only sent on the resolved channels of interaction responses for application commands. /// Gets the permissions of the user in this channel who invoked the command. @@ -312,7 +310,17 @@ public DiscordVoiceRegion RtcRegion /// Initializes a new instance of the class. /// internal DiscordChannel() - : base(new() { "hashes", "guild_hashes", "owner_id", "thread_metadata", "message_count", "member_count", "total_message_sent", "member" }) + : base(new() + { + "hashes", + "guild_hashes", + "owner_id", + "thread_metadata", + "message_count", + "member_count", + "total_message_sent", + "member" + }) { this._permissionOverwritesLazy = new(() => new ReadOnlyCollection(this.PermissionOverwritesInternal)); } @@ -326,7 +334,7 @@ internal DiscordChannel(List? ignored = null) this._permissionOverwritesLazy = new(() => new ReadOnlyCollection(this.PermissionOverwritesInternal)); } - #region Methods +#region Methods /// /// Sends a message to this channel. @@ -340,7 +348,7 @@ internal DiscordChannel(List? ignored = null) public Task SendMessageAsync(string content) => !this.IsWritable() ? throw new ArgumentException("Cannot send a text message to a non-text channel.") - : this.Discord.ApiClient.CreateMessageAsync(this.Id, content, null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + : this.Discord.ApiClient.CreateMessageAsync(this.Id, content, null, null, null, false, false); /// /// Sends a message to this channel. @@ -354,7 +362,12 @@ public Task SendMessageAsync(string content) => public Task SendMessageAsync(DiscordEmbed embed) => !this.IsWritable() ? throw new ArgumentException("Cannot send a text message to a non-text channel.") - : this.Discord.ApiClient.CreateMessageAsync(this.Id, null, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + : this.Discord.ApiClient.CreateMessageAsync(this.Id, null, embed != null + ? new[] + { + embed + } + : null, null, null, false, false); /// /// Sends a message to this channel. @@ -369,7 +382,12 @@ public Task SendMessageAsync(DiscordEmbed embed) => public Task SendMessageAsync(string content, DiscordEmbed embed) => !this.IsWritable() ? throw new ArgumentException("Cannot send a text message to a non-text channel.") - : this.Discord.ApiClient.CreateMessageAsync(this.Id, content, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: null, mentionReply: false, failOnInvalidReply: false); + : this.Discord.ApiClient.CreateMessageAsync(this.Id, content, embed != null + ? new[] + { + embed + } + : null, null, null, false, false); /// /// Sends a message to this channel. @@ -397,7 +415,6 @@ public Task SendMessageAsync(Action actio var builder = new DiscordMessageBuilder(); action(builder); - return !this.IsWritable() ? throw new ArgumentException("Cannot send a text message to a non-text channel.") : this.Discord.ApiClient.CreateMessageAsync(this.Id, builder); @@ -443,13 +460,9 @@ public async Task CloneAsync(string reason = null) } if (this.Type == ChannelType.Stage) - { userLimit = null; - } if (!this.IsWritable()) - { perUserRateLimit = Optional.None; - } return await this.Guild.CreateChannelAsync(this.Name, this.Type, this.Parent, this.Topic, bitrate, userLimit, ovrs, this.IsNsfw, perUserRateLimit, this.QualityMode, this.DefaultAutoArchiveDuration, this.Flags, reason).ConfigureAwait(false); } @@ -542,8 +555,8 @@ public Task ModifyForumAsync(Action action) return mdl.AvailableTags.HasValue && mdl.AvailableTags.Value.Count > 20 ? throw new NotSupportedException("Cannot have more than 20 tags in a forum channel.") : (Task)this.Discord.ApiClient.ModifyForumChannelAsync(this.Id, mdl.Name, mdl.Position, mdl.Topic, mdl.Template, mdl.Nsfw, - mdl.Parent.Map(p => p?.Id), mdl.AvailableTags, mdl.DefaultReactionEmoji, mdl.PerUserRateLimit, mdl.PostCreateUserRateLimit, - mdl.DefaultSortOrder, mdl.DefaultAutoArchiveDuration, mdl.PermissionOverwrites, mdl.Flags, mdl.AuditLogReason); + mdl.Parent.Map(p => p?.Id), mdl.AvailableTags, mdl.DefaultReactionEmoji, mdl.PerUserRateLimit, mdl.PostCreateUserRateLimit, + mdl.DefaultSortOrder, mdl.DefaultAutoArchiveDuration, mdl.PermissionOverwrites, mdl.Flags, mdl.AuditLogReason); } /// @@ -572,7 +585,11 @@ public Task ModifyPositionAsync(int position, string reason = null) .Select(x => new RestGuildChannelReorderPayload { ChannelId = x.Id, - Position = x.Id == this.Id ? position : x.Position >= position ? x.Position + 1 : x.Position + Position = x.Id == this.Id + ? position + : x.Position >= position + ? x.Position + 1 + : x.Position }); return this.Discord.ApiClient.ModifyGuildChannelPositionAsync(this.Guild.Id, pmds, reason); @@ -629,7 +646,9 @@ public async Task ModifyPositionInCategoryAsync(int position, string reason = nu ? position : isUp ? x.Position <= position && x.Position > this.Position ? x.Position - 1 : x.Position - : x.Position >= position && x.Position < this.Position ? x.Position + 1 : x.Position + : x.Position >= position && x.Position < this.Position + ? x.Position + 1 + : x.Position } ); @@ -653,15 +672,14 @@ internal void Initialize(BaseDiscordClient client) xo.Discord = this.Discord; xo.ChannelId = this.Id; } + if (this.InternalAvailableTags != null) - { foreach (var xo in this.InternalAvailableTags) { xo.Discord = this.Discord; xo.ChannelId = this.Id; xo.Channel = this; } - } } /// @@ -735,9 +753,8 @@ public Task ModifyParentAsync(DiscordChannel newParent, bool? lockPermissions = if (newParent.Type is not ChannelType.Category) throw new ArgumentException("Only category type channels can be parents."); - var position = this.Guild.ChannelsInternal.Values.Where(xc => xc.Type == this.Type && xc.ParentId == newParent.Id) // gets list same type channels in parent - .Select(xc => xc.Position).DefaultIfEmpty(-1).Max() + 1; // returns highest position of list +1, default val: 0 + .Select(xc => xc.Position).DefaultIfEmpty(-1).Max() + 1; // returns highest position of list +1, default val: 0 var pmds = this.Guild.ChannelsInternal.Values.Where(xc => xc.Type == this.Type) .OrderBy(xc => xc.Position) @@ -745,8 +762,7 @@ public Task ModifyParentAsync(DiscordChannel newParent, bool? lockPermissions = { var pmd = new RestGuildChannelNewParentPayload { - ChannelId = x.Id, - Position = x.Position >= position ? x.Position + 1 : x.Position, + ChannelId = x.Id, Position = x.Position >= position ? x.Position + 1 : x.Position }; if (x.Id == this.Id) { @@ -780,16 +796,17 @@ public Task RemoveParentAsync(string reason = null) .OrderBy(xc => xc.Position) .Select(x => { - var pmd = new RestGuildChannelNoParentPayload { ChannelId = x.Id }; + var pmd = new RestGuildChannelNoParentPayload + { + ChannelId = x.Id + }; if (x.Id == this.Id) { pmd.Position = 1; pmd.ParentId = null; } else - { pmd.Position = x.Position < this.Position ? x.Position + 1 : x.Position; - } return pmd; }); @@ -890,8 +907,7 @@ private async Task> GetMessagesInternalAsync(int l msgs.InsertRange(0, fetch); last = fetch.FirstOrDefault()?.Id; } - } - while (remaining > 0 && lastCount > 0); + } while (remaining > 0 && lastCount > 0); return new ReadOnlyCollection(msgs); } @@ -964,8 +980,7 @@ public Task> GetInvitesAsync() => public Task CreateInviteAsync(int maxAge = 86400, int maxUses = 0, bool temporary = false, bool unique = false, TargetType? targetType = null, ulong? targetApplicationId = null, ulong? targetUser = null, string reason = null) => this.Discord.ApiClient.CreateChannelInviteAsync(this.Id, maxAge, maxUses, targetType, targetApplicationId, targetUser, temporary, unique, reason); - - #region Voice Channel +#region Voice Channel /// /// Sets a voice channels status. @@ -988,9 +1003,10 @@ public Task SetVoiceChannelStatusAsync(string status) public Task RemoveVoiceChannelStatusAsync(string reason = null) => this.Type != ChannelType.Voice ? throw new NotSupportedException("Cannot execute this request on a non-voice channel.") : this.Discord.ApiClient.ModifyVoiceChannelStatusAsync(this.Id, null); - #endregion +#endregion + +#region Stage - #region Stage /// /// Opens a stage. /// @@ -1040,9 +1056,9 @@ public async Task CloseStageAsync(string reason = null) public async Task GetStageAsync() => await this.Discord.ApiClient.GetStageInstanceAsync(this.Id).ConfigureAwait(false); - #endregion +#endregion - #region Scheduled Events +#region Scheduled Events /// /// Creates a scheduled event based on the channel type. @@ -1066,9 +1082,9 @@ public async Task CreateScheduledEventAsync(string name, return await this.Guild.CreateScheduledEventAsync(name, scheduledStartTime, null, this, null, description, type, coverImage, reason).ConfigureAwait(false); } - #endregion +#endregion - #region Threads +#region Threads /// /// Creates a thread. @@ -1114,7 +1130,8 @@ public async Task CreateThreadAsync(string name, ThreadAut /// Thrown when the guild hasn't enabled threads atm. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public async Task CreatePostAsync(string name, DiscordMessageBuilder builder, int? rateLimitPerUser = null, IEnumerable? tags = null, string reason = null) => this.Type != ChannelType.Forum ? throw new NotSupportedException("Parent channel must be forum.") : await this.Discord.ApiClient.CreateThreadAsync(this.Id, null, name, null, null, rateLimitPerUser, tags, builder, true, reason).ConfigureAwait(false); + public async Task CreatePostAsync(string name, DiscordMessageBuilder builder, int? rateLimitPerUser = null, IEnumerable? tags = null, string reason = null) + => this.Type != ChannelType.Forum ? throw new NotSupportedException("Parent channel must be forum.") : await this.Discord.ApiClient.CreateThreadAsync(this.Id, null, name, null, null, rateLimitPerUser, tags, builder, true, reason).ConfigureAwait(false); /// /// Gets joined archived private threads. Can contain more threads. @@ -1181,6 +1198,7 @@ public ForumPostTag GetForumPostTag(ulong id) tag.Discord = this.Discord; tag.ChannelId = this.Id; } + return tag; } @@ -1196,17 +1214,18 @@ public ForumPostTag GetForumPostTag(ulong id) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public async Task CreateForumPostTagAsync(string name, DiscordEmoji emoji = null, bool moderated = false, string reason = null) - => this.Type != ChannelType.Forum ? throw new NotSupportedException("Channel needs to be type of Forum") : - this.AvailableTags.Count == 20 ? - throw new NotSupportedException("Cannot have more than 20 tags in a forum channel.") : - await this.Discord.ApiClient.ModifyForumChannelAsync(this.Id, null, null, Optional.None, Optional.None, null, Optional.None, this.InternalAvailableTags.Append(new() - { - Name = name, - EmojiId = emoji != null && emoji.Id != 0 ? emoji.Id : null, - UnicodeEmojiString = emoji?.Id == null || emoji?.Id == 0 ? emoji?.Name ?? null : null, - Moderated = moderated, - Id = null - }).ToList(), Optional.None, Optional.None, Optional.None, Optional.None, Optional.None, null, Optional.None, reason).ConfigureAwait(false); + => this.Type != ChannelType.Forum + ? throw new NotSupportedException("Channel needs to be type of Forum") + : this.AvailableTags.Count == 20 + ? throw new NotSupportedException("Cannot have more than 20 tags in a forum channel.") + : await this.Discord.ApiClient.ModifyForumChannelAsync(this.Id, null, null, Optional.None, Optional.None, null, Optional.None, this.InternalAvailableTags.Append(new() + { + Name = name, + EmojiId = emoji != null && emoji.Id != 0 ? emoji.Id : null, + UnicodeEmojiString = emoji?.Id == null || emoji?.Id == 0 ? emoji?.Name ?? null : null, + Moderated = moderated, + Id = null + }).ToList(), Optional.None, Optional.None, Optional.None, Optional.None, Optional.None, null, Optional.None, reason).ConfigureAwait(false); /// /// Deletes a forum channel tag. @@ -1220,7 +1239,7 @@ await this.Discord.ApiClient.ModifyForumChannelAsync(this.Id, null, null, Option public async Task DeleteForumPostTag(ulong id, string reason = null) => this.Type != ChannelType.Forum ? throw new NotSupportedException("Channel needs to be type of Forum") : await this.Discord.ApiClient.ModifyForumChannelAsync(this.Id, null, null, Optional.None, Optional.None, null, Optional.None, this.InternalAvailableTags?.Where(x => x.Id != id)?.ToList(), Optional.None, Optional.None, Optional.None, Optional.None, Optional.None, null, Optional.None, reason).ConfigureAwait(false); - #endregion +#endregion /// /// Adds a channel permission overwrite for specified role. @@ -1236,7 +1255,6 @@ public async Task DeleteForumPostTag(ulong id, string reason = n public Task AddOverwriteAsync(DiscordRole role, Permissions allow = Permissions.None, Permissions deny = Permissions.None, string reason = null) => this.Discord.ApiClient.EditChannelPermissionsAsync(this.Id, role.Id, allow, deny, "role", reason); - /// /// Adds a channel permission overwrite for specified member. /// @@ -1462,9 +1480,11 @@ public override string ToString() => ? $"Channel #{this.Name} ({this.Id})" : this.IsVoiceJoinable() ? $"Channel #!{this.Name} ({this.Id})" - : !string.IsNullOrWhiteSpace(this.Name) ? $"Channel {this.Name} ({this.Id})" : $"Channel {this.Id}"; + : !string.IsNullOrWhiteSpace(this.Name) + ? $"Channel {this.Name} ({this.Id})" + : $"Channel {this.Id}"; - #endregion +#endregion /// /// Checks whether this is equal to another object. @@ -1500,7 +1520,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Channel/DiscordGuildDirectoryChannel.cs b/DisCatSharp/Entities/Channel/DiscordGuildDirectoryChannel.cs index 031147c2c4..4e5db9068a 100644 --- a/DisCatSharp/Entities/Channel/DiscordGuildDirectoryChannel.cs +++ b/DisCatSharp/Entities/Channel/DiscordGuildDirectoryChannel.cs @@ -21,9 +21,9 @@ internal DiscordGuildDirectoryChannel() public IReadOnlyList Entries => this.Guild.ChannelsInternal.Values.Where(e => e.ParentId == this.Id).Select(x => x as DiscordGuildDirectoryEntry).ToList(); - #region Methods +#region Methods - #endregion +#endregion /// /// Checks whether this is equal to another object. @@ -59,7 +59,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Channel/DiscordGuildDirectoryEntry.cs b/DisCatSharp/Entities/Channel/DiscordGuildDirectoryEntry.cs index 466d556341..d52958537b 100644 --- a/DisCatSharp/Entities/Channel/DiscordGuildDirectoryEntry.cs +++ b/DisCatSharp/Entities/Channel/DiscordGuildDirectoryEntry.cs @@ -11,7 +11,6 @@ namespace DisCatSharp.Entities; /// public class DiscordGuildDirectoryEntry : DiscordChannel, IEquatable { - /// /// Gets the description of the directory entry. /// @@ -30,9 +29,9 @@ public class DiscordGuildDirectoryEntry : DiscordChannel, IEquatable /// Checks whether this is equal to another object. @@ -68,7 +67,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwrite.cs b/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwrite.cs index 2434c03298..d10c969b3d 100644 --- a/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwrite.cs +++ b/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwrite.cs @@ -34,7 +34,7 @@ public class DiscordOverwrite : SnowflakeObject [JsonIgnore] internal ulong ChannelId; - #region Methods +#region Methods /// /// Deletes this channel overwrite. @@ -91,7 +91,7 @@ public async Task GetRoleAsync() => public DiscordOverwriteBuilder ConvertToBuilder() => new(this); - #endregion +#endregion /// /// Initializes a new instance of the class. @@ -107,7 +107,9 @@ internal DiscordOverwrite() public PermissionLevel CheckPermission(Permissions permission) => (this.Allowed & permission) != 0 ? PermissionLevel.Allowed - : (this.Denied & permission) != 0 ? PermissionLevel.Denied : PermissionLevel.Unset; + : (this.Denied & permission) != 0 + ? PermissionLevel.Denied + : PermissionLevel.Unset; /// /// Automatically converts this to a . diff --git a/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwriteBuilder.cs b/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwriteBuilder.cs index af5c741dc1..d29c9be641 100644 --- a/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwriteBuilder.cs +++ b/DisCatSharp/Entities/Channel/Overwrite/DiscordOverwriteBuilder.cs @@ -157,15 +157,10 @@ public DiscordOverwriteBuilder For(DiscordRole role) /// /// Use this object for creation of new overwrites. internal DiscordRestOverwrite Build() - { - return new() + => new() { - Allow = this.Allowed, - Deny = this.Denied, - Id = this.Target, - Type = this.Type, + Allow = this.Allowed, Deny = this.Denied, Id = this.Target, Type = this.Type }; - } } public static class DiscordOverwriteBuilderExtensions @@ -185,7 +180,10 @@ public static List Merge(this IEnumerable x.Target == target && x.Type == type)) - newList.Add(new() { Type = type, Target = target }); + newList.Add(new() + { + Type = type, Target = target + }); var discordOverwriteBuilder = newList.First(x => x.Target == target && x.Type == type); discordOverwriteBuilder.Allow(allowed); diff --git a/DisCatSharp/Entities/Color/DiscordColor.Colors.cs b/DisCatSharp/Entities/Color/DiscordColor.Colors.cs index 87cce6c09c..77240f1586 100644 --- a/DisCatSharp/Entities/Color/DiscordColor.Colors.cs +++ b/DisCatSharp/Entities/Color/DiscordColor.Colors.cs @@ -1,9 +1,9 @@ - namespace DisCatSharp.Entities; public readonly partial struct DiscordColor { - #region Black and White +#region Black and White + /// /// Represents no color, or integer 0; /// @@ -38,9 +38,11 @@ public readonly partial struct DiscordColor /// Very dark gray, or #666666. /// public static DiscordColor VeryDarkGray { get; } = new(0x666666); - #endregion - #region Discord branding colors +#endregion + +#region Discord branding colors + // See https://discord.com/branding. /// @@ -67,9 +69,11 @@ public readonly partial struct DiscordColor /// Discord Red, or #ED4245. /// public static DiscordColor Red { get; } = new(0xED4245); - #endregion - #region Other colors +#endregion + +#region Other colors + /// /// Dark red, or #7F0000. /// @@ -217,5 +221,6 @@ public readonly partial struct DiscordColor /// Sienna, or #882D17. /// public static DiscordColor Sienna { get; } = new(0x882D17); - #endregion + +#endregion } diff --git a/DisCatSharp/Entities/Color/DiscordColor.cs b/DisCatSharp/Entities/Color/DiscordColor.cs index 36cf08d7a7..31013e3108 100644 --- a/DisCatSharp/Entities/Color/DiscordColor.cs +++ b/DisCatSharp/Entities/Color/DiscordColor.cs @@ -9,7 +9,10 @@ namespace DisCatSharp.Entities; /// public partial struct DiscordColor { - private static readonly char[] s_hexAlphabet = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + private static readonly char[] s_hexAlphabet = new[] + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; /// /// Gets the integer representation of this color. @@ -20,13 +23,13 @@ public partial struct DiscordColor /// Gets the red component of this color as an 8-bit integer. /// public byte R - => (byte)((this.Value >> 16) & 0xFF); + => (byte)(this.Value >> 16 & 0xFF); /// /// Gets the green component of this color as an 8-bit integer. /// public byte G - => (byte)((this.Value >> 8) & 0xFF); + => (byte)(this.Value >> 8 & 0xFF); /// /// Gets the blue component of this color as an 8-bit integer. @@ -51,7 +54,7 @@ public DiscordColor(int color) /// Value of the blue component. public DiscordColor(byte r, byte g, byte b) { - this.Value = (r << 16) | (g << 8) | b; + this.Value = r << 16 | g << 8 | b; } /// @@ -69,7 +72,7 @@ public DiscordColor(float r, float g, float b) var gb = (byte)(g * 255); var bb = (byte)(b * 255); - this.Value = (rb << 16) | (gb << 8) | bb; + this.Value = rb << 16 | gb << 8 | bb; } /// diff --git a/DisCatSharp/Entities/DCS/DisCatSharpTeam.cs b/DisCatSharp/Entities/DCS/DisCatSharpTeam.cs index 06dd2de3be..b9d8e00187 100644 --- a/DisCatSharp/Entities/DCS/DisCatSharpTeam.cs +++ b/DisCatSharp/Entities/DCS/DisCatSharpTeam.cs @@ -154,7 +154,6 @@ internal static async Task Get(HttpClient http, ILogger logger, team.Add(owner); } else - { team.Add(new() { Id = user.Id, @@ -164,7 +163,6 @@ internal static async Task Get(HttpClient http, ILogger logger, BannerHash = tuser.BannerHash, BannerColorInternal = tuser.BannerColorInternal }); - } } dcst.Owner = owner; diff --git a/DisCatSharp/Entities/DiscordLocales.cs b/DisCatSharp/Entities/DiscordLocales.cs index 8514453a8f..27898f8bfd 100644 --- a/DisCatSharp/Entities/DiscordLocales.cs +++ b/DisCatSharp/Entities/DiscordLocales.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Entities; public static class DiscordLocales diff --git a/DisCatSharp/Entities/DiscordProtocol.cs b/DisCatSharp/Entities/DiscordProtocol.cs index 05ea21ef8e..420982aa54 100644 --- a/DisCatSharp/Entities/DiscordProtocol.cs +++ b/DisCatSharp/Entities/DiscordProtocol.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Entities; /// @@ -6,9 +5,9 @@ namespace DisCatSharp.Entities; /// public class DiscordProtocol { - #region Properties +#region Properties - #endregion +#endregion /// /// Initializes a new instance of the class. @@ -16,7 +15,7 @@ public class DiscordProtocol public DiscordProtocol() { } - #region Methods +#region Methods - #endregion +#endregion } diff --git a/DisCatSharp/Entities/DiscordUri.cs b/DisCatSharp/Entities/DiscordUri.cs index 5c5f5bae6d..cd6dff1717 100644 --- a/DisCatSharp/Entities/DiscordUri.cs +++ b/DisCatSharp/Entities/DiscordUri.cs @@ -97,18 +97,22 @@ internal sealed class DiscordUriJsonConverter : JsonConverter /// The object type. /// The existing value. /// The serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) + public override object ReadJson( + JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer + ) { var val = reader.Value; return val == null ? null : val is not string s - ? throw new JsonReaderException("DiscordUri value invalid format! This is a bug in DisCatSharp. " + - $"Include the type in your bug report: [[{reader.TokenType}]]") - : IsStandard(s) - ? new(new Uri(s)) - : new DiscordUri(s); + ? throw new JsonReaderException("DiscordUri value invalid format! This is a bug in DisCatSharp. " + + $"Include the type in your bug report: [[{reader.TokenType}]]") + : IsStandard(s) + ? new(new Uri(s)) + : new DiscordUri(s); } /// diff --git a/DisCatSharp/Entities/Embed/DiscordEmbed.cs b/DisCatSharp/Entities/Embed/DiscordEmbed.cs index 0783e7f2ff..94dd7d324a 100644 --- a/DisCatSharp/Entities/Embed/DiscordEmbed.cs +++ b/DisCatSharp/Entities/Embed/DiscordEmbed.cs @@ -49,6 +49,7 @@ public Optional Color [JsonProperty("color", NullValueHandling = NullValueHandling.Include)] internal Optional ColorInternal; + [JsonIgnore] private readonly Lazy> _colorLazy; diff --git a/DisCatSharp/Entities/Embed/DiscordEmbedBuilder.cs b/DisCatSharp/Entities/Embed/DiscordEmbedBuilder.cs index e9ff37c88b..481df91bd5 100644 --- a/DisCatSharp/Entities/Embed/DiscordEmbedBuilder.cs +++ b/DisCatSharp/Entities/Embed/DiscordEmbedBuilder.cs @@ -22,9 +22,11 @@ public string Title { if (value != null && value.Length > 256) throw new ArgumentException("Title length cannot exceed 256 characters.", nameof(value)); + this._title = value; } } + private string _title; /// @@ -37,9 +39,11 @@ public string Description { if (value != null && value.Length > 4096) throw new ArgumentException("Description length cannot exceed 4096 characters.", nameof(value)); + this._description = value; } } + private string _description; /// @@ -50,6 +54,7 @@ public string Url get => this._url?.ToString(); set => this._url = string.IsNullOrEmpty(value) ? null : new Uri(value); } + private Uri _url; /// @@ -70,6 +75,7 @@ public string ImageUrl get => this._imageUri?.ToString(); set => this._imageUri = string.IsNullOrEmpty(value) ? null : new DiscordUri(value); } + private DiscordUri _imageUri; /// @@ -91,6 +97,7 @@ public string ImageUrl /// Gets the embed's fields. /// public IReadOnlyList Fields { get; } + private readonly List _fields = new(); /// @@ -118,24 +125,19 @@ public DiscordEmbedBuilder(DiscordEmbed original) if (original.Thumbnail != null) this.Thumbnail = new() { - Url = original.Thumbnail.Url?.ToString(), - Height = original.Thumbnail.Height, - Width = original.Thumbnail.Width + Url = original.Thumbnail.Url?.ToString(), Height = original.Thumbnail.Height, Width = original.Thumbnail.Width }; if (original.Author != null) this.Author = new() { - IconUrl = original.Author.IconUrl?.ToString(), - Name = original.Author.Name, - Url = original.Author.Url?.ToString() + IconUrl = original.Author.IconUrl?.ToString(), Name = original.Author.Name, Url = original.Author.Url?.ToString() }; if (original.Footer != null) this.Footer = new() { - IconUrl = original.Footer.IconUrl?.ToString(), - Text = original.Footer.Text + IconUrl = original.Footer.IconUrl?.ToString(), Text = original.Footer.Text }; if (original.Fields?.Any() == true) @@ -266,9 +268,7 @@ public DiscordEmbedBuilder WithThumbnail(string url, int height = 0, int width = { this.Thumbnail = new() { - Url = url, - Height = height, - Width = width + Url = url, Height = height, Width = width }; return this; @@ -285,9 +285,7 @@ public DiscordEmbedBuilder WithThumbnail(Uri url, int height = 0, int width = 0) { this.Thumbnail = new() { - Uri = new(url), - Height = height, - Width = width + Uri = new(url), Height = height, Width = width }; return this; @@ -304,13 +302,12 @@ public DiscordEmbedBuilder WithAuthor(string name = null, string url = null, str { if (!string.IsNullOrEmpty(name) && name.Length > 256) throw new NotSupportedException("Embed author name can not exceed 256 chars. See https://discord.com/developers/docs/resources/channel#embed-limits."); + this.Author = string.IsNullOrEmpty(name) && string.IsNullOrEmpty(url) && string.IsNullOrEmpty(iconUrl) ? null : new EmbedAuthor { - Name = name, - Url = url, - IconUrl = iconUrl + Name = name, Url = url, IconUrl = iconUrl }; return this; } @@ -330,8 +327,7 @@ public DiscordEmbedBuilder WithFooter(string text = null, string iconUrl = null) ? null : new EmbedFooter { - Text = text, - IconUrl = iconUrl + Text = text, IconUrl = iconUrl }; return this; } @@ -451,39 +447,35 @@ public DiscordEmbed Build() if (this.Footer != null) embed.Footer = new() { - Text = this.Footer.Text, - IconUrl = this.Footer.IconUri + Text = this.Footer.Text, IconUrl = this.Footer.IconUri }; if (this.Author != null) embed.Author = new() { - Name = this.Author.Name, - Url = this.Author.Uri, - IconUrl = this.Author.IconUri + Name = this.Author.Name, Url = this.Author.Uri, IconUrl = this.Author.IconUri }; if (this._imageUri != null) - embed.Image = new() { Url = this._imageUri }; + embed.Image = new() + { + Url = this._imageUri + }; if (this.Thumbnail != null) embed.Thumbnail = new() { - Url = this.Thumbnail.Uri, - Height = this.Thumbnail.Height, - Width = this.Thumbnail.Width + Url = this.Thumbnail.Uri, Height = this.Thumbnail.Height, Width = this.Thumbnail.Width }; embed.Fields = new ReadOnlyCollection(new List(this._fields)); // copy the list, don't wrap it, prevents mutation var charCount = 0; if (embed.Fields.Any()) - { foreach (var field in embed.Fields) { charCount += field.Name.Length; charCount += field.Value.Length; } - } if (embed.Author != null && !string.IsNullOrEmpty(embed.Author.Name)) charCount += embed.Author.Name.Length; @@ -524,9 +516,11 @@ public string Name { if (value != null && value.Length > 256) throw new ArgumentException("Author name length cannot exceed 256 characters.", nameof(value)); + this._name = value; } } + private string _name; /// @@ -537,6 +531,7 @@ public string Url get => this.Uri?.ToString(); set => this.Uri = string.IsNullOrEmpty(value) ? null : new Uri(value); } + internal Uri Uri; /// @@ -547,6 +542,7 @@ public string IconUrl get => this.IconUri?.ToString(); set => this.IconUri = string.IsNullOrEmpty(value) ? null : new DiscordUri(value); } + internal DiscordUri IconUri; } @@ -565,9 +561,11 @@ public string Text { if (value != null && value.Length > 2048) throw new ArgumentException("Footer text length cannot exceed 2048 characters.", nameof(value)); + this._text = value; } } + private string _text; /// @@ -578,6 +576,7 @@ public string IconUrl get => this.IconUri?.ToString(); set => this.IconUri = string.IsNullOrEmpty(value) ? null : new DiscordUri(value); } + internal DiscordUri IconUri; } @@ -594,6 +593,7 @@ public string Url get => this.Uri?.ToString(); set => this.Uri = string.IsNullOrEmpty(value) ? null : new DiscordUri(value); } + internal DiscordUri Uri; /// @@ -604,6 +604,7 @@ public int Height get => this._height; set => this._height = value >= 0 ? value : 0; } + private int _height; /// @@ -614,6 +615,7 @@ public int Width get => this._width; set => this._width = value >= 0 ? value : 0; } + private int _width; } } diff --git a/DisCatSharp/Entities/Embed/DiscordEmbedField.cs b/DisCatSharp/Entities/Embed/DiscordEmbedField.cs index f14d31dea8..c18b9cf3cb 100644 --- a/DisCatSharp/Entities/Embed/DiscordEmbedField.cs +++ b/DisCatSharp/Entities/Embed/DiscordEmbedField.cs @@ -25,6 +25,7 @@ public string Name { if (value == null) throw new ArgumentNullException(nameof(value)); + throw new ArgumentException("Name cannot be empty or whitespace.", nameof(value)); } @@ -51,6 +52,7 @@ public string Value { if (value == null) throw new ArgumentNullException(nameof(value)); + throw new ArgumentException("Value cannot be empty or whitespace.", nameof(value)); } diff --git a/DisCatSharp/Entities/Emoji/DiscordEmoji.EmojiUtils.cs b/DisCatSharp/Entities/Emoji/DiscordEmoji.EmojiUtils.cs index 6af437c696..41b916cd56 100644 --- a/DisCatSharp/Entities/Emoji/DiscordEmoji.EmojiUtils.cs +++ b/DisCatSharp/Entities/Emoji/DiscordEmoji.EmojiUtils.cs @@ -22,7 +22,8 @@ public partial class DiscordEmoji /// static DiscordEmoji() { - #region Generated Emoji Map +#region Generated Emoji Map + s_unicodeEmojis = new Dictionary { [":100:"] = "\U0001f4af", @@ -6676,7 +6677,7 @@ static DiscordEmoji() [":zipper_mouth:"] = "\U0001f910", [":zipper_mouth_face:"] = "\U0001f910", [":zombie:"] = "\U0001f9df", - [":zzz:"] = "\U0001f4a4", + [":zzz:"] = "\U0001f4a4" }; s_discordNameLookup = new Dictionary @@ -10119,8 +10120,9 @@ static DiscordEmoji() ["\u0030\u20e3"] = ":zero:", ["\U0001f910"] = ":zipper_mouth:", ["\U0001f9df"] = ":zombie:", - ["\U0001f4a4"] = ":zzz:", + ["\U0001f4a4"] = ":zzz:" }; - #endregion + +#endregion } } diff --git a/DisCatSharp/Entities/Emoji/DiscordEmoji.cs b/DisCatSharp/Entities/Emoji/DiscordEmoji.cs index 30d5c3cc98..7fe057657a 100644 --- a/DisCatSharp/Entities/Emoji/DiscordEmoji.cs +++ b/DisCatSharp/Entities/Emoji/DiscordEmoji.cs @@ -126,7 +126,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(DiscordEmoji e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id && this.Name == e.Name)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id && this.Name == e.Name); /// /// Gets the hash code for this . @@ -135,8 +135,8 @@ public bool Equals(DiscordEmoji e) public override int GetHashCode() { var hash = 13; - hash = (hash * 7) + this.Id.GetHashCode(); - hash = (hash * 7) + this.Name.GetHashCode(); + hash = hash * 7 + this.Id.GetHashCode(); + hash = hash * 7 + this.Name.GetHashCode(); return hash; } @@ -158,7 +158,7 @@ internal string ToReactionString() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || (e1.Id == e2.Id && e1.Name == e2.Name)); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id && e1.Name == e2.Name); } /// @@ -194,7 +194,10 @@ public static bool IsValidUnicode(string unicodeEntity) public static DiscordEmoji FromUnicode(BaseDiscordClient client, string unicodeEntity) => !IsValidUnicode(unicodeEntity) ? throw new ArgumentException("Specified unicode entity is not a valid unicode emoji.", nameof(unicodeEntity)) - : new DiscordEmoji { Name = unicodeEntity, Discord = client }; + : new DiscordEmoji + { + Name = unicodeEntity, Discord = client + }; /// /// Creates an emoji object from a unicode entity. @@ -223,7 +226,10 @@ public static bool TryFromUnicode(BaseDiscordClient client, string unicodeEntity if (!s_unicodeEmojis.TryGetValue(discordName, out unicodeEntity)) return false; - emoji = new() { Name = unicodeEntity, Discord = client }; + emoji = new() + { + Name = unicodeEntity, Discord = client + }; return true; } @@ -248,10 +254,8 @@ public static DiscordEmoji FromGuildEmote(BaseDiscordClient client, ulong id) throw new ArgumentNullException(nameof(client), "Client cannot be null."); foreach (var guild in client.Guilds.Values) - { if (guild.Emojis.TryGetValue(id, out var found)) return found; - } throw new KeyNotFoundException("Given emote was not found."); } @@ -269,10 +273,8 @@ public static bool TryFromGuildEmote(BaseDiscordClient client, ulong id, out Dis throw new ArgumentNullException(nameof(client), "Client cannot be null."); foreach (var guild in client.Guilds.Values) - { if (guild.Emojis.TryGetValue(id, out emoji)) return true; - } emoji = null; return false; @@ -296,7 +298,10 @@ public static DiscordEmoji FromName(BaseDiscordClient client, string name, bool throw new ArgumentNullException(nameof(name), "Name cannot be empty or null."); if (s_unicodeEmojis.TryGetValue(name, out var unicodeEntity)) - return new() { Discord = client, Name = unicodeEntity }; + return new() + { + Discord = client, Name = unicodeEntity + }; if (includeGuilds) { @@ -344,7 +349,10 @@ public static bool TryFromName(BaseDiscordClient client, string name, bool inclu if (s_unicodeEmojis.TryGetValue(name, out var unicodeEntity)) { - emoji = new() { Discord = client, Name = unicodeEntity }; + emoji = new() + { + Discord = client, Name = unicodeEntity + }; return true; } diff --git a/DisCatSharp/Entities/Emoji/DiscordUnicodeEmoji.cs b/DisCatSharp/Entities/Emoji/DiscordUnicodeEmoji.cs index 87cd4218bf..bd9ecce5a2 100644 --- a/DisCatSharp/Entities/Emoji/DiscordUnicodeEmoji.cs +++ b/DisCatSharp/Entities/Emoji/DiscordUnicodeEmoji.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Entities; /// diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ApplicationCommandPermissionUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ApplicationCommandPermissionUpdateChangeSet.cs new file mode 100644 index 0000000000..032993333e --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ApplicationCommandPermissionUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating permissions for an application command. +/// +public sealed class ApplicationCommandPermissionUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationBlockMessageChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationBlockMessageChangeSet.cs new file mode 100644 index 0000000000..902b6ea8ea --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationBlockMessageChangeSet.cs @@ -0,0 +1,43 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a message being blocked by Auto Moderation. +/// +public sealed class AutoModerationBlockMessageChangeSet : DiscordAuditLogEntry +{ + public AutoModerationBlockMessageChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationBlockMessage; + } + + /// + /// The rule's name that blocked the message. + /// + public string RuleName => this.Options.AutoModerationRuleName; + + /// + /// What type of filter the rule uses. + /// + public AutomodTriggerType? TriggerType => this.Options.AutoModerationRuleTriggerType; + + /// + /// The channel's id in which the rule triggered. + /// + public ulong? ChannelId => this.Options.ChannelId!.Value; + + /// + /// The channel in which the rule triggered. + /// + public DiscordChannel Channel => this.Options.Channel; + + /// + /// The member that was timed out. + /// + public DiscordMember TargetMember => this.Discord.Guilds[this.GuildId].Members[this.TargetId.Value!]; + + /// + internal override string? ChangeDescription + => $"Automod blocked a message from being sended in {this.Channel} from {this.TargetMember} for reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationFlagToChannelChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationFlagToChannelChangeSet.cs new file mode 100644 index 0000000000..f317abfa14 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationFlagToChannelChangeSet.cs @@ -0,0 +1,43 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a message being flagged by Auto Moderation. +/// +public sealed class AutoModerationFlagToChannelChangeSet : DiscordAuditLogEntry +{ + public AutoModerationFlagToChannelChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationFlagToChannel; + } + + /// + /// The rule's name that blocked the message. + /// + public string RuleName => this.Options.AutoModerationRuleName; + + /// + /// What type of filter the rule uses. + /// + public AutomodTriggerType? TriggerType => this.Options.AutoModerationRuleTriggerType; + + /// + /// The channel's id in which the rule triggered. + /// + public ulong? ChannelId => this.Options.ChannelId!.Value; + + /// + /// The channel in which the rule triggered. + /// + public DiscordChannel Channel => this.Options.Channel; + + /// + /// The member that was timed out. + /// + public DiscordMember TargetMember => this.Discord.Guilds[this.GuildId].Members[this.TargetId.Value!]; + + /// + internal override string? ChangeDescription + => $"Automod flagged a message in {this.Channel} from {this.TargetMember} for reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleCreateChangeSet.cs new file mode 100644 index 0000000000..ec01c5e310 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleCreateChangeSet.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating an Auto Moderation rule. +/// +public sealed class AutoModerationRuleCreateChangeSet : DiscordAuditLogEntry +{ + public AutoModerationRuleCreateChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationRuleCreate; + } + + public bool Enabled => (bool)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.NewValue; + public string RuleName => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public AutomodTriggerType TriggerType => (AutomodTriggerType)this.Changes.FirstOrDefault(x => x.Key == "trigger_type")?.NewValue; + public AutomodEventType EventType => (AutomodEventType)this.Changes.FirstOrDefault(x => x.Key == "event_type")?.NewValue; + public AutomodAction[] Actions => (AutomodAction[])this.Changes.FirstOrDefault(x => x.Key == "actions")?.NewValue; + public AutomodTriggerMetadata TriggerMetadata => (AutomodTriggerMetadata)this.Changes.FirstOrDefault(x => x.Key == "trigger_metadata")?.NewValue; + + public IReadOnlyList? ExemptRoleIds => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_roles")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptRoles => this.ExemptRoleIds.Select(x => this.Discord.Guilds[this.GuildId].Roles[x]); + + public IReadOnlyList? ExemptChannelIds => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_channels")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptChannels => this.ExemptChannelIds.Select(x => this.Discord.Guilds[this.GuildId].Channels[x]); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleDeleteChangeSet.cs new file mode 100644 index 0000000000..56ef5d9379 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleDeleteChangeSet.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting an Auto Moderation rule. +/// +public sealed class AutoModerationRuleDeleteChangeSet : DiscordAuditLogEntry +{ + public AutoModerationRuleDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationRuleDelete; + } + + public bool Enabled => (bool)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.OldValue; + public string RuleName => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public AutomodTriggerType TriggerType => (AutomodTriggerType)this.Changes.FirstOrDefault(x => x.Key == "trigger_type")?.OldValue; + public AutomodEventType EventType => (AutomodEventType)this.Changes.FirstOrDefault(x => x.Key == "event_type")?.OldValue; + public AutomodAction[] Actions => (AutomodAction[])this.Changes.FirstOrDefault(x => x.Key == "actions")?.OldValue; + public AutomodTriggerMetadata TriggerMetadata => (AutomodTriggerMetadata)this.Changes.FirstOrDefault(x => x.Key == "trigger_metadata")?.OldValue; + + public IReadOnlyList? ExemptRoleIds => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_roles")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptRoles => this.ExemptRoleIds.Select(x => this.Discord.Guilds[this.GuildId].Roles[x]); + + public IReadOnlyList? ExemptChannelIds => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_channels")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptChannels => this.ExemptChannelIds.Select(x => this.Discord.Guilds[this.GuildId].Channels[x]); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleUpdateChangeSet.cs new file mode 100644 index 0000000000..ffa94d5d80 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationRuleUpdateChangeSet.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating an Auto Moderation rule. +/// +public sealed class AutoModerationRuleUpdateChangeSet : DiscordAuditLogEntry +{ + public AutoModerationRuleUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationRuleUpdate; + } + + public bool EnabledChanged => this.EnabledBefore is not null || this.EnabledAfter is not null; + public bool? EnabledBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.OldValue; + public bool? EnabledAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.NewValue; + + public bool RuleNameChanged => this.RuleNameBefore is not null || this.RuleNameAfter is not null; + public string? RuleNameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? RuleNameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool TriggerTypeChanged => this.TriggerTypeBefore is not null || this.TriggerTypeAfter is not null; + public AutomodTriggerType? TriggerTypeBefore => (AutomodTriggerType?)this.Changes.FirstOrDefault(x => x.Key == "trigger_type")?.OldValue; + public AutomodTriggerType? TriggerTypeAfter => (AutomodTriggerType?)this.Changes.FirstOrDefault(x => x.Key == "trigger_type")?.NewValue; + + public bool EventTypeChanged => this.EventTypeBefore is not null || this.EventTypeAfter is not null; + public AutomodEventType? EventTypeBefore => (AutomodEventType?)this.Changes.FirstOrDefault(x => x.Key == "event_type")?.OldValue; + public AutomodEventType? EventTypeAfter => (AutomodEventType?)this.Changes.FirstOrDefault(x => x.Key == "event_type")?.NewValue; + + public bool ActionsChanged => this.ActionsBefore is not null || this.ActionsAfter is not null; + public AutomodAction[]? ActionsBefore => (AutomodAction[]?)this.Changes.FirstOrDefault(x => x.Key == "actions")?.OldValue; + public AutomodAction[]? ActionsAfter => (AutomodAction[]?)this.Changes.FirstOrDefault(x => x.Key == "actions")?.NewValue; + + public bool TriggerMetadataChanged => this.TriggerMetadataBefore is not null || this.TriggerMetadataAfter is not null; + public AutomodTriggerMetadata? TriggerMetadataBefore => (AutomodTriggerMetadata?)this.Changes.FirstOrDefault(x => x.Key == "trigger_metadata")?.OldValue; + public AutomodTriggerMetadata? TriggerMetadataAfter => (AutomodTriggerMetadata?)this.Changes.FirstOrDefault(x => x.Key == "trigger_metadata")?.NewValue; + + public bool ExemptRoleIdsChanged => this.ExemptRoleIdsBefore is not null || this.ExemptRoleIdsAfter is not null; + public IReadOnlyList? ExemptRoleIdsBefore => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_roles")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IReadOnlyList? ExemptRoleIdsAfter => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_roles")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptRolesBefore => this.ExemptRoleIdsBefore.Select(x => this.Discord.Guilds[this.GuildId].Roles[x]); + public IEnumerable ExemptRolesAfter => this.ExemptRoleIdsAfter.Select(x => this.Discord.Guilds[this.GuildId].Roles[x]); + + public bool ExemptChannelIdsChanged => this.ExemptChannelIdsBefore is not null || this.ExemptChannelIdsAfter is not null; + public IReadOnlyList? ExemptChannelIdsBefore => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_channels")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IReadOnlyList? ExemptChannelIdsAfter => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "exempt_channels")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IEnumerable ExemptChannelsBefore => this.ExemptChannelIdsBefore.Select(x => this.Discord.Guilds[this.GuildId].Channels[x]); + public IEnumerable ExemptChannelsAfter => this.ExemptChannelIdsAfter.Select(x => this.Discord.Guilds[this.GuildId].Channels[x]); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationUserCommunicationDisabledChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationUserCommunicationDisabledChangeSet.cs new file mode 100644 index 0000000000..13ce46df72 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/AutoModerationUserCommunicationDisabledChangeSet.cs @@ -0,0 +1,43 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a member being timed out by Auto Moderation. +/// +public sealed class AutoModerationUserCommunicationDisabledChangeSet : DiscordAuditLogEntry +{ + public AutoModerationUserCommunicationDisabledChangeSet() + { + this.ValidFor = AuditLogActionType.AutoModerationUserCommunicationDisabled; + } + + /// + /// The rule's name that blocked the message and triggered the timeout. + /// + public string RuleName => this.Options!.AutoModerationRuleName; + + /// + /// What type of filter the rule uses. + /// + public AutomodTriggerType? TriggerType => this.Options!.AutoModerationRuleTriggerType; + + /// + /// The channel's id in which the rule triggered. + /// + public ulong? ChannelId => this.Options!.ChannelId!.Value; + + /// + /// The channel in which the rule triggered. + /// + public DiscordChannel? Channel => this.Options!.Channel; + + /// + /// The member that was timed out. + /// + public DiscordMember TargetMember => this.Discord.Guilds[this.GuildId].Members[this.TargetId.Value!]; + + /// + internal override string? ChangeDescription + => $"Automod timed out {this.TargetMember} for reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/BotAddChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/BotAddChangeSet.cs new file mode 100644 index 0000000000..97e7919911 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/BotAddChangeSet.cs @@ -0,0 +1,23 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for adding a bot user to the server. +/// +public sealed class BotAddChangeSet : DiscordAuditLogEntry +{ + public BotAddChangeSet() + { + this.ValidFor = AuditLogActionType.BotAdd; + } + + /// + /// Gets the bot user that was added. + /// + public DiscordUser Bot => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + /// + internal override string? ChangeDescription + => $"{this.User} added {this.Bot}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelCreateChangeSet.cs new file mode 100644 index 0000000000..c33808b9bc --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelCreateChangeSet.cs @@ -0,0 +1,139 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a new channel creation. +/// +public sealed class ChannelCreateChangeSet : DiscordAuditLogEntry +{ + public ChannelCreateChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelCreate; + } + + /// + /// Gets the Discord channel associated with this change. + /// + public DiscordChannel Channel => this.Discord.Guilds[this.GuildId].Channels[this.TargetId!.Value]; + + /// + /// Gets the new name of the channel. + /// + public string Name => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + /// + /// Gets the type of the channel. + /// + public ChannelType Type => (ChannelType)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + + /// + /// Gets the new topic of the channel. + /// + public string? Topic => (string?)this.Changes.FirstOrDefault(x => x.Key == "topic")?.NewValue; + + /// + /// Gets the new position of the channel. + /// + public int? Position => (int?)this.Changes.FirstOrDefault(x => x.Key == "position")?.NewValue; + + /// + /// Gets the new permission overwrites for the channel. + /// + public DiscordOverwrite[] PermissionOverwrites => (DiscordOverwrite[])this.Changes.FirstOrDefault(x => x.Key == "permission_overwrites")?.NewValue; + + /// + /// Gets a value indicating whether the channel is marked as NSFW (Not Safe For Work). + /// + public bool IsNfsw => (bool)this.Changes.FirstOrDefault(x => x.Key == "nsfw")?.NewValue; + + /// + /// Gets the new rate limit per user for the channel. + /// + public int PerUserRateLimit => (int)this.Changes.FirstOrDefault(x => x.Key == "rate_limit_per_user")?.NewValue; + + /// + /// Gets the new icon emoji for the channel. + /// + public DiscordEmoji? IconEmoji => (DiscordEmoji?)this.Changes.FirstOrDefault(x => x.Key == "icon_emoji")?.NewValue; + + /// + /// Gets the new default auto-archive duration for the channel. + /// + public ThreadAutoArchiveDuration? DefaultAutoArchiveDuration => (ThreadAutoArchiveDuration?)this.Changes.FirstOrDefault(x => x.Key == "default_auto_archive_duration")?.NewValue; + + /// + /// Gets the new flags for the channel. + /// + public ChannelFlags Flags => (ChannelFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; + + /// + /// Gets the new parent ID for the channel. + /// + public ulong? ParentId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "parent_id")?.NewValue; + + /// + /// Gets the parent channel of this channel, if it has one. + /// + public DiscordChannel? Parent => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ParentId ?? 0ul, out var channel) ? channel : null; + +#region Voice + + /// + /// Gets the new bitrate for the voice channel. + /// + public int? Bitrate => (int?)this.Changes.FirstOrDefault(x => x.Key == "bitrate")?.NewValue; + + /// + /// Gets the new user limit for the voice channel. + /// + public int? UserLimit => (int?)this.Changes.FirstOrDefault(x => x.Key == "user_limit")?.NewValue; + + /// + /// Gets the new RTC (Real-Time Communication) region ID for the voice channel. + /// + public string? RtcRegionId => (string?)this.Changes.FirstOrDefault(x => x.Key == "rtc_region")?.NewValue; + + /// + /// Gets the RTC region associated with the voice channel. + /// + public DiscordVoiceRegion? RtcRegion => this.Discord.VoiceRegions[this.RtcRegionId]; + + /// + /// Gets the new video quality mode for the voice channel. + /// + public VideoQualityMode? VideoQualityMode => (VideoQualityMode?)this.Changes.FirstOrDefault(x => x.Key == "video_quality_mode")?.NewValue; + +#endregion + +#region Forum + + /// + /// Gets the new available tags for the forum channel. + /// + public ForumPostTag? AvailableTags => (ForumPostTag?)this.Changes.FirstOrDefault(x => x.Key == "available_tags")?.NewValue; + + /// + /// Gets the new default reaction emoji for the forum channel. + /// + public ForumReactionEmoji? DefaultReactionEmoji => (ForumReactionEmoji?)this.Changes.FirstOrDefault(x => x.Key == "default_reaction_emoji")?.NewValue; + + /// + /// Gets the new default sort order for the forum channel. + /// + public ForumPostSortOrder? DefaultSortOrder => (ForumPostSortOrder?)this.Changes.FirstOrDefault(x => x.Key == "default_sort_order")?.NewValue; + + /// + /// Gets the new default layout for the forum channel. + /// + public ForumLayout? DefaultLayout => (ForumLayout?)this.Changes.FirstOrDefault(x => x.Key == "default_forum_layout")?.NewValue; + + /// + /// Gets the new default thread per user rate limit for the forum channel. + /// + public int? DefaultThreadPerUserRateLimit => (int?)this.Changes.FirstOrDefault(x => x.Key == "default_thread_rate_limit_per_user")?.NewValue; + +#endregion +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelDeleteChangeSet.cs new file mode 100644 index 0000000000..1c0d8a216c --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelDeleteChangeSet.cs @@ -0,0 +1,134 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a channel deletion. +/// +public sealed class ChannelDeleteChangeSet : DiscordAuditLogEntry +{ + public ChannelDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelDelete; + } + + /// + /// Gets the old name of the deleted channel. + /// + public string Name => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + + /// + /// Gets the old type of the deleted channel. + /// + public ChannelType Type => (ChannelType)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + + /// + /// Gets the old topic of the deleted channel. + /// + public string? Topic => (string?)this.Changes.FirstOrDefault(x => x.Key == "topic")?.OldValue; + + /// + /// Gets the old position of the deleted channel. + /// + public int? Position => (int?)this.Changes.FirstOrDefault(x => x.Key == "position")?.OldValue; + + /// + /// Gets the old permission overwrites of the deleted channel. + /// + public DiscordOverwrite[] PermissionOverwrites => (DiscordOverwrite[])this.Changes.FirstOrDefault(x => x.Key == "permission_overwrites")?.OldValue; + + /// + /// Gets a value indicating whether the deleted channel was marked as NSFW. + /// + public bool IsNfsw => (bool)this.Changes.FirstOrDefault(x => x.Key == "nsfw")?.OldValue; + + /// + /// Gets the old per-user rate limit of the deleted channel. + /// + public int PerUserRateLimit => (int)this.Changes.FirstOrDefault(x => x.Key == "rate_limit_per_user")?.OldValue; + + /// + /// Gets the old icon emoji of the deleted channel. + /// + public DiscordEmoji? IconEmoji => (DiscordEmoji?)this.Changes.FirstOrDefault(x => x.Key == "icon_emoji")?.OldValue; + + /// + /// Gets the old default auto-archive duration of the deleted channel. + /// + public ThreadAutoArchiveDuration? DefaultAutoArchiveDuration => (ThreadAutoArchiveDuration?)this.Changes.FirstOrDefault(x => x.Key == "default_auto_archive_duration")?.OldValue; + + /// + /// Gets the old flags of the deleted channel. + /// + public ChannelFlags Flags => (ChannelFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + + /// + /// Gets the old parent ID of the deleted channel. + /// + public ulong? ParentId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "parent_id")?.OldValue; + + /// + /// Gets the old parent channel of the deleted channel. + /// + public DiscordChannel? Parent => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ParentId ?? 0ul, out var channel) ? channel : null; + +#region Voice + + /// + /// Gets the old bitrate of the deleted voice channel. + /// + public int? Bitrate => (int?)this.Changes.FirstOrDefault(x => x.Key == "bitrate")?.OldValue; + + /// + /// Gets the old user limit of the deleted voice channel. + /// + public int? UserLimit => (int?)this.Changes.FirstOrDefault(x => x.Key == "user_limit")?.OldValue; + + /// + /// Gets the old RTC region ID of the deleted voice channel. + /// + public string? RtcRegionId => (string?)this.Changes.FirstOrDefault(x => x.Key == "rtc_region")?.OldValue; + + /// + /// Gets the old RTC region of the deleted voice channel. + /// + public DiscordVoiceRegion? RtcRegion => this.Discord.VoiceRegions[this.RtcRegionId]; + + /// + /// Gets the old video quality mode of the deleted voice channel. + /// + public VideoQualityMode? VideoQualityMode => (VideoQualityMode?)this.Changes.FirstOrDefault(x => x.Key == "video_quality_mode")?.OldValue; + +#endregion + +#region Forum + + /// + /// Gets the old available tags of the deleted forum channel. + /// + public ForumPostTag? AvailableTags => (ForumPostTag?)this.Changes.FirstOrDefault(x => x.Key == "available_tags")?.OldValue; + + /// + /// Gets the old default reaction emoji of the deleted forum channel. + /// + public ForumReactionEmoji? DefaultReactionEmoji => (ForumReactionEmoji?)this.Changes.FirstOrDefault(x => x.Key == "default_reaction_emoji")?.OldValue; + + /// + /// Gets the old default sort order of the deleted forum channel. + /// + public ForumPostSortOrder? DefaultSortOrder => (ForumPostSortOrder?)this.Changes.FirstOrDefault(x => x.Key == "default_sort_order")?.OldValue; + + /// + /// Gets the old default forum layout of the deleted forum channel. + /// + public ForumLayout? DefaultLayout => (ForumLayout?)this.Changes.FirstOrDefault(x => x.Key == "default_forum_layout")?.OldValue; + + /// + /// Gets the old default thread per-user rate limit of the deleted forum channel. + /// + public int? DefaultThreadPerUserRateLimit => (int?)this.Changes.FirstOrDefault(x => x.Key == "default_thread_rate_limit_per_user")?.OldValue; + +#endregion +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteCreateChangeSet.cs new file mode 100644 index 0000000000..faff5721e1 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteCreateChangeSet.cs @@ -0,0 +1,41 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for adding a permission overwrite to a channel. +/// +public sealed class ChannelOverwriteCreateChangeSet : DiscordAuditLogEntry +{ + public ChannelOverwriteCreateChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelOverwriteCreate; + } + + /// + /// Gets the allowed permissions after the change. + /// + public Permissions? Allowed => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "allow")?.NewValue; + + /// + /// Gets the denied permissions after the change. + /// + public Permissions? Denied => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "deny")?.NewValue; + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} executed {this.GetType().Name.Replace("ChangeSet", string.Empty)} for {this.Options!.OverwrittenEntityType} with id{this.Options.OverwrittenEntityId} {(this.Options.OverwrittenEntityType == OverwriteType.Role ? $" and name {this.Options.RoleName}" : string.Empty)} with reason {this.Reason ?? $"No reason given".Italic()}\n"; + + description += this.Allowed is not null ? $"- Set Allowed Permissions to {this.Allowed}\n" : "- No Allowed Permissions\n"; + + description += this.Denied is not null ? $"- Set Denied Permissions to {this.Denied}\n" : "- No Denied Permissions\n"; + + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteDeleteChangeSet.cs new file mode 100644 index 0000000000..c626b556c0 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteDeleteChangeSet.cs @@ -0,0 +1,26 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a permission overwrite from a channel. +/// +public sealed class ChannelOverwriteDeleteChangeSet : DiscordAuditLogEntry +{ + public ChannelOverwriteDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelOverwriteDelete; + } + + /// + /// Gets the allowed permissions before the change. + /// + public Permissions? Allowed => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "allow")?.OldValue; + + /// + /// Gets the denied permissions before the change. + /// + public Permissions? Denied => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "deny")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteUpdateChangeSet.cs new file mode 100644 index 0000000000..f278421ab0 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelOverwriteUpdateChangeSet.cs @@ -0,0 +1,63 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a permission overwrite for a channel. +/// +public sealed class ChannelOverwriteUpdateChangeSet : DiscordAuditLogEntry +{ + public ChannelOverwriteUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelOverwriteUpdate; + } + + /// + /// Gets a value indicating whether the allowed permissions have changed. + /// + public bool AllowChanged => this.AllowBefore is not null || this.AllowAfter is not null; + + /// + /// Gets the old allowed permissions before the change. + /// + public Permissions? AllowBefore => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "allow")?.OldValue; + + /// + /// Gets the new allowed permissions after the change. + /// + public Permissions? AllowAfter => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "allow")?.NewValue; + + /// + /// Gets a value indicating whether the denied permissions have changed. + /// + public bool DenyChanged => this.DenyBefore is not null || this.DenyAfter is not null; + + /// + /// Gets the old denied permissions before the change. + /// + public Permissions? DenyBefore => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "deny")?.OldValue; + + /// + /// Gets the new denied permissions after the change. + /// + public Permissions? DenyAfter => (Permissions?)this.Changes.FirstOrDefault(x => x.Key == "deny")?.NewValue; + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} executed {this.GetType().Name.Replace("ChangeSet", string.Empty)} for {this.Options!.OverwrittenEntityType} with id{this.Options.OverwrittenEntityId} {(this.Options.OverwrittenEntityType == OverwriteType.Role ? $" and name {this.Options.RoleName}" : string.Empty)} with reason {this.Reason ?? $"No reason given".Italic()}\n"; + + if (this.AllowChanged) + description += this.AllowAfter is not null ? $"- Set Allowed Permissions to {this.AllowAfter}\n" : "- Unset Allowed Permissions\n"; + + if (this.DenyChanged) + description += this.DenyAfter is not null ? $"- Set Denied Permissions to {this.DenyAfter}\n" : "- Unset Denied Permissions\n"; + + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelUpdateChangeSet.cs new file mode 100644 index 0000000000..c492356dfd --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ChannelUpdateChangeSet.cs @@ -0,0 +1,334 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating channel settings. +/// +public sealed class ChannelUpdateChangeSet : DiscordAuditLogEntry +{ + public ChannelUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.ChannelUpdate; + } + + /// + /// Gets the Discord channel associated with this change. + /// + public DiscordChannel Channel => this.Discord.Guilds[this.GuildId].Channels[this.TargetId!.Value]; + + /// + /// Gets a value indicating whether the channel's name was changed. + /// + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + + /// + /// Gets the previous name of the channel. + /// + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + + /// + /// Gets the new name of the channel. + /// + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + /// + /// Gets a value indicating whether the channel's type was changed. + /// + public bool TypeChanged => this.TypeBefore is not null || this.TypeAfter is not null; + + /// + /// Gets the previous type of the channel. + /// + public ChannelType? TypeBefore => (ChannelType?)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + + /// + /// Gets the new type of the channel. + /// + public ChannelType? TypeAfter => (ChannelType?)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + + /// + /// Gets a value indicating whether the channel's topic was changed. + /// + public bool TopicChanged => this.TopicBefore is not null || this.TopicAfter is not null; + + /// + /// Gets the previous topic of the channel. + /// + public string? TopicBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "topic")?.OldValue; + + /// + /// Gets the new topic of the channel. + /// + public string? TopicAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "topic")?.NewValue; + + /// + /// Gets a value indicating whether the channel's position was changed. + /// + public bool PositionChanged => this.PositionBefore is not null || this.PositionAfter is not null; + + /// + /// Gets the previous position of the channel. + /// + public int? PositionBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "position")?.OldValue; + + /// + /// Gets the new position of the channel. + /// + public int? PositionAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "position")?.NewValue; + + /// + /// Gets a value indicating whether the channel's NSFW status was changed. + /// + public bool IsNfswChanged => this.IsNfswBefore is not null || this.IsNfswAfter is not null; + + /// + /// Gets the previous NSFW status of the channel. + /// + public bool? IsNfswBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "nsfw")?.OldValue; + + /// + /// Gets the new NSFW status of the channel. + /// + public bool? IsNfswAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "nsfw")?.NewValue; + + /// + /// Gets a value indicating whether the channel's rate limit per user was changed. + /// + public bool PerUserRateLimitChanged => this.PerUserRateLimitBefore is not null || this.PerUserRateLimitAfter is not null; + + /// + /// Gets the previous rate limit per user of the channel. + /// + public int? PerUserRateLimitBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "rate_limit_per_user")?.OldValue; + + /// + /// Gets the new rate limit per user of the channel. + /// + public int? PerUserRateLimitAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "rate_limit_per_user")?.NewValue; + + /// + /// Gets a value indicating whether the channel's icon emoji was changed. + /// + public bool IconEmojiChanged => this.IconEmojiBefore is not null || this.IconEmojiAfter is not null; + + /// + /// Gets the previous icon emoji of the channel. + /// + public DiscordEmoji? IconEmojiBefore => (DiscordEmoji?)this.Changes.FirstOrDefault(x => x.Key == "icon_emoji")?.OldValue; + + /// + /// Gets the new icon emoji of the channel. + /// + public DiscordEmoji? IconEmojiAfter => (DiscordEmoji?)this.Changes.FirstOrDefault(x => x.Key == "icon_emoji")?.NewValue; + + /// + /// Gets a value indicating whether the channel's default auto-archive duration was changed. + /// + public bool DefaultAutoArchiveDurationChanged => this.DefaultAutoArchiveDurationBefore is not null || this.DefaultAutoArchiveDurationAfter is not null; + + /// + /// Gets the previous default auto-archive duration of the channel. + /// + public ThreadAutoArchiveDuration? DefaultAutoArchiveDurationBefore => (ThreadAutoArchiveDuration?)this.Changes.FirstOrDefault(x => x.Key == "default_auto_archive_duration")?.OldValue; + + /// + /// Gets the new default auto-archive duration of the channel. + /// + public ThreadAutoArchiveDuration? DefaultAutoArchiveDurationAfter => (ThreadAutoArchiveDuration?)this.Changes.FirstOrDefault(x => x.Key == "default_auto_archive_duration")?.NewValue; + + /// + /// Gets a value indicating whether the channel's flags were changed. + /// + public bool FlagsChanged => this.FlagsBefore is not null || this.FlagsAfter is not null; + + /// + /// Gets the previous flags of the channel. + /// + public ChannelFlags? FlagsBefore => (ChannelFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + + /// + /// Gets the new flags of the channel. + /// + public ChannelFlags? FlagsAfter => (ChannelFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; + + /// + /// Gets a value indicating whether the channel's parent ID was changed. + /// + public bool ParentIdChanged => this.ParentIdBefore is not null || this.ParentIdAfter is not null; + + /// + /// Gets the previous parent ID of the channel. + /// + public ulong? ParentIdBefore => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "parent_id")?.OldValue; + + /// + /// Gets the new parent ID of the channel. + /// + public ulong? ParentIdAfter => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "parent_id")?.NewValue; + + /// + /// Gets the previous parent channel of the channel. + /// + public DiscordChannel? ParentBefore => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ParentIdBefore ?? 0ul, out var channel) ? channel : null; + + /// + /// Gets the new parent channel of the channel. + /// + public DiscordChannel? ParentAfter => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ParentIdAfter ?? 0ul, out var channel) ? channel : null; + +#region Voice + + /// + /// Gets a value indicating whether the channel's bitrate was changed. + /// + public bool BitrateChanged => this.BitrateBefore is not null || this.BitrateAfter is not null; + + /// + /// Gets the previous bitrate of the channel. + /// + public int? BitrateBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "bitrate")?.OldValue; + + /// + /// Gets the new bitrate of the channel. + /// + public int? BitrateAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "bitrate")?.NewValue; + + /// + /// Gets a value indicating whether the channel's user limit was changed. + /// + public bool UserLimitChanged => this.UserLimitBefore is not null || this.UserLimitAfter is not null; + + /// + /// Gets the previous user limit of the channel. + /// + public int? UserLimitBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "user_limit")?.OldValue; + + /// + /// Gets the new user limit of the channel. + /// + public int? UserLimitAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "user_limit")?.NewValue; + + /// + /// Gets a value indicating whether the channel's RTC region ID was changed. + /// + public bool RtcRegionIdChanged => this.RtcRegionIdBefore is not null || this.RtcRegionIdAfter is not null; + + /// + /// Gets the previous RTC region ID of the channel. + /// + public string? RtcRegionIdBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "rtc_region")?.OldValue; + + /// + /// Gets the new RTC region ID of the channel. + /// + public string? RtcRegionIdAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "rtc_region")?.NewValue; + + /// + /// Gets the previous RTC region of the channel. + /// + public DiscordVoiceRegion? RtcRegionBefore => this.Discord.VoiceRegions[this.RtcRegionIdBefore]; + + /// + /// Gets the new RTC region of the channel. + /// + public DiscordVoiceRegion? RtcRegionAfter => this.Discord.VoiceRegions[this.RtcRegionIdAfter]; + + /// + /// Gets a value indicating whether the channel's video quality mode was changed. + /// + public bool VideoQualityModeChanged => this.VideoQualityModeBefore is not null || this.VideoQualityModeAfter is not null; + + /// + /// Gets the previous video quality mode of the channel. + /// + public VideoQualityMode? VideoQualityModeBefore => (VideoQualityMode?)this.Changes.FirstOrDefault(x => x.Key == "video_quality_mode")?.OldValue; + + /// + /// Gets the new video quality mode of the channel. + /// + public VideoQualityMode? VideoQualityModeAfter => (VideoQualityMode?)this.Changes.FirstOrDefault(x => x.Key == "video_quality_mode")?.NewValue; + +#endregion + +#region Forum + + /// + /// Gets a value indicating whether the available tags for forum posts were changed. + /// + public bool AvailableTagsChanged => this.AvailableTagsBefore is not null || this.AvailableTagsAfter is not null; + + /// + /// Gets the previous available tags for forum posts. + /// + public ForumPostTag? AvailableTagsBefore => (ForumPostTag?)this.Changes.FirstOrDefault(x => x.Key == "available_tags")?.OldValue; + + /// + /// Gets the new available tags for forum posts. + /// + public ForumPostTag? AvailableTagsAfter => (ForumPostTag?)this.Changes.FirstOrDefault(x => x.Key == "available_tags")?.NewValue; + + /// + /// Gets a value indicating whether the default reaction emoji for forum posts was changed. + /// + public bool DefaultReactionEmojiChanged => this.DefaultReactionEmojiBefore is not null || this.DefaultReactionEmojiAfter is not null; + + /// + /// Gets the previous default reaction emoji for forum posts. + /// + public ForumReactionEmoji? DefaultReactionEmojiBefore => (ForumReactionEmoji?)this.Changes.FirstOrDefault(x => x.Key == "default_reaction_emoji")?.OldValue; + + /// + /// Gets the new default reaction emoji for forum posts. + /// + public ForumReactionEmoji? DefaultReactionEmojiAfter => (ForumReactionEmoji?)this.Changes.FirstOrDefault(x => x.Key == "default_reaction_emoji")?.NewValue; + + /// + /// Gets a value indicating whether the default sort order for forum posts was changed. + /// + public bool DefaultSortOrderChanged => this.DefaultSortOrderBefore is not null || this.DefaultSortOrderAfter is not null; + + /// + /// Gets the previous default sort order for forum posts. + /// + public ForumPostSortOrder? DefaultSortOrderBefore => (ForumPostSortOrder?)this.Changes.FirstOrDefault(x => x.Key == "default_sort_order")?.OldValue; + + /// + /// Gets the new default sort order for forum posts. + /// + public ForumPostSortOrder? DefaultSortOrderAfter => (ForumPostSortOrder?)this.Changes.FirstOrDefault(x => x.Key == "default_sort_order")?.NewValue; + + /// + /// Gets a value indicating whether the default layout for forum posts was changed. + /// + public bool DefaultLayoutChanged => this.DefaultLayoutBefore is not null || this.DefaultLayoutAfter is not null; + + /// + /// Gets the previous default layout for forum posts. + /// + public ForumLayout? DefaultLayoutBefore => (ForumLayout?)this.Changes.FirstOrDefault(x => x.Key == "default_forum_layout")?.OldValue; + + /// + /// Gets the new default layout for forum posts. + /// + public ForumLayout? DefaultLayoutAfter => (ForumLayout?)this.Changes.FirstOrDefault(x => x.Key == "default_forum_layout")?.NewValue; + + /// + /// Gets a value indicating whether the default thread rate limit per user for forum posts was changed. + /// + public bool DefaultThreadPerUserRateLimitChanged => this.DefaultThreadPerUserRateLimitBefore is not null || this.DefaultThreadPerUserRateLimitAfter is not null; + + /// + /// Gets the previous default thread rate limit per user for forum posts. + /// + public int? DefaultThreadPerUserRateLimitBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "default_thread_rate_limit_per_user")?.OldValue; + + /// + /// Gets the new default thread rate limit per user for forum posts. + /// + public int? DefaultThreadPerUserRateLimitAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "default_thread_rate_limit_per_user")?.NewValue; + +#endregion +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ClydeUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ClydeUpdateChangeSet.cs new file mode 100644 index 0000000000..04d70c2018 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/ClydeUpdateChangeSet.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating clyde in the server. +/// +public sealed class ClydeUpdateChangeSet : DiscordAuditLogEntry +{ + public ClydeUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.ClydeAIProfileUpdate; + } + + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool AvatarHashChanged => this.AvatarHashBefore is not null || this.AvatarHashAfter is not null; + public string? AvatarHashBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.OldValue; + public string? AvatarHashAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.NewValue; + + public bool BannerHashChanged => this.BannerHashBefore is not null || this.BannerHashAfter is not null; + public string? BannerHashBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "banner_hash")?.OldValue; + public string? BannerHashAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "banner_hash")?.NewValue; + + public bool BioChanged => this.BioBefore is not null || this.BioAfter is not null; + public string? BioBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "bio")?.OldValue; + public string? BioAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "bio")?.NewValue; + + public bool PersonalityChanged => this.PersonalityBefore is not null || this.PersonalityAfter is not null; + public string? PersonalityBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "personality")?.OldValue; + public string? PersonalityAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "personality")?.NewValue; + + public bool ClydeProfileIdChanged => this.ClydeProfileIdBefore is not null || this.ClydeProfileIdAfter is not null; + public ulong? ClydeProfileIdBefore => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "clyde_profile_id")?.OldValue; + public ulong? ClydeProfileIdAfter => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "clyde_profile_id")?.NewValue; + + public bool ThemeColorsChanged => this.ThemeColorIntsBefore is not null || this.ThemeColorIntsAfter is not null; + public List? ThemeColorIntsBefore => (List?)this.Changes.FirstOrDefault(x => x.Key == "theme_colors")?.OldValue; + public IReadOnlyList? ThemeColoreBefore => !(this.ThemeColorIntsBefore is not null && this.ThemeColorIntsBefore.Count != 0) ? null : this.ThemeColorIntsBefore.Select(x => new DiscordColor(x)).ToList(); + public List? ThemeColorIntsAfter => (List?)this.Changes.FirstOrDefault(x => x.Key == "theme_colors")?.NewValue; + public IReadOnlyList? ThemeColorsAfter => !(this.ThemeColorIntsAfter is not null && this.ThemeColorIntsAfter.Count != 0) ? null : this.ThemeColorIntsAfter.Select(x => new DiscordColor(x)).ToList(); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationRequestCreatedChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationRequestCreatedChangeSet.cs new file mode 100644 index 0000000000..93376a3872 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationRequestCreatedChangeSet.cs @@ -0,0 +1,18 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for the creation of a creator monetization request. +/// +public sealed class CreatorMonetizationRequestCreatedChangeSet : DiscordAuditLogEntry +{ + public CreatorMonetizationRequestCreatedChangeSet() + { + this.ValidFor = AuditLogActionType.CreatorMonetizationRequestCreated; + } + + /// + internal override string? ChangeDescription + => $"{this.User} created Creator Monetization Request"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationTermsAcceptedChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationTermsAcceptedChangeSet.cs new file mode 100644 index 0000000000..da1ca4b5a1 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/CreatorMonetizationTermsAcceptedChangeSet.cs @@ -0,0 +1,18 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for the acceptance of creator monetization terms. +/// +public sealed class CreatorMonetizationTermsAcceptedChangeSet : DiscordAuditLogEntry +{ + public CreatorMonetizationTermsAcceptedChangeSet() + { + this.ValidFor = AuditLogActionType.CreatorMonetizationTermsAccepted; + } + + /// + internal override string? ChangeDescription + => $"{this.User} accepted Creator Monetization Terms"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiCreateChangeSet.cs new file mode 100644 index 0000000000..61242a433b --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiCreateChangeSet.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating an emoji. +/// +public sealed class EmojiCreateChangeSet : DiscordAuditLogEntry +{ + public EmojiCreateChangeSet() + { + this.ValidFor = AuditLogActionType.EmojiCreate; + } + + public string? EmojiName => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public IReadOnlyList? RolesAllowed => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "roles")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public bool EmojiNameChanged => this.EmojiName is not null; + public bool RolesAllowedChanged => this.RolesAllowed is not null; + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} created a new emoji with the following details:\n"; + if (this.EmojiNameChanged) + description += $"- Emoji Name: {this.EmojiName}\n"; + if (this.RolesAllowedChanged) + description += this.RolesAllowed != null && this.RolesAllowed.Any() + ? $"- Roles Allowed: {string.Join(", ", this.RolesAllowed.Select(this.Discord.Guilds[this.GuildId].GetRole))}\n" + : "- Allowed everyone to use the emoji"; + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiDeleteChangeSet.cs new file mode 100644 index 0000000000..81f3ebaea0 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiDeleteChangeSet.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting an emoji. +/// +public sealed class EmojiDeleteChangeSet : DiscordAuditLogEntry +{ + public EmojiDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.EmojiDelete; + } + + public string? EmojiName => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public IReadOnlyList? RolesAllowed => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "roles")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public bool EmojiNameChanged => this.EmojiName is not null; + public bool RolesAllowedChanged => this.RolesAllowed is not null; + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} deleted emoji {this.TargetId}:\n"; + if (this.EmojiNameChanged) + description += $"- Name: {this.EmojiName}\n"; + if (this.RolesAllowedChanged) + description += this.RolesAllowed != null && this.RolesAllowed.Any() + ? $"- Roles Allowed: {string.Join(", ", this.RolesAllowed.Select(this.Discord.Guilds[this.GuildId].GetRole))}\n" + : "- Allowed everyone to use the emoji"; + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiUpdateChangeSet.cs new file mode 100644 index 0000000000..338c01c75e --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/EmojiUpdateChangeSet.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating the name of an emoji. +/// +public sealed class EmojiUpdateChangeSet : DiscordAuditLogEntry +{ + public EmojiUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.EmojiUpdate; + } + + public string? EmojiNameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? EmojiNameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public IReadOnlyList? RolesAllowedBefore => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "roles")?.OldValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public IReadOnlyList? RolesAllowedAfter => ((IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "roles")?.NewValue)?.Select(x => ConvertToUlong(x)!.Value).ToList(); + public bool EmojiNameChanged => this.EmojiNameBefore is not null || this.EmojiNameAfter is not null; + public bool RolesAllowedChanged => this.RolesAllowedBefore is not null || this.RolesAllowedAfter is not null; + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} updated emoji {this.TargetId}:\n"; + if (this.EmojiNameChanged) + { + description += this.EmojiNameBefore is not null ? $"- Emoji Name Before: {this.EmojiNameBefore}\n" : "- Emoji Name Before: Not set\n"; + description += this.EmojiNameAfter is not null ? $"- Emoji Name After: {this.EmojiNameAfter}\n" : "- Emoji Name After: Not set\n"; + } + + if (this.RolesAllowedChanged) + { + description += this.RolesAllowedBefore is not null ? $"- Roles Allowed Before: {string.Join(", ", this.RolesAllowedBefore.Select(this.Discord.Guilds[this.GuildId].GetRole))}\n" : "- Roles Allowed Before: Not set\n"; + description += this.RolesAllowedAfter is not null ? $"- Roles Allowed After: {string.Join(", ", this.RolesAllowedAfter.Select(this.Discord.Guilds[this.GuildId].GetRole))}\n" : "- Roles Allowed After: Not set\n"; + } + + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/GuildUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/GuildUpdateChangeSet.cs new file mode 100644 index 0000000000..67cd61c020 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/GuildUpdateChangeSet.cs @@ -0,0 +1,278 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for a server settings update. +/// +public sealed class GuildUpdateChangeSet : DiscordAuditLogEntry +{ + public GuildUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.GuildUpdate; + } + + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool IconChanged => this.IconBefore is not null || this.IconAfter is not null; + public string? IconBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.OldValue; + public string? IconAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.NewValue; + + public bool SplashChanged => this.SplashBefore is not null || this.SplashAfter is not null; + public string? SplashBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "splash")?.OldValue; + public string? SplashAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "splash")?.NewValue; + + public bool DiscoverySplashChanged => this.DiscoverySplashBefore is not null || this.DiscoverySplashAfter is not null; + public string? DiscoverySplashBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "discovery_splash")?.OldValue; + public string? DiscoverySplashAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "discovery_splash")?.NewValue; + + public bool OwnerIdChanged => this.OwnerIdBefore is not null || this.OwnerIdAfter is not null; + public ulong? OwnerIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "owner_id")?.OldValue); + public ulong? OwnerIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "owner_id")?.NewValue); + + public bool AfkChannelIdChanged => this.AfkChannelIdBefore is not null || this.AfkChannelIdAfter is not null; + public ulong? AfkChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "afk_channel_id")?.OldValue); + public ulong? AfkChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "afk_channel_id")?.NewValue); + + public bool AfkTimeoutChanged => this.AfkTimeoutBefore is not null || this.AfkTimeoutAfter is not null; + public int? AfkTimeoutBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "afk_timeout")?.OldValue; + public int? AfkTimeoutAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "afk_timeout")?.NewValue; + + public bool WidgetEnabledChanged => this.WidgetEnabledBefore is not null || this.WidgetEnabledAfter is not null; + public bool? WidgetEnabledBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "widget_enabled")?.OldValue; + public bool? WidgetEnabledAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "widget_enabled")?.NewValue; + + public bool WidgetChannelIdChanged => this.WidgetChannelIdBefore is not null || this.WidgetChannelIdAfter is not null; + public ulong? WidgetChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "widget_channel_id")?.OldValue); + public ulong? WidgetChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "widget_channel_id")?.NewValue); + + public bool VerificationLevelChanged => this.VerificationLevelBefore is not null || this.VerificationLevelAfter is not null; + public VerificationLevel? VerificationLevelBefore => (VerificationLevel?)this.Changes.FirstOrDefault(x => x.Key == "verification_level")?.OldValue; + public VerificationLevel? VerificationLevelAfter => (VerificationLevel?)this.Changes.FirstOrDefault(x => x.Key == "verification_level")?.NewValue; + + public bool DefaultMessageNotificationsChanged => this.DefaultMessageNotificationsBefore is not null || this.DefaultMessageNotificationsAfter is not null; + public DefaultMessageNotifications? DefaultMessageNotificationsBefore => (DefaultMessageNotifications?)this.Changes.FirstOrDefault(x => x.Key == "default_message_notifications")?.OldValue; + public DefaultMessageNotifications? DefaultMessageNotificationsAfter => (DefaultMessageNotifications?)this.Changes.FirstOrDefault(x => x.Key == "default_message_notifications")?.NewValue; + + public bool ExplicitContentFilterChanged => this.ExplicitContentFilterBefore is not null || this.ExplicitContentFilterAfter is not null; + public ExplicitContentFilter? ExplicitContentFilterBefore => (ExplicitContentFilter?)this.Changes.FirstOrDefault(x => x.Key == "explicit_content_filter")?.OldValue; + public ExplicitContentFilter? ExplicitContentFilterAfter => (ExplicitContentFilter?)this.Changes.FirstOrDefault(x => x.Key == "explicit_content_filter")?.NewValue; + + public bool FeaturesChanged => this.FeaturesBefore is not null || this.FeaturesAfter is not null; + public IReadOnlyList? FeaturesBefore => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "features")?.OldValue; + public IReadOnlyList? FeaturesAfter => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "features")?.NewValue; + + public bool MfaLevelChanged => this.MfaLevelBefore is not null || this.MfaLevelAfter is not null; + public MfaLevel? MfaLevelBefore => (MfaLevel?)this.Changes.FirstOrDefault(x => x.Key == "mfa_level")?.OldValue; + public MfaLevel? MfaLevelAfter => (MfaLevel?)this.Changes.FirstOrDefault(x => x.Key == "mfa_level")?.NewValue; + + public bool SystemChannelIdChanged => this.SystemChannelIdBefore is not null || this.SystemChannelIdAfter is not null; + public ulong? SystemChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "system_channel_id")?.OldValue); + public ulong? SystemChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "system_channel_id")?.NewValue); + + public bool SystemChannelFlagsChanged => this.SystemChannelFlagsBefore is not null || this.SystemChannelFlagsAfter is not null; + public SystemChannelFlags? SystemChannelFlagsBefore => (SystemChannelFlags?)this.Changes.FirstOrDefault(x => x.Key == "system_channel_flags")?.OldValue; + public SystemChannelFlags? SystemChannelFlagsAfter => (SystemChannelFlags?)this.Changes.FirstOrDefault(x => x.Key == "system_channel_flags")?.NewValue; + + public bool RulesChannelIdChanged => this.RulesChannelIdBefore is not null || this.RulesChannelIdAfter is not null; + public ulong? RulesChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "rules_channel_id")?.OldValue); + public ulong? RulesChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "rules_channel_id")?.NewValue); + + public bool VanityUrlCodeChanged => this.VanityUrlCodeBefore is not null || this.VanityUrlCodeAfter is not null; + public string? VanityUrlCodeBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "vanity_url_code")?.OldValue; + public string? VanityUrlCodeAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "vanity_url_code")?.NewValue; + + public bool DescriptionChanged => this.DescriptionBefore is not null || this.DescriptionAfter is not null; + public string? DescriptionBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "description")?.OldValue; + public string? DescriptionAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "description")?.NewValue; + + public bool BannerChanged => this.BannerBefore is not null || this.BannerAfter is not null; + public string? BannerBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "banner")?.OldValue; + public string? BannerAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "banner")?.NewValue; + + public bool PreferredLocaleChanged => this.PreferredLocaleBefore is not null || this.PreferredLocaleAfter is not null; + public string? PreferredLocaleBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "preferred_locale")?.OldValue; + public string? PreferredLocaleAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "preferred_locale")?.NewValue; + + public bool PublicUpdatesChannelIdChanged => this.PublicUpdatesChannelIdBefore is not null || this.PublicUpdatesChannelIdAfter is not null; + public ulong? PublicUpdatesChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "public_updates_channel_id")?.OldValue); + public ulong? PublicUpdatesChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "public_updates_channel_id")?.NewValue); + + public bool NsfwLevelChanged => this.NsfwLevelBefore is not null || this.NsfwLevelAfter is not null; + public NsfwLevel? NsfwLevelBefore => (NsfwLevel?)this.Changes.FirstOrDefault(x => x.Key == "nsfw_level")?.OldValue; + public NsfwLevel? NsfwLevelAfter => (NsfwLevel?)this.Changes.FirstOrDefault(x => x.Key == "nsfw_level")?.NewValue; + + public bool PremiumProgressBarEnabledChanged => this.PremiumProgressBarEnabledBefore is not null || this.PremiumProgressBarEnabledAfter is not null; + public bool? PremiumProgressBarEnabledBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "premium_progress_bar_enabled")?.OldValue; + public bool? PremiumProgressBarEnabledAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "premium_progress_bar_enabled")?.NewValue; + + public bool SafetyAlertsChannelIdChanged => this.SafetyAlertsChannelIdBefore is not null || this.SafetyAlertsChannelIdAfter is not null; + public ulong? SafetyAlertsChannelIdBefore => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "safety_alerts_channel_id")?.OldValue); + public ulong? SafetyAlertsChannelIdAfter => ConvertToUlong(this.Changes.FirstOrDefault(x => x.Key == "safety_alerts_channel_id")?.NewValue); + + /// + internal override string ChangeDescription + { + get + { + var description = $"{this.User} executed {this.GetType().Name.Replace("ChangeSet", string.Empty)} with reason {this.Reason ?? "No reason given".Italic()}\n"; + + if (this.NameChanged) + { + description += $"Old Name: {this.NameBefore ?? "Not set"}\n"; + description += $"New Name: {this.NameAfter ?? "Not set"}\n"; + } + + if (this.IconChanged) + { + description += $"Old Icon: {this.IconBefore ?? "Not set"}\n"; + description += $"New Icon: {this.IconAfter ?? "Not set"}\n"; + } + + if (this.SplashChanged) + { + description += $"Old Splash: {this.SplashBefore ?? "Not set"}\n"; + description += $"New Splash: {this.SplashAfter ?? "Not set"}\n"; + } + + if (this.DiscoverySplashChanged) + { + description += $"Old Discovery Splash: {this.DiscoverySplashBefore ?? "Not set"}\n"; + description += $"New Discovery Splash: {this.DiscoverySplashAfter ?? "Not set"}\n"; + } + + if (this.OwnerIdChanged) + { + description += $"Old Owner ID: {this.OwnerIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New Owner ID: {this.OwnerIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.AfkChannelIdChanged) + { + description += $"Old AFK Channel ID: {this.AfkChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New AFK Channel ID: {this.AfkChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.AfkTimeoutChanged) + { + description += $"Old AFK Timeout: {this.AfkTimeoutBefore?.ToString() ?? "Not set"} seconds\n"; + description += $"New AFK Timeout: {this.AfkTimeoutAfter?.ToString() ?? "Not set"} seconds\n"; + } + + if (this.WidgetEnabledChanged) + { + description += $"Old Widget Enabled: {this.WidgetEnabledBefore?.ToString() ?? "Not set"}\n"; + description += $"New Widget Enabled: {this.WidgetEnabledAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.WidgetChannelIdChanged) + { + description += $"Old Widget Channel ID: {this.WidgetChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New Widget Channel ID: {this.WidgetChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.VerificationLevelChanged) + { + description += $"Old Verification Level: {this.VerificationLevelBefore?.ToString() ?? "Not set"}\n"; + description += $"New Verification Level: {this.VerificationLevelAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.DefaultMessageNotificationsChanged) + { + description += $"Old Default Message Notifications: {this.DefaultMessageNotificationsBefore?.ToString() ?? "Not set"}\n"; + description += $"New Default Message Notifications: {this.DefaultMessageNotificationsAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.ExplicitContentFilterChanged) + { + description += $"Old Explicit Content Filter: {this.ExplicitContentFilterBefore?.ToString() ?? "Not set"}\n"; + description += $"New Explicit Content Filter: {this.ExplicitContentFilterAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.FeaturesChanged) + { + description += $"Old Features: {string.Join(", ", this.FeaturesBefore ?? new List())}\n"; + description += $"New Features: {string.Join(", ", this.FeaturesAfter ?? new List())}\n"; + } + + if (this.MfaLevelChanged) + { + description += $"Old MFA Level: {this.MfaLevelBefore?.ToString() ?? "Not set"}\n"; + description += $"New MFA Level: {this.MfaLevelAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.SystemChannelIdChanged) + { + description += $"Old System Channel ID: {this.SystemChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New System Channel ID: {this.SystemChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.SystemChannelFlagsChanged) + { + description += $"Old System Channel Flags: {this.SystemChannelFlagsBefore?.ToString() ?? "Not set"}\n"; + description += $"New System Channel Flags: {this.SystemChannelFlagsAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.RulesChannelIdChanged) + { + description += $"Old Rules Channel ID: {this.RulesChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New Rules Channel ID: {this.RulesChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.VanityUrlCodeChanged) + { + description += $"Old Vanity URL Code: {this.VanityUrlCodeBefore ?? "Not set"}\n"; + description += $"New Vanity URL Code: {this.VanityUrlCodeAfter ?? "Not set"}\n"; + } + + if (this.DescriptionChanged) + { + description += $"Old Description: {this.DescriptionBefore ?? "Not set"}\n"; + description += $"New Description: {this.DescriptionAfter ?? "Not set"}\n"; + } + + if (this.BannerChanged) + { + description += $"Old Banner: {this.BannerBefore ?? "Not set"}\n"; + description += $"New Banner: {this.BannerAfter ?? "Not set"}\n"; + } + + if (this.PreferredLocaleChanged) + { + description += $"Old Preferred Locale: {this.PreferredLocaleBefore ?? "Not set"}\n"; + description += $"New Preferred Locale: {this.PreferredLocaleAfter ?? "Not set"}\n"; + } + + if (this.PublicUpdatesChannelIdChanged) + { + description += $"Old Public Updates Channel ID: {this.PublicUpdatesChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New Public Updates Channel ID: {this.PublicUpdatesChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.NsfwLevelChanged) + { + description += $"Old NSFW Level: {this.NsfwLevelBefore?.ToString() ?? "Not set"}\n"; + description += $"New NSFW Level: {this.NsfwLevelAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.PremiumProgressBarEnabledChanged) + { + description += $"Old Premium Progress Bar Enabled: {this.PremiumProgressBarEnabledBefore?.ToString() ?? "Not set"}\n"; + description += $"New Premium Progress Bar Enabled: {this.PremiumProgressBarEnabledAfter?.ToString() ?? "Not set"}\n"; + } + + if (this.SafetyAlertsChannelIdChanged) + { + description += $"Old Safety Alerts Channel ID: {this.SafetyAlertsChannelIdBefore?.ToString() ?? "Not set"}\n"; + description += $"New Safety Alerts Channel ID: {this.SafetyAlertsChannelIdAfter?.ToString() ?? "Not set"}\n"; + } + + return description; + } + } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationCreateChangeSet.cs new file mode 100644 index 0000000000..b41df37b27 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationCreateChangeSet.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for adding an app to the server. +/// +public sealed class IntegrationCreateChangeSet : DiscordAuditLogEntry +{ + public IntegrationCreateChangeSet() + { + this.ValidFor = AuditLogActionType.IntegrationCreate; + } + + public string Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public string Type => (string?)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + public bool? Enabled => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.NewValue; + public bool? Syncing => (bool?)this.Changes.FirstOrDefault(x => x.Key == "syncing")?.NewValue; + + public ulong? RoleId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "role_id")?.NewValue; + public DiscordRole? Role => this.Discord.Guilds[this.GuildId].Roles.TryGetValue(this.RoleId ?? 0ul, out var role) ? role : null; + + public bool? EnableEmoticons => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enable_emoticons")?.NewValue; + public IntegrationExpireBehavior? ExpireBehavior => (IntegrationExpireBehavior?)this.Changes.FirstOrDefault(x => x.Key == "expire_behavior")?.NewValue; + public int? ExpireGracePeriod => (int?)this.Changes.FirstOrDefault(x => x.Key == "expire_grace_period")?.NewValue; + public DiscordUser? Bot => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "user")?.NewValue; + public DiscordIntegrationAccount? Account => (DiscordIntegrationAccount?)this.Changes.FirstOrDefault(x => x.Key == "account")?.NewValue; + public DiscordApplication? Application => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "application")?.NewValue; + public bool? Revoked => (bool?)this.Changes.FirstOrDefault(x => x.Key == "revoked")?.NewValue; + public IReadOnlyList? Scopes => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "scopes")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationDeleteChangeSet.cs new file mode 100644 index 0000000000..45d7870378 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationDeleteChangeSet.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for removing an app from the server. +/// +public sealed class IntegrationDeleteChangeSet : DiscordAuditLogEntry +{ + public IntegrationDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.IntegrationDelete; + } + + public string Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string Type => (string?)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + public bool? Enabled => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.OldValue; + public bool? Syncing => (bool?)this.Changes.FirstOrDefault(x => x.Key == "syncing")?.OldValue; + + public ulong? RoleId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "role_id")?.OldValue; + public DiscordRole? Role => this.Discord.Guilds[this.GuildId].Roles.TryGetValue(this.RoleId ?? 0ul, out var role) ? role : null; + + public bool? EnableEmoticons => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enable_emoticons")?.OldValue; + public IntegrationExpireBehavior? ExpireBehavior => (IntegrationExpireBehavior?)this.Changes.FirstOrDefault(x => x.Key == "expire_behavior")?.OldValue; + public int? ExpireGracePeriod => (int?)this.Changes.FirstOrDefault(x => x.Key == "expire_grace_period")?.OldValue; + public DiscordUser? Bot => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "user")?.OldValue; + public DiscordIntegrationAccount? Account => (DiscordIntegrationAccount?)this.Changes.FirstOrDefault(x => x.Key == "account")?.OldValue; + public DiscordApplication? Application => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "application")?.OldValue; + public bool? Revoked => (bool?)this.Changes.FirstOrDefault(x => x.Key == "revoked")?.OldValue; + public IReadOnlyList? Scopes => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "scopes")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationUpdateChangeSet.cs new file mode 100644 index 0000000000..b3c4855d83 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/IntegrationUpdateChangeSet.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating an app, such as its scopes. +/// +public sealed class IntegrationUpdateChangeSet : DiscordAuditLogEntry +{ + public IntegrationUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.IntegrationUpdate; + } + + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool EnabledChanged => this.EnabledBefore is not null || this.EnabledAfter is not null; + public bool? EnabledBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.OldValue; + public bool? EnabledAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enabled")?.NewValue; + + public bool SyncingChanged => this.SyncingBefore is not null || this.SyncingAfter is not null; + public bool? SyncingBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "syncing")?.OldValue; + public bool? SyncingAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "syncing")?.NewValue; + + public bool RoleIdChanged => this.RoleIdBefore is not null || this.RoleIdAfter is not null; + public ulong? RoleIdBefore => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "role_id")?.OldValue; + public ulong? RoleIdAfter => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "role_id")?.NewValue; + public DiscordRole? RoleBefore => this.Discord.Guilds[this.GuildId].Roles.TryGetValue(this.RoleIdBefore ?? 0ul, out var role) ? role : null; + public DiscordRole? RoleAfter => this.Discord.Guilds[this.GuildId].Roles.TryGetValue(this.RoleIdAfter ?? 0ul, out var role) ? role : null; + + public bool EnableEmoticonsChanged => this.EnableEmoticonsBefore is not null || this.EnableEmoticonsAfter is not null; + public bool? EnableEmoticonsBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enable_emoticons")?.OldValue; + public bool? EnableEmoticonsAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "enable_emoticons")?.NewValue; + + public bool ExpireBehaviorChanged => this.ExpireBehaviorBefore is not null || this.ExpireBehaviorAfter is not null; + public IntegrationExpireBehavior? ExpireBehaviorBefore => (IntegrationExpireBehavior?)this.Changes.FirstOrDefault(x => x.Key == "expire_behavior")?.OldValue; + public IntegrationExpireBehavior? ExpireBehaviorAfter => (IntegrationExpireBehavior?)this.Changes.FirstOrDefault(x => x.Key == "expire_behavior")?.NewValue; + + public bool ExpireGracePeriodChanged => this.ExpireGracePeriodBefore is not null || this.ExpireGracePeriodAfter is not null; + public int? ExpireGracePeriodBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "expire_grace_period")?.OldValue; + public int? ExpireGracePeriodAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "expire_grace_period")?.NewValue; + + public bool AccountChanged => this.AccountBefore is not null || this.AccountAfter is not null; + public DiscordIntegrationAccount? AccountBefore => (DiscordIntegrationAccount?)this.Changes.FirstOrDefault(x => x.Key == "account")?.OldValue; + public DiscordIntegrationAccount? AccountAfter => (DiscordIntegrationAccount?)this.Changes.FirstOrDefault(x => x.Key == "account")?.NewValue; + + public bool RevokedChanged => this.RevokedBefore is not null || this.RevokedAfter is not null; + public bool? RevokedBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "revoked")?.OldValue; + public bool? RevokedAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "revoked")?.NewValue; + + public bool ScopesChanged => this.ScopesBefore is not null || this.ScopesAfter is not null; + public IReadOnlyList? ScopesBefore => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "scopes")?.OldValue; + public IReadOnlyList? ScopesAfter => (IReadOnlyList?)this.Changes.FirstOrDefault(x => x.Key == "scopes")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteCreateChangeSet.cs new file mode 100644 index 0000000000..bd9e19365e --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteCreateChangeSet.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a server invite. +/// +public sealed class InviteCreateChangeSet : DiscordAuditLogEntry +{ + public InviteCreateChangeSet() + { + this.ValidFor = AuditLogActionType.InviteCreate; + + var rawMaxAge = this.MaxAge; + this.ExpiryDateTime = rawMaxAge is not null && rawMaxAge != 0 ? DateTime.UtcNow.AddSeconds(rawMaxAge ?? 0) : null; + } + + public string Code => (string?)this.Changes.FirstOrDefault(x => x.Key == "code")?.NewValue; + public string Url => DiscordDomain.GetDomain(CoreDomain.DiscordShortlink).Url + "/" + this.Code; + + public ulong? ChannelId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "channel_id")?.NewValue; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId ?? 0ul, out var channel) ? channel : null; + + public ulong? InviterId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "inviter_id")?.NewValue; + public DiscordUser? Inviter => this.InviterId is null ? null : this.Discord.GetCachedOrEmptyUserInternal(this.InviterId.Value); + + public int? Uses => (int?)this.Changes.FirstOrDefault(x => x.Key == "uses")?.NewValue; + public int? MaxUses => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_uses")?.NewValue; + public int? MaxAge => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_age")?.NewValue; + public DateTime? ExpiryDateTime { get; internal set; } = null; + public bool? Temporary => (bool?)this.Changes.FirstOrDefault(x => x.Key == "temporary")?.NewValue; + public InviteFlags? Flags => (InviteFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; + + public TargetType? TargetType => (TargetType?)this.Changes.FirstOrDefault(x => x.Key == "target_type")?.NewValue; + public DiscordUser? TargetUser => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "target_user")?.NewValue; + public DiscordApplication? TargetApplication => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "target_application")?.NewValue; + public DiscordStageInstance? TargetStage => (DiscordStageInstance?)this.Changes.FirstOrDefault(x => x.Key == "stage_instance")?.NewValue; + public DiscordScheduledEvent? TargetEvent => (DiscordScheduledEvent?)this.Changes.FirstOrDefault(x => x.Key == "guild_scheduled_event")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteDeleteChangeSet.cs new file mode 100644 index 0000000000..17b7aaec27 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteDeleteChangeSet.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a server invite. +/// +public sealed class InviteDeleteChangeSet : DiscordAuditLogEntry +{ + public InviteDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.InviteCreate; + + var rawMaxAge = this.MaxAge; + this.ExpiryDateTime = rawMaxAge is not null && rawMaxAge != 0 ? DateTime.UtcNow.AddSeconds(rawMaxAge ?? 0) : null; + } + + public string Code => (string?)this.Changes.FirstOrDefault(x => x.Key == "code")?.OldValue; + public string Url => DiscordDomain.GetDomain(CoreDomain.DiscordShortlink).Url + "/" + this.Code; + + public ulong? ChannelId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "channel_id")?.OldValue; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId ?? 0ul, out var channel) ? channel : null; + + public ulong? InviterId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "inviter_id")?.OldValue; + public DiscordUser? Inviter => this.InviterId is null ? null : this.Discord.GetCachedOrEmptyUserInternal(this.InviterId.Value); + + public int? Uses => (int?)this.Changes.FirstOrDefault(x => x.Key == "uses")?.OldValue; + public int? MaxUses => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_uses")?.OldValue; + public int? MaxAge => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_age")?.OldValue; + public DateTime? ExpiryDateTime { get; internal set; } = null; + public bool? Temporary => (bool?)this.Changes.FirstOrDefault(x => x.Key == "temporary")?.OldValue; + public InviteFlags? Flags => (InviteFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + + public TargetType? TargetType => (TargetType?)this.Changes.FirstOrDefault(x => x.Key == "target_type")?.OldValue; + public DiscordUser? TargetUser => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "target_user")?.OldValue; + public DiscordApplication? TargetApplication => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "target_application")?.OldValue; + public DiscordStageInstance? TargetStage => (DiscordStageInstance?)this.Changes.FirstOrDefault(x => x.Key == "stage_instance")?.OldValue; + public DiscordScheduledEvent? TargetEvent => (DiscordScheduledEvent?)this.Changes.FirstOrDefault(x => x.Key == "guild_scheduled_event")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteUpdateChangeSet.cs new file mode 100644 index 0000000000..46cbef951b --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/InviteUpdateChangeSet.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a server invite. +/// +public sealed class InviteUpdateChangeSet : DiscordAuditLogEntry +{ + public InviteUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.InviteUpdate; + + var rawMaxAgeBefore = this.MaxAgeBefore; + this.ExpiryDateTimeBefore = rawMaxAgeBefore is not null && rawMaxAgeBefore != 0 ? DateTime.UtcNow.AddSeconds(rawMaxAgeBefore.Value) : null; + + var rawMaxAgeAfter = this.MaxAgeAfter; + this.ExpiryDateTimeAfter = rawMaxAgeAfter is not null && rawMaxAgeAfter != 0 ? DateTime.UtcNow.AddSeconds(rawMaxAgeAfter.Value) : null; + } + + public bool CodeChanged => this.CodeBefore is not null || this.CodeAfter is not null; + public string CodeBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "code")?.OldValue; + public string CodeAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "code")?.OldValue; + public string UrlBefore => DiscordDomain.GetDomain(CoreDomain.DiscordShortlink).Url + "/" + this.CodeBefore; + public string UrlAfter => DiscordDomain.GetDomain(CoreDomain.DiscordShortlink).Url + "/" + this.CodeAfter; + + public bool ChannelIdChanged => this.ChannelIdBefore is not null || this.ChannelIdAfter is not null; + public ulong? ChannelIdBefore => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "channel_id")?.OldValue; + public ulong? ChannelIdAfter => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "channel_id")?.NewValue; + public DiscordChannel? ChannelBefore => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelIdBefore ?? 0ul, out var channel) ? channel : null; + public DiscordChannel? ChannelAfter => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelIdAfter ?? 0ul, out var channel) ? channel : null; + + public bool InviterIdChanged => this.InviterIdBefore is not null || this.InviterIdAfter is not null; + public ulong? InviterIdBefore => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "inviter_id")?.OldValue; + public ulong? InviterIdAfter => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "inviter_id")?.NewValue; + public DiscordUser? InviterBefore => this.InviterIdBefore is null ? null : this.Discord.GetCachedOrEmptyUserInternal(this.InviterIdBefore.Value); + public DiscordUser? InviterAfter => this.InviterAfter is null ? null : this.Discord.GetCachedOrEmptyUserInternal(this.InviterIdAfter.Value); + + public bool UsesChanged => this.UsesBefore is not null || this.UsesAfter is not null; + public int? UsesBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "uses")?.OldValue; + public int? UsesAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "uses")?.NewValue; + + public bool MaxUsesChanged => this.MaxUsesBefore is not null || this.MaxUsesAfter is not null; + public int? MaxUsesBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_uses")?.OldValue; + public int? MaxUsesAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_uses")?.NewValue; + + public bool MaxAgeChanged => this.MaxAgeBefore is not null || this.MaxAgeAfter is not null; + public int? MaxAgeBefore => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_age")?.OldValue; + public int? MaxAgeAfter => (int?)this.Changes.FirstOrDefault(x => x.Key == "max_age")?.NewValue; + public DateTime? ExpiryDateTimeBefore { get; internal set; } = null; + public DateTime? ExpiryDateTimeAfter { get; internal set; } = null; + + public bool TemporaryChanged => this.TemporaryBefore is not null || this.TemporaryAfter is not null; + public bool? TemporaryBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "temporary")?.OldValue; + public bool? TemporaryAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "temporary")?.NewValue; + + public bool FlagsChanged => this.FlagsBefore is not null || this.FlagsAfter is not null; + public InviteFlags? FlagsBefore => (InviteFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + public InviteFlags? FlagsAfter => (InviteFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; + + public bool TargetTypeChanged => this.TargetTypeBefore is not null || this.TargetTypeAfter is not null; + public TargetType? TargetTypeBefore => (TargetType?)this.Changes.FirstOrDefault(x => x.Key == "target_type")?.OldValue; + public TargetType? TargetTypeAfter => (TargetType?)this.Changes.FirstOrDefault(x => x.Key == "target_type")?.NewValue; + + public bool TargetUserChanged => this.TargetUserBefore is not null || this.TargetUserAfter is not null; + public DiscordUser? TargetUserBefore => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "target_user")?.OldValue; + public DiscordUser? TargetUserAfter => (DiscordUser?)this.Changes.FirstOrDefault(x => x.Key == "target_user")?.NewValue; + + public bool TargetApplicationChanged => this.TargetApplicationBefore is not null || this.TargetApplicationAfter is not null; + public DiscordApplication? TargetApplicationBefore => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "target_application")?.OldValue; + public DiscordApplication? TargetApplicationAfter => (DiscordApplication?)this.Changes.FirstOrDefault(x => x.Key == "target_application")?.NewValue; + + public bool TargetStageChanged => this.TargetStageBefore is not null || this.TargetStageAfter is not null; + public DiscordStageInstance? TargetStageBefore => (DiscordStageInstance?)this.Changes.FirstOrDefault(x => x.Key == "stage_instance")?.OldValue; + public DiscordStageInstance? TargetStageAfter => (DiscordStageInstance?)this.Changes.FirstOrDefault(x => x.Key == "stage_instance")?.NewValue; + + public bool TargetEventChanged => this.TargetEventBefore is not null || this.TargetEventAfter is not null; + public DiscordScheduledEvent? TargetEventBefore => (DiscordScheduledEvent?)this.Changes.FirstOrDefault(x => x.Key == "guild_scheduled_event")?.OldValue; + public DiscordScheduledEvent? TargetEventAfter => (DiscordScheduledEvent?)this.Changes.FirstOrDefault(x => x.Key == "guild_scheduled_event")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanAddChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanAddChangeSet.cs new file mode 100644 index 0000000000..e408dfb076 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanAddChangeSet.cs @@ -0,0 +1,23 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for banning a member from the server. +/// +public sealed class MemberBanAddChangeSet : DiscordAuditLogEntry +{ + public MemberBanAddChangeSet() + { + this.ValidFor = AuditLogActionType.MemberBanAdd; + } + + /// + /// Gets the user who was banned. + /// + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + /// + internal override string? ChangeDescription + => $"{this.User} banned {this.Target} with reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanRemoveChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanRemoveChangeSet.cs new file mode 100644 index 0000000000..71d4d9aa95 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberBanRemoveChangeSet.cs @@ -0,0 +1,23 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for lifting a server ban for a member. +/// +public sealed class MemberBanRemoveChangeSet : DiscordAuditLogEntry +{ + public MemberBanRemoveChangeSet() + { + this.ValidFor = AuditLogActionType.MemberBanRemove; + } + + /// + /// Gets the user who was unbanned. + /// + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + /// + internal override string? ChangeDescription + => $"{this.User} unbanned {this.Target} with reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberDisconnectChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberDisconnectChangeSet.cs new file mode 100644 index 0000000000..e550b007dc --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberDisconnectChangeSet.cs @@ -0,0 +1,30 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for disconnecting a member from a voice channel. +/// +public sealed class MemberDisconnectChangeSet : DiscordAuditLogEntry +{ + public MemberDisconnectChangeSet() + { + this.ValidFor = AuditLogActionType.MemberDisconnect; + } + + /// + /// Gets the count of members that were disconnected. + /// + public int Count => this.Options!.Count.Value; + + /// + /// Gets the channel from which the members were disconnected. + /// + public DiscordChannel Channel => this.Discord.Guilds[this.GuildId].GetChannel(this.TargetId.Value!); + + /// + internal override string? ChangeDescription + => $"{this.User} disconnected {this.Count} users from {this.Channel} with reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberKickChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberKickChangeSet.cs new file mode 100644 index 0000000000..13bac7641b --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberKickChangeSet.cs @@ -0,0 +1,23 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for removing a member from the server. +/// +public sealed class MemberKickChangeSet : DiscordAuditLogEntry +{ + public MemberKickChangeSet() + { + this.ValidFor = AuditLogActionType.MemberKick; + } + + /// + /// Gets the user who was kicked. + /// + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + /// + internal override string? ChangeDescription + => $"{this.User} kicked {this.Target} with reason {this.Reason ?? "No reason given".Italic()}"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberMoveChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberMoveChangeSet.cs new file mode 100644 index 0000000000..ec81002008 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberMoveChangeSet.cs @@ -0,0 +1,21 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for moving a member to a different voice channel. +/// +public sealed class MemberMoveChangeSet : DiscordAuditLogEntry +{ + public MemberMoveChangeSet() + { + this.ValidFor = AuditLogActionType.MemberMove; + } + + public int Count => (int)this.Options!.Count; + + public ulong ChannelId => (ulong)this.Options!.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberPruneChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberPruneChangeSet.cs new file mode 100644 index 0000000000..aad1687882 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberPruneChangeSet.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for pruning members from the server. +/// +public sealed class MemberPruneChangeSet : DiscordAuditLogEntry +{ + public MemberPruneChangeSet() + { + this.ValidFor = AuditLogActionType.MemberPrune; + } + + public int DeleteMemberDays => (int)this.Changes.FirstOrDefault(x => x.Key == "delete_member_days")?.OldValue; + public int Count => (int)this.Changes.FirstOrDefault(x => x.Key == "members_removed")?.OldValue; + + /// + internal override string? ChangeDescription + => $"{this.User} pruned {this.Count} members with reason {this.Reason ?? "none"} and deleted messages from the last {this.DeleteMemberDays} days"; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberRoleUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberRoleUpdateChangeSet.cs new file mode 100644 index 0000000000..43655dbb3d --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberRoleUpdateChangeSet.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for adding or removing a role from a member. +/// +public sealed class MemberRoleUpdateChangeSet : DiscordAuditLogEntry +{ + public MemberRoleUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.MemberRoleUpdate; + } + + public IReadOnlyList AddedRoles + => ((IReadOnlyList)this.Changes.FirstOrDefault(x => x.Key == "$add")?.OldValue) + .Select(x => this.Discord.Guilds[this.GuildId].GetRole(x.Id)).ToList(); + + public IReadOnlyList RemovedRoles + => ((IReadOnlyList)this.Changes.FirstOrDefault(x => x.Key == "$remove")?.OldValue) + .Select(x => this.Discord.Guilds[this.GuildId].GetRole(x.Id)).ToList(); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberUpdateChangeSet.cs new file mode 100644 index 0000000000..3b181f5723 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MemberUpdateChangeSet.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a member in the server. +/// +public sealed class MemberUpdateChangeSet : DiscordAuditLogEntry +{ + public MemberUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.MemberUpdate; + } + + public bool NicknameChanged => this.NicknameBefore is not null || this.NicknameAfter is not null; + public string? NicknameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "nick")?.OldValue; + public string? NicknameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "nick")?.NewValue; + + public bool AvatarChanged => this.AvatarBefore is not null || this.AvatarAfter is not null; + public string? AvatarBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar")?.OldValue; + public string? AvatarAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar")?.NewValue; + + public bool DeafChanged => this.DeafBefore is not null || this.DeafAfter is not null; + public bool? DeafBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "deaf")?.OldValue; + public bool? DeafAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "deaf")?.NewValue; + + public bool MuteChanged => this.MuteBefore is not null || this.MuteAfter is not null; + public bool? MuteBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "mute")?.OldValue; + public bool? MuteAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "mute")?.NewValue; + + public bool FlagsChanged => this.FlagsBefore is not null || this.FlagsAfter is not null; + public MemberFlags? FlagsBefore => (MemberFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + public MemberFlags? FlagsAfter => (MemberFlags?)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; + + public bool PendingChanged => this.PendingBefore is not null || this.PendingAfter is not null; + public bool? PendingBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "pending")?.OldValue; + public bool? PendingAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "pending")?.NewValue; + + public bool CommunicationDisabledUntilChanged => this.CommunicationDisabledUntilBefore is not null || this.CommunicationDisabledUntilAfter is not null; + public DateTimeOffset? CommunicationDisabledUntilBefore => (DateTimeOffset?)this.Changes.FirstOrDefault(x => x.Key == "communication_disabled_until")?.OldValue; + public DateTimeOffset? CommunicationDisabledUntilAfter => (DateTimeOffset?)this.Changes.FirstOrDefault(x => x.Key == "communication_disabled_until")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageBulkDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageBulkDeleteChangeSet.cs new file mode 100644 index 0000000000..7e80dd4f3a --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageBulkDeleteChangeSet.cs @@ -0,0 +1,18 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting multiple messages. +/// +public sealed class MessageBulkDeleteChangeSet : DiscordAuditLogEntry +{ + public MessageBulkDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.MessageBulkDelete; + } + + public DiscordChannel Channel => this.Discord.Guilds[this.GuildId].Channels[this.TargetId!.Value]; + + public int Count => (int)this.Options.Count; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageDeleteChangeSet.cs new file mode 100644 index 0000000000..74ccd2853f --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageDeleteChangeSet.cs @@ -0,0 +1,21 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a single message. +/// +public sealed class MessageDeleteChangeSet : DiscordAuditLogEntry +{ + public MessageDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.MessageDelete; + } + + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + public int Count => (int)this.Options.Count; + + public ulong ChannelId => (ulong)this.Options.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessagePinChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessagePinChangeSet.cs new file mode 100644 index 0000000000..f5353f34f5 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessagePinChangeSet.cs @@ -0,0 +1,22 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for pinning a message to a channel. +/// +public sealed class MessagePinChangeSet : DiscordAuditLogEntry +{ + public MessagePinChangeSet() + { + this.ValidFor = AuditLogActionType.MessagePin; + } + + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + public ulong ChannelId => (ulong)this.Options.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; + + public ulong MessageId => (ulong)this.Options.MessageId; + public DiscordMessage? Message => this.Discord.MessageCache.TryGet(x => x.Id == this.MessageId, out var message) ? message : null; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageUnpinChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageUnpinChangeSet.cs new file mode 100644 index 0000000000..ac764da826 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/MessageUnpinChangeSet.cs @@ -0,0 +1,22 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for unpinning a message from a channel. +/// +public sealed class MessageUnpinChangeSet : DiscordAuditLogEntry +{ + public MessageUnpinChangeSet() + { + this.ValidFor = AuditLogActionType.MessageUnpin; + } + + public DiscordUser Target => this.Discord.GetCachedOrEmptyUserInternal(this.TargetId!.Value); + + public ulong ChannelId => (ulong)this.Options.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; + + public ulong MessageId => (ulong)this.Options.MessageId; + public DiscordMessage? Message => this.Discord.MessageCache.TryGet(x => x.Id == this.MessageId, out var message) ? message : null; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleCreateChangeSet.cs new file mode 100644 index 0000000000..46249248be --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleCreateChangeSet.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a role. +/// +public sealed class RoleCreateChangeSet : DiscordAuditLogEntry +{ + public RoleCreateChangeSet() + { + this.ValidFor = AuditLogActionType.RoleCreate; + } + + public DiscordRole Role => this.Discord.Guilds[this.GuildId].GetRole(this.TargetId.Value!); + + public string Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public DiscordColor Color => new((int)this.Changes.FirstOrDefault(x => x.Key == "color")?.NewValue); + public bool IsHoisted => (bool)this.Changes.FirstOrDefault(x => x.Key == "hoist")?.NewValue; + public bool IsManaged => (bool)this.Changes.FirstOrDefault(x => x.Key == "managed")?.NewValue; + public bool IsMentionable => (bool)this.Changes.FirstOrDefault(x => x.Key == "mentionable")?.NewValue; + public string? IconHash => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.NewValue; + public string? UnicodeEmoji => (string?)this.Changes.FirstOrDefault(x => x.Key == "unicode_emoji")?.NewValue; + public int Position => (int)this.Changes.FirstOrDefault(x => x.Key == "position")?.NewValue; + public Permissions Permissions => (Permissions)Convert.ToInt64(this.Changes.FirstOrDefault(x => x.Key == "permissions")?.NewValue); + public DiscordRoleTags Tags => (DiscordRoleTags)this.Changes.FirstOrDefault(x => x.Key == "tags")?.NewValue; + public RoleFlags Flags => (RoleFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleDeleteChangeSet.cs new file mode 100644 index 0000000000..482e25143d --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleDeleteChangeSet.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a role. +/// +public sealed class RoleDeleteChangeSet : DiscordAuditLogEntry +{ + public RoleDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.RoleDelete; + } + + public DiscordRole Role => this.Discord.Guilds[this.GuildId].GetRole(this.TargetId.Value!); + + public string Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public DiscordColor Color => new((int)this.Changes.FirstOrDefault(x => x.Key == "color")?.OldValue); + public bool IsHoisted => (bool)this.Changes.FirstOrDefault(x => x.Key == "hoist")?.OldValue; + public bool IsManaged => (bool)this.Changes.FirstOrDefault(x => x.Key == "managed")?.OldValue; + public bool IsMentionable => (bool)this.Changes.FirstOrDefault(x => x.Key == "mentionable")?.OldValue; + public string? IconHash => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.OldValue; + public string? UnicodeEmoji => (string?)this.Changes.FirstOrDefault(x => x.Key == "unicode_emoji")?.OldValue; + public int Position => (int)this.Changes.FirstOrDefault(x => x.Key == "position")?.OldValue; + public Permissions Permissions => (Permissions)Convert.ToInt64(this.Changes.FirstOrDefault(x => x.Key == "permissions")?.OldValue); + public DiscordRoleTags Tags => (DiscordRoleTags)this.Changes.FirstOrDefault(x => x.Key == "tags")?.OldValue; + public RoleFlags Flags => (RoleFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleUpdateChangeSet.cs new file mode 100644 index 0000000000..1e358d154c --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/RoleUpdateChangeSet.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for editing a role. +/// +public sealed class RoleUpdateChangeSet : DiscordAuditLogEntry +{ + public RoleUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.RoleUpdate; + } + + public DiscordRole Role => this.Discord.Guilds[this.GuildId].GetRole(this.TargetId.Value!); + + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool ColorChanged => this.ColorBefore is not null || this.ColorAfter is not null; + public DiscordColor? ColorBefore => new((int)this.Changes.FirstOrDefault(x => x.Key == "color")?.OldValue); + public DiscordColor? ColorAfter => new((int)this.Changes.FirstOrDefault(x => x.Key == "color")?.NewValue); + + public bool IsHoistedChanged => this.IsHoistedBefore is not null || this.IsHoistedAfter is not null; + public bool? IsHoistedBefore => (bool)this.Changes.FirstOrDefault(x => x.Key == "hoist")?.OldValue; + public bool? IsHoistedAfter => (bool)this.Changes.FirstOrDefault(x => x.Key == "hoist")?.NewValue; + + public bool IsManagedChanged => this.IsManagedBefore is not null || this.IsManagedAfter is not null; + public bool? IsManagedBefore => (bool)this.Changes.FirstOrDefault(x => x.Key == "managed")?.OldValue; + public bool? IsManagedAfter => (bool)this.Changes.FirstOrDefault(x => x.Key == "managed")?.NewValue; + + public bool IsMentionableChanged => this.IsMentionableBefore is not null || this.IsMentionableAfter is not null; + public bool? IsMentionableBefore => (bool)this.Changes.FirstOrDefault(x => x.Key == "mentionable")?.OldValue; + public bool? IsMentionableAfter => (bool)this.Changes.FirstOrDefault(x => x.Key == "mentionable")?.NewValue; + + public bool IconHashChanged => this.IconHashBefore is not null || this.IconHashAfter is not null; + public string? IconHashBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.OldValue; + public string? IconHashAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "icon")?.NewValue; + + public bool UnicodeEmojiChanged => this.UnicodeEmojiBefore is not null || this.UnicodeEmojiAfter is not null; + public string? UnicodeEmojiBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "unicode_emoji")?.OldValue; + public string? UnicodeEmojiAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "unicode_emoji")?.NewValue; + + public bool PositionChanged => this.PositionBefore is not null || this.PositionAfter is not null; + public int? PositionBefore => (int)this.Changes.FirstOrDefault(x => x.Key == "position")?.OldValue; + public int? PositionAfter => (int)this.Changes.FirstOrDefault(x => x.Key == "position")?.NewValue; + + public bool PermissionsChanged => this.PermissionsBefore is not null || this.PermissionsAfter is not null; + public Permissions? PermissionsBefore => (Permissions)Convert.ToInt64(this.Changes.FirstOrDefault(x => x.Key == "permissions")?.OldValue); + public Permissions? PermissionsAfter => (Permissions)Convert.ToInt64(this.Changes.FirstOrDefault(x => x.Key == "permissions")?.NewValue); + + public bool TagsChanged => this.TagsBefore is not null || this.TagsAfter is not null; + public DiscordRoleTags? TagsBefore => (DiscordRoleTags)this.Changes.FirstOrDefault(x => x.Key == "tags")?.OldValue; + public DiscordRoleTags? TagsAfter => (DiscordRoleTags)this.Changes.FirstOrDefault(x => x.Key == "tags")?.NewValue; + + public bool FlagsChanged => this.FlagsBefore is not null || this.FlagsAfter is not null; + public RoleFlags? FlagsBefore => (RoleFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.OldValue; + public RoleFlags? FlagsAfter => (RoleFlags)this.Changes.FirstOrDefault(x => x.Key == "flags")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerCreateChangeSet.cs new file mode 100644 index 0000000000..7fa4e2df90 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerCreateChangeSet.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a sticker. +/// +public sealed class StickerCreateChangeSet : DiscordAuditLogEntry +{ + public StickerCreateChangeSet() + { + this.ValidFor = AuditLogActionType.StickerCreate; + } + + public string Name => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + public string Description => (string)this.Changes.FirstOrDefault(x => x.Key == "description")?.NewValue; + public string Tags => (string)this.Changes.FirstOrDefault(x => x.Key == "tags")?.NewValue; + public StickerType StickerType => (StickerType)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + public StickerFormat FormatType => (StickerFormat)this.Changes.FirstOrDefault(x => x.Key == "format_type")?.NewValue; + public bool? IsAvailable => (bool?)this.Changes.FirstOrDefault(x => x.Key == "available")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerDeleteChangeSet.cs new file mode 100644 index 0000000000..6d7daac0ae --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerDeleteChangeSet.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a sticker. +/// +public sealed class StickerDeleteChangeSet : DiscordAuditLogEntry +{ + public StickerDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.StickerDelete; + } + + public string Name => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string Description => (string)this.Changes.FirstOrDefault(x => x.Key == "description")?.OldValue; + public string Tags => (string)this.Changes.FirstOrDefault(x => x.Key == "tags")?.OldValue; + public StickerType StickerType => (StickerType)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + public StickerFormat FormatType => (StickerFormat)this.Changes.FirstOrDefault(x => x.Key == "format_type")?.OldValue; + public bool? IsAvailable => (bool?)this.Changes.FirstOrDefault(x => x.Key == "available")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerUpdateChangeSet.cs new file mode 100644 index 0000000000..f48b06faaf --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/StickerUpdateChangeSet.cs @@ -0,0 +1,40 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating sticker details. +/// +public sealed class StickerUpdateChangeSet : DiscordAuditLogEntry +{ + public StickerUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.StickerUpdate; + } + + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + public string? NameBefore => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + public string? NameAfter => (string)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + public bool DescriptionChanged => this.DescriptionBefore is not null || this.DescriptionAfter is not null; + public string? DescriptionBefore => (string)this.Changes.FirstOrDefault(x => x.Key == "description")?.OldValue; + public string? DescriptionAfter => (string)this.Changes.FirstOrDefault(x => x.Key == "description")?.NewValue; + + public bool TagsChanged => this.TagsBefore is not null || this.TagsAfter is not null; + public string? TagsBefore => (string)this.Changes.FirstOrDefault(x => x.Key == "tags")?.OldValue; + public string? TagsAfter => (string)this.Changes.FirstOrDefault(x => x.Key == "tags")?.NewValue; + + public bool StickerTypeChanged => this.StickerTypeBefore is not null || this.StickerTypeAfter is not null; + public StickerType? StickerTypeBefore => (StickerType)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + public StickerType? StickerTypeAfter => (StickerType)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + + public bool FormatTypeChanged => this.FormatTypeBefore is not null || this.FormatTypeAfter is not null; + public StickerFormat? FormatTypeBefore => (StickerFormat)this.Changes.FirstOrDefault(x => x.Key == "format_type")?.OldValue; + public StickerFormat? FormatTypeAfter => (StickerFormat)this.Changes.FirstOrDefault(x => x.Key == "format_type")?.NewValue; + + public bool IsAvailableChanged => this.IsAvailableBefore is not null || this.IsAvailableAfter is not null; + public bool? IsAvailableBefore => (bool?)this.Changes.FirstOrDefault(x => x.Key == "available")?.OldValue; + public bool? IsAvailableAfter => (bool?)this.Changes.FirstOrDefault(x => x.Key == "available")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusDeleteChangeSet.cs new file mode 100644 index 0000000000..2df12e5cc0 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusDeleteChangeSet.cs @@ -0,0 +1,18 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting voice channel status. +/// +public sealed class VoiceChannelStatusDeleteChangeSet : DiscordAuditLogEntry +{ + public VoiceChannelStatusDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.VoiceChannelStatusDelete; + } + + public ulong ChannelId => (ulong)this.Options!.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; + +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusUpdateChangeSet.cs new file mode 100644 index 0000000000..a822cf51da --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/VoiceChannelStatusUpdateChangeSet.cs @@ -0,0 +1,18 @@ +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating voice channel status. +/// +public sealed class VoiceChannelStatusUpdateChangeSet : DiscordAuditLogEntry +{ + public VoiceChannelStatusUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.VoiceChannelStatusUpdate; + } + + public ulong ChannelId => (ulong)this.Options!.ChannelId; + public DiscordChannel? Channel => this.Discord.Guilds[this.GuildId].Channels.TryGetValue(this.ChannelId, out var channel) ? channel : null; + public string Status => this.Options!.Status!; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookCreateChangeSet.cs new file mode 100644 index 0000000000..d590c59976 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookCreateChangeSet.cs @@ -0,0 +1,56 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a webhook. +/// +public sealed class WebhookCreateChangeSet : DiscordAuditLogEntry +{ + public WebhookCreateChangeSet() + { + this.ValidFor = AuditLogActionType.WebhookCreate; + } + + /// + /// Gets the type of the webhook. + /// + public WebhookType Type => (WebhookType)this.Changes.FirstOrDefault(x => x.Key == "type")?.NewValue; + + /// + /// Gets the name of the webhook. + /// + public string? Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + /// + /// Gets the avatar hash of the webhook. + /// + public string? Avatar => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.NewValue; + + /// + /// Gets the token of the webhook. + /// + public string? Token => (string?)this.Changes.FirstOrDefault(x => x.Key == "token")?.NewValue; + + /// + /// Gets the application id of the webhook, if applicable. + /// + public ulong? ApplicationId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "application_id")?.NewValue; + + /// + /// Gets the source guild id of the webhook, if applicable. + /// + public ulong? SourceGuildId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "source_guild_id")?.NewValue; + + /// + /// Gets the source channel id of the webhook, if applicable. + /// + public ulong? SourceChannelId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "source_channel_id")?.NewValue; + + /// + /// Gets the url of the webhook, if applicable. + /// + public string? Url => (string?)this.Changes.FirstOrDefault(x => x.Key == "url")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookDeleteChangeSet.cs new file mode 100644 index 0000000000..fab39c268c --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookDeleteChangeSet.cs @@ -0,0 +1,56 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a webhook. +/// +public sealed class WebhookDeleteChangeSet : DiscordAuditLogEntry +{ + public WebhookDeleteChangeSet() + { + this.ValidFor = AuditLogActionType.WebhookDelete; + } + + /// + /// Gets the type of the webhook. + /// + public WebhookType Type => (WebhookType)this.Changes.FirstOrDefault(x => x.Key == "type")?.OldValue; + + /// + /// Gets the name of the webhook. + /// + public string? Name => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + + /// + /// Gets the avatar hash of the webhook. + /// + public string? Avatar => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.OldValue; + + /// + /// Gets the token of the webhook. + /// + public string? Token => (string?)this.Changes.FirstOrDefault(x => x.Key == "token")?.OldValue; + + /// + /// Gets the application id of the webhook, if applicable. + /// + public ulong? ApplicationId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "application_id")?.OldValue; + + /// + /// Gets the source guild id of the webhook, if applicable. + /// + public ulong? SourceGuildId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "source_guild_id")?.OldValue; + + /// + /// Gets the source channel id of the webhook, if applicable. + /// + public ulong? SourceChannelId => (ulong?)this.Changes.FirstOrDefault(x => x.Key == "source_channel_id")?.OldValue; + + /// + /// Gets the url of the webhook, if applicable. + /// + public string? Url => (string?)this.Changes.FirstOrDefault(x => x.Key == "url")?.OldValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookUpdateChangeSet.cs new file mode 100644 index 0000000000..5d4f5f0bc8 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/Done/WebhookUpdateChangeSet.cs @@ -0,0 +1,46 @@ +using System.Linq; + +using DisCatSharp.Enums; + +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a webhook or its properties. +/// +public sealed class WebhookUpdateChangeSet : DiscordAuditLogEntry +{ + public WebhookUpdateChangeSet() + { + this.ValidFor = AuditLogActionType.WebhookUpdate; + } + + /// + /// Gets a value indicating whether the name of the webhook has changed. + /// + public bool NameChanged => this.NameBefore is not null || this.NameAfter is not null; + + /// + /// Gets the old name of the webhook. + /// + public string? NameBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.OldValue; + + /// + /// Gets the new name of the webhook. + /// + public string? NameAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "name")?.NewValue; + + /// + /// Gets a value indicating whether the avatar hash of the webhook has changed. + /// + public bool AvatarChanged => this.AvatarBefore is not null || this.AvatarAfter is not null; + + /// + /// Gets the old avatar hash of the webhook. + /// + public string? AvatarBefore => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.OldValue; + + /// + /// Gets the new avatar hash of the webhook. + /// + public string? AvatarAfter => (string?)this.Changes.FirstOrDefault(x => x.Key == "avatar_hash")?.NewValue; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventCreateChangeSet.cs new file mode 100644 index 0000000000..8251644d6e --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventCreateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a guild scheduled event. +/// +public sealed class GuildScheduledEventCreateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventDeleteChangeSet.cs new file mode 100644 index 0000000000..7b7983f0b8 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventDeleteChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for cancelling a guild scheduled event. +/// +public sealed class GuildScheduledEventDeleteChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventUpdateChangeSet.cs new file mode 100644 index 0000000000..723616129b --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/GuildScheduledEventUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a guild scheduled event. +/// +public sealed class GuildScheduledEventUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionCreateChangeSet.cs new file mode 100644 index 0000000000..9815b6085a --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionCreateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating an onboarding question. +/// +public sealed class OnboardingQuestionCreateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionUpdateChangeSet.cs new file mode 100644 index 0000000000..e5bc488dc4 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingQuestionUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating an onboarding question. +/// +public sealed class OnboardingQuestionUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingUpdateChangeSet.cs new file mode 100644 index 0000000000..09d1a9fdb3 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/OnboardingUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating onboarding settings. +/// +public sealed class OnboardingUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideCreateChangeSet.cs new file mode 100644 index 0000000000..c3972bd253 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideCreateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a server guide. +/// +public sealed class ServerGuideCreateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideUpdateChangeSet.cs new file mode 100644 index 0000000000..51ccda8b6b --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ServerGuideUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a server guide. +/// +public sealed class ServerGuideUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceCreateChangeSet.cs new file mode 100644 index 0000000000..c26bbf0c4e --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceCreateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a stage instance, making a stage channel live. +/// +public sealed class StageInstanceCreateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceDeleteChangeSet.cs new file mode 100644 index 0000000000..8ad2f80592 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceDeleteChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a stage instance, ending a live stage channel. +/// +public sealed class StageInstanceDeleteChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceUpdateChangeSet.cs new file mode 100644 index 0000000000..b8dbf8ea3f --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/StageInstanceUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating stage instance details. +/// +public sealed class StageInstanceUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadCreateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadCreateChangeSet.cs new file mode 100644 index 0000000000..16ee2cd54a --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadCreateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for creating a thread in a channel. +/// +public sealed class ThreadCreateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadDeleteChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadDeleteChangeSet.cs new file mode 100644 index 0000000000..92fc7353df --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadDeleteChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for deleting a thread. +/// +public sealed class ThreadDeleteChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadUpdateChangeSet.cs b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadUpdateChangeSet.cs new file mode 100644 index 0000000000..08323b4a14 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/ChangeSet/ThreadUpdateChangeSet.cs @@ -0,0 +1,7 @@ +namespace DisCatSharp.Entities; + +/// +/// Represents a change set for updating a thread. +/// +public sealed class ThreadUpdateChangeSet : DiscordAuditLogEntry +{ } diff --git a/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditEntryInfo.cs b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditEntryInfo.cs new file mode 100644 index 0000000000..a8649d1c45 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditEntryInfo.cs @@ -0,0 +1,122 @@ +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents additional information about the . +/// +public sealed class DiscordAuditEntryInfo : ObservableApiObject +{ + /// + /// Gets the guild in which the entities were targeted. + /// + [JsonIgnore] + internal DiscordGuild Guild + => (this.Discord.Guilds.TryGetValue(this.GuildId, out var guild) ? guild : null!)!; + + /// + /// Gets the ID of the guild in which the entities were targeted. + /// + [JsonIgnore] + internal ulong GuildId { get; set; } + + /// + /// Gets the ID of the app whose permissions were targeted. + /// Event Type: . + /// + [JsonProperty("application_id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? ApplicationId { get; internal set; } = null; + + /// + /// Gets the name of the Auto Moderation rule that was triggered. + /// Event Types: , , + /// + [JsonProperty("auto_moderation_rule_name", NullValueHandling = NullValueHandling.Ignore)] + public string? AutoModerationRuleName { get; internal set; } = null; + + /// + /// Gets the trigger type of the Auto Moderation rule that was triggered. + /// Event Types: , , + /// + [JsonProperty("auto_moderation_rule_trigger_type", NullValueHandling = NullValueHandling.Ignore)] + public AutomodTriggerType? AutoModerationRuleTriggerType { get; internal set; } = null; + + /// + /// Gets the ID of the channel in which the entities were targeted. + /// Event Types: , , , , , , , , , + /// + [JsonProperty("channel_id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? ChannelId { get; internal set; } = null; + + /// + /// Gets the channel in which the entities were targeted. + /// + [JsonIgnore] + public DiscordChannel? Channel + => this.ChannelId.HasValue ? this.Guild.GetChannel(this.ChannelId.Value) : null; + + /// + /// Gets the number of entities that were targeted. + /// Event Types: , , , + /// + [JsonProperty("count", NullValueHandling = NullValueHandling.Ignore)] + public int? Count { get; internal set; } = null; + + /// + /// Gets the number of days after which inactive members were kicked. + /// Event Type: + /// + [JsonProperty("delete_member_days", NullValueHandling = NullValueHandling.Ignore)] + public int? DeleteMemberDays { get; internal set; } = null; + + /// + /// Gets the ID of the overwritten entity. + /// Event Types: , , "/> + /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? OverwrittenEntityId { get; internal set; } = null; + + /// + /// Gets the number of members removed by the prune. + /// Event Type: + /// + [JsonProperty("members_removed", NullValueHandling = NullValueHandling.Ignore)] + public int? MembersRemoved { get; internal set; } = null; + + /// + /// Gets the ID of the message that was targeted. + /// Event Types: , + /// + [JsonProperty("message_id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? MessageId { get; internal set; } = null; + + /// + /// Gets the name of the role if the type is "0" (not present if the type is "1"). + /// Event Types: , , + /// + [JsonProperty("role_name", NullValueHandling = NullValueHandling.Ignore)] + public string? RoleName { get; internal set; } = null; + + /// + /// Gets the type of the overwritten entity - role ("0") or member ("1"). + /// Event Types: , , + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public OverwriteType? OverwrittenEntityType { get; internal set; } = null; + + /// + /// Gets the type of integration which performed the action. + /// Event Types: , + /// + [JsonProperty("integration_type", NullValueHandling = NullValueHandling.Ignore)] + public string? IntegrationType { get; internal set; } = null; + + /// + /// Gets the voice channel status. + /// Event Types: + /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + public string? Status { get; internal set; } +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLog.cs b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLog.cs new file mode 100644 index 0000000000..c58b2a9d13 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLog.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a Discord audit log. +/// +public sealed class DiscordAuditLog : ObservableApiObject +{ + /// + /// Gets or sets the ID of the guild in which the entities were targeted. + /// + [JsonIgnore] + internal ulong GuildId { get; set; } + + /// + /// List of application commands referenced in the . + /// + [JsonProperty("application_commands", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedApplicationCommands { get; internal set; } = new(); + + /// + /// List of , sorted from most to least recent. + /// + [JsonProperty("audit_log_entries", NullValueHandling = NullValueHandling.Ignore)] + public List Entries { get; internal set; } = new(); + + /// + /// List of auto moderation rules referenced in the . + /// + [JsonProperty("auto_moderation_rules", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedAutomodRules { get; internal set; } = new(); + + /// + /// List of guild scheduled events referenced in the . + /// + [JsonProperty("guild_scheduled_events", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedScheduledEvents { get; internal set; } = new(); + + /// + /// List of partial integration objects referenced in the . + /// + [JsonProperty("integrations", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedIntegrations { get; internal set; } = new(); + + /// + /// List of threads referenced in the . + /// + [JsonProperty("threads", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedThreads { get; internal set; } = new(); + + /// + /// List of users referenced in the . + /// + [JsonProperty("users", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedUsers { get; internal set; } = new(); + + /// + /// List of webhooks referenced in the . + /// + [JsonProperty("webhooks", NullValueHandling = NullValueHandling.Ignore)] + public List ReferencedWebhooks { get; internal set; } = new(); +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogChangeObject.cs b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogChangeObject.cs new file mode 100644 index 0000000000..821c79fcb4 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogChangeObject.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a in a . +/// +public sealed class DiscordAuditLogChangeObject +{ + /// + /// Gets the new value of the change. + /// + [JsonProperty("new_value", NullValueHandling = NullValueHandling.Ignore)] + public object? NewValue { get; internal set; } + + /// + /// Gets the old value of the change. + /// + [JsonProperty("old_value", NullValueHandling = NullValueHandling.Ignore)] + public object? OldValue { get; internal set; } + + /// + /// Gets the key of the changed entity. + /// + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key { get; internal set; } + + [JsonIgnore] + public bool IsSpecialKey + => SpecialChangeKeys.SpecialKeys.Contains(this.Key); +} + +/// +/// Represents special change keys for the . +/// +public static class SpecialChangeKeys +{ + /// + /// Special for role add. + /// Contains a partial role object. + /// + public const string PARTIAL_ROLE_ADD = "$add"; + + /// + /// Special for role remove. + /// Contains a partial role object. + /// + public const string PARTIAL_ROLE_REMOVE = "$remove"; + + /// + /// Special for invite and invite metadata channel ids. + /// Uses channel_id instead of channel.id. + /// + public const string INVITE_CHANNEL_ID = "channel_id"; + + /// + /// Special for webhook avatars. + /// Uses avatar_hash instead of avatar. + /// + public const string WEBHOOK_AVATAR = "avatar_hash"; + + public static readonly List SpecialKeys = new() + { + PARTIAL_ROLE_ADD, PARTIAL_ROLE_REMOVE, INVITE_CHANNEL_ID, WEBHOOK_AVATAR + }; +} diff --git a/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogEntry.cs b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogEntry.cs new file mode 100644 index 0000000000..0d95d018d8 --- /dev/null +++ b/DisCatSharp/Entities/Guild/AuditLog/DiscordAuditLogEntry.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; + +using DisCatSharp.Enums; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +/// +/// Represents a Discord audit log entry. +/// +public class DiscordAuditLogEntry : SnowflakeObject +{ + /// + /// Gets the client instance this object is tied to. + /// + [JsonIgnore] + internal new DiscordClient Discord { get; set; } + + /// + /// Gets or sets the ID of the guild in which the entities were targeted. + /// + [JsonIgnore] + internal ulong GuildId { get; set; } + + /// + /// Gets the ID of the affected entity (webhook, user, role, etc.). + /// + [JsonProperty("target_id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? TargetId { get; internal set; } + + /// + /// Gets the list of changes made to the target_id. + /// + [JsonProperty("changes", NullValueHandling = NullValueHandling.Ignore)] + public List Changes { get; internal set; } = new(); + + /// + /// Gets the ID of the user or app that made the changes. + /// + [JsonProperty("user_id", NullValueHandling = NullValueHandling.Ignore)] + public ulong? UserId { get; internal set; } + + /// + /// Gets the user or app that made the changes. + /// + [JsonIgnore] + public DiscordUser? User + => this.UserId.HasValue ? this.Discord.GetCachedOrEmptyUserInternal(this.UserId.Value) : null; + + /// + /// Gets the type of action that occurred in the audit log entry. + /// + [JsonProperty("action_type", NullValueHandling = NullValueHandling.Ignore)] + public AuditLogActionType ActionType { get; internal set; } + + /// + /// Gets additional information for certain event types. + /// + [JsonProperty("options", NullValueHandling = NullValueHandling.Ignore)] + public DiscordAuditEntryInfo? Options { get; internal set; } + + /// + /// Gets the reason for the change (1-512 characters). + /// + [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] + public string? Reason { get; internal set; } + + /// + /// Gets the change description. + /// + [JsonIgnore] + internal virtual string? ChangeDescription { get; set; } = null; + + /// + /// Gets the valid action type for this change set. + /// + [JsonIgnore] + internal AuditLogActionType ValidFor { get; init; } + + /// + public override string ToString() + => /* this.ChangeDescription ?? temporary disabled */ $"{this.User} executed {this.ActionType}"; + + /// + /// Gets this as an easy to-use change set with the given type. + /// + /// The type to convert to. Use the type based on the . + /// The easy to-use audit log entry. + /// Thrown when the is not compatible with the targets type. + public T As() + where T : DiscordAuditLogEntry, new() + { + if (this is T t) + return t.ValidFor == this.ActionType + ? t + : throw new InvalidCastException($"Cannot convert {this.GetType().Name} with action type {this.ActionType} to {typeof(T).Name}."); + + var target = new T + { + TargetId = this.TargetId, + Changes = this.Changes, + UserId = this.UserId, + ActionType = this.ActionType, + Options = this.Options, + Id = this.Id, + Discord = this.Discord, + Reason = this.Reason, + GuildId = this.GuildId + }; + + if (target.Options is not null) + target.Options.Discord = this.Discord; + + return target.ValidFor == this.ActionType + ? target + : throw new InvalidCastException($"Cannot convert {this.GetType().Name} with action type {this.ActionType} to {typeof(T).Name}."); + } + + /// + /// Converts an object to ulong?. + /// + /// The object to convert. + internal static ulong? ConvertToUlong(object? obj) + { + var str = obj?.ToString(); + return str == null + ? null + : ulong.TryParse(str, out var val) + ? val + : null; + } +} diff --git a/DisCatSharp/Entities/Guild/Automod/AutomodRule.cs b/DisCatSharp/Entities/Guild/Automod/AutomodRule.cs index 7457f1b172..8759b0f7ec 100644 --- a/DisCatSharp/Entities/Guild/Automod/AutomodRule.cs +++ b/DisCatSharp/Entities/Guild/Automod/AutomodRule.cs @@ -107,6 +107,7 @@ public async Task ModifyAsync(Action action) if (mdl.TriggerMetadata.Value.MentionRaidProtectionEnabled != null && this.TriggerType != AutomodTriggerType.MentionSpam) throw new ArgumentException($"Cannot use MentionRaidProtectionEnabled for a {this.TriggerType} rule. Only {AutomodTriggerType.MentionSpam} is valid in this context."); } + return await this.Discord.ApiClient.ModifyAutomodRuleAsync(this.GuildId, this.Id, mdl.Name, mdl.EventType, mdl.TriggerMetadata, mdl.Actions, mdl.Enabled, mdl.ExemptRoles, mdl.ExemptChannels, mdl.AuditLogReason).ConfigureAwait(false); } diff --git a/DisCatSharp/Entities/Guild/DiscordAuditLogObjects.cs b/DisCatSharp/Entities/Guild/DiscordAuditLogObjects.cs deleted file mode 100644 index 89cda0ffb6..0000000000 --- a/DisCatSharp/Entities/Guild/DiscordAuditLogObjects.cs +++ /dev/null @@ -1,831 +0,0 @@ -using System; -using System.Collections.Generic; - -using DisCatSharp.Enums; - -namespace DisCatSharp.Entities; - -/// -/// Represents an audit log entry. -/// -public abstract class DiscordAuditLogEntry : SnowflakeObject -{ - /// - /// Gets the entry's action type. - /// - public AuditLogActionType ActionType { get; internal set; } - - /// - /// Gets the user responsible for the action. - /// - public DiscordUser UserResponsible { get; internal set; } - - /// - /// Gets the reason defined in the action. - /// - public string Reason { get; internal set; } - - /// - /// Gets the category under which the action falls. - /// - public AuditLogActionCategory ActionCategory { get; internal set; } -} - -/// -/// Represents a description of how a property changed. -/// -/// Type of the changed property. -public sealed class PropertyChange -{ - /// - /// The property's value before it was changed. - /// - public T Before { get; internal set; } - - /// - /// The property's value after it was changed. - /// - public T After { get; internal set; } -} - -/// -/// Represents a audit log guild entry. -/// -public sealed class DiscordAuditLogGuildEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected guild. - /// - public DiscordGuild Target { get; internal set; } - - /// - /// Gets the name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the owner change. - /// - public PropertyChange OwnerChange { get; internal set; } - - /// - /// Gets the icon change. - /// - public PropertyChange IconChange { get; internal set; } - - /// - /// Gets the verification level change. - /// - public PropertyChange VerificationLevelChange { get; internal set; } - - /// - /// Gets the afk channel change. - /// - public PropertyChange AfkChannelChange { get; internal set; } - - /// - /// Gets the system channel flags change. - /// - public PropertyChange SystemChannelFlagsChange { get; internal set; } - - /// - /// - /// - public PropertyChange WidgetChannelChange { get; internal set; } - - /// - /// - /// - public PropertyChange RulesChannelChange { get; internal set; } - - /// - /// - /// - public PropertyChange PublicUpdatesChannelChange { get; internal set; } - - /// - /// - /// - public PropertyChange NotificationSettingsChange { get; internal set; } - - /// - /// - /// - public PropertyChange SystemChannelChange { get; internal set; } - - /// - /// - /// - public PropertyChange ExplicitContentFilterChange { get; internal set; } - - /// - /// - /// - public PropertyChange MfaLevelChange { get; internal set; } - - /// - /// - /// - public PropertyChange SplashChange { get; internal set; } - - /// - /// - /// - public PropertyChange RegionChange { get; internal set; } - - /// - /// - /// - public PropertyChange VanityUrlCodeChange { get; internal set; } - - /// - /// - /// - public PropertyChange PremiumProgressBarChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogGuildEntry() { } -} - -/// -/// Represents a audit log channel entry. -/// -public sealed class DiscordAuditLogChannelEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected channel. - /// - public DiscordChannel Target { get; internal set; } - - /// - /// Gets the description of channel's name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the description of channel's type change. - /// - public PropertyChange TypeChange { get; internal set; } - - /// - /// Gets the description of channel's nsfw flag change. - /// - public PropertyChange NsfwChange { get; internal set; } - - /// - /// Gets the rtc region id change. - /// - public PropertyChange RtcRegionIdChange { get; internal set; } - - /// - /// Gets the description of channel's bitrate change. - /// - public PropertyChange BitrateChange { get; internal set; } - - /// - /// Gets the description of channel permission overwrites' change. - /// - public PropertyChange> OverwriteChange { get; internal set; } - - /// - /// Gets the description of channel's topic change. - /// - public PropertyChange TopicChange { get; internal set; } - - /// - /// Gets the user limit change. - /// - public PropertyChange UserLimitChange { get; internal set; } - - /// - /// Gets the description of channel's slow mode timeout change. - /// - public PropertyChange PerUserRateLimitChange { get; internal set; } - - /// - /// Gets the channel flags change. - /// - public PropertyChange ChannelFlagsChange { get; internal set; } - - /// - /// Gets the default auto archive duration change. - /// - public PropertyChange DefaultAutoArchiveDurationChange { get; internal set; } - - /// - /// Gets the default available tags change. - /// - public PropertyChange> AvailableTagsChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogChannelEntry() { } -} - -/// -/// Represents a audit log overwrite entry. -/// -public sealed class DiscordAuditLogOverwriteEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected overwrite. - /// - public DiscordOverwrite Target { get; internal set; } - - /// - /// Gets the channel for which the overwrite was changed. - /// - public DiscordChannel Channel { get; internal set; } - - /// - /// Gets the description of overwrite's allow value change. - /// - public PropertyChange AllowChange { get; internal set; } - - /// - /// Gets the description of overwrite's deny value change. - /// - public PropertyChange DenyChange { get; internal set; } - - /// - /// Gets the description of overwrite's type change. - /// - public PropertyChange TypeChange { get; internal set; } - - /// - /// Gets the description of overwrite's target id change. - /// - public PropertyChange TargetIdChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogOverwriteEntry() { } -} - -/// -/// Represents a audit log kick entry. -/// -public sealed class DiscordAuditLogKickEntry : DiscordAuditLogEntry -{ - /// - /// Gets the kicked member. - /// - public DiscordMember Target { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogKickEntry() { } -} - -/// -/// Represents a audit log prune entry. -/// -public sealed class DiscordAuditLogPruneEntry : DiscordAuditLogEntry -{ - /// - /// Gets the number inactivity days after which members were pruned. - /// - public int Days { get; internal set; } - - /// - /// Gets the number of members pruned. - /// - public int Toll { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogPruneEntry() { } -} - -/// -/// Represents a audit log ban entry. -/// -public sealed class DiscordAuditLogBanEntry : DiscordAuditLogEntry -{ - /// - /// Gets the banned member. - /// - public DiscordMember Target { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogBanEntry() { } -} - -/// -/// Represents a audit log member update entry. -/// -public sealed class DiscordAuditLogMemberUpdateEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected member. - /// - public DiscordMember Target { get; internal set; } - - /// - /// Gets the description of member's nickname change. - /// - public PropertyChange NicknameChange { get; internal set; } - - /// - /// Gets the roles that were removed from the member. - /// - public IReadOnlyList RemovedRoles { get; internal set; } - - /// - /// Gets the roles that were added to the member. - /// - public IReadOnlyList AddedRoles { get; internal set; } - - /// - /// Gets the description of member's mute status change. - /// - public PropertyChange MuteChange { get; internal set; } - - /// - /// Gets the description of member's deaf status change. - /// - public PropertyChange DeafenChange { get; internal set; } - - /// - /// Get's the timeout change. - /// - public PropertyChange CommunicationDisabledUntilChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogMemberUpdateEntry() { } -} - -/// -/// Represents a audit log role update entry. -/// -public sealed class DiscordAuditLogRoleUpdateEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected role. - /// - public DiscordRole Target { get; internal set; } - - /// - /// Gets the description of role's name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the description of role's color change. - /// - public PropertyChange ColorChange { get; internal set; } - - /// - /// Gets the description of role's permission set change. - /// - public PropertyChange PermissionChange { get; internal set; } - - /// - /// Gets the description of the role's position change. - /// - public PropertyChange PositionChange { get; internal set; } - - /// - /// Gets the description of the role's mentionability change. - /// - public PropertyChange MentionableChange { get; internal set; } - - /// - /// Gets the description of the role's hoist status change. - /// - public PropertyChange HoistChange { get; internal set; } - - /// - /// Gets the role icon hash change. - /// - public PropertyChange IconHashChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogRoleUpdateEntry() { } -} - -/// -/// Represents a audit log invite entry. -/// -public sealed class DiscordAuditLogInviteEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected invite. - /// - public DiscordInvite Target { get; internal set; } - - /// - /// Gets the description of invite's max age change. - /// - public PropertyChange MaxAgeChange { get; internal set; } - - /// - /// Gets the description of invite's code change. - /// - public PropertyChange CodeChange { get; internal set; } - - /// - /// Gets the description of invite's temporariness change. - /// - public PropertyChange TemporaryChange { get; internal set; } - - /// - /// Gets the description of invite's inviting member change. - /// - public PropertyChange InviterChange { get; internal set; } - - /// - /// Gets the description of invite's target channel change. - /// - public PropertyChange ChannelChange { get; internal set; } - - /// - /// Gets the description of invite's use count change. - /// - public PropertyChange UsesChange { get; internal set; } - - /// - /// Gets the description of invite's max use count change. - /// - public PropertyChange MaxUsesChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogInviteEntry() { } -} - -/// -/// Represents a audit log webhook entry. -/// -public sealed class DiscordAuditLogWebhookEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected webhook. - /// - public DiscordWebhook Target { get; internal set; } - - /// - /// Undocumented. - /// - public PropertyChange IdChange { get; internal set; } - - /// - /// Gets the description of webhook's name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the description of webhook's target channel change. - /// - public PropertyChange ChannelChange { get; internal set; } - - /// - /// Gets the description of webhook's type change. - /// - public PropertyChange TypeChange { get; internal set; } - - /// - /// Gets the description of webhook's avatar change. - /// - public PropertyChange AvatarHashChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogWebhookEntry() { } -} - -/// -/// Represents a audit log emoji entry. -/// -public sealed class DiscordAuditLogEmojiEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected emoji. - /// - public DiscordEmoji Target { get; internal set; } - - /// - /// Gets the description of emoji's name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogEmojiEntry() { } -} - -/// -/// Represents a audit log sticker entry. -/// -public sealed class DiscordAuditLogStickerEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected sticker. - /// - public DiscordSticker Target { get; internal set; } - - /// - /// Gets the description of sticker's name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the description of sticker's description change. - /// - public PropertyChange DescriptionChange { get; internal set; } - - /// - /// Gets the description of sticker's tags change. - /// - public PropertyChange TagsChange { get; internal set; } - - /// - /// Gets the description of sticker's tags change. - /// - public PropertyChange AssetChange { get; internal set; } - - /// - /// Gets the description of sticker's guild id change. - /// - public PropertyChange GuildIdChange { get; internal set; } - - /// - /// Gets the description of sticker's availability change. - /// - public PropertyChange AvailabilityChange { get; internal set; } - - /// - /// Gets the description of sticker's id change. - /// - public PropertyChange IdChange { get; internal set; } - - /// - /// Gets the description of sticker's type change. - /// - public PropertyChange TypeChange { get; internal set; } - - /// - /// Gets the description of sticker's format change. - /// - public PropertyChange FormatChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogStickerEntry() { } -} - -/// -/// Represents a audit log message entry. -/// -public sealed class DiscordAuditLogMessageEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected message. Note that more often than not, this will only have ID specified. - /// - public DiscordMessage Target { get; internal set; } - - /// - /// Gets the channel in which the action occurred. - /// - public DiscordChannel Channel { get; internal set; } - - /// - /// Gets the number of messages that were affected. - /// - public int? MessageCount { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogMessageEntry() { } -} - -/// -/// Represents a audit log message pin entry. -/// -public sealed class DiscordAuditLogMessagePinEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected message's user. - /// - public DiscordUser Target { get; internal set; } - - /// - /// Gets the channel the message is in. - /// - public DiscordChannel Channel { get; internal set; } - - /// - /// Gets the message the pin action was for. - /// - public DiscordMessage Message { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogMessagePinEntry() { } -} - -/// -/// Represents a audit log bot add entry. -/// -public sealed class DiscordAuditLogBotAddEntry : DiscordAuditLogEntry -{ - /// - /// Gets the bot that has been added to the guild. - /// - public DiscordUser TargetBot { get; internal set; } -} - -/// -/// Represents a audit log member move entry. -/// -public sealed class DiscordAuditLogMemberMoveEntry : DiscordAuditLogEntry -{ - /// - /// Gets the channel the members were moved in. - /// - public DiscordChannel Channel { get; internal set; } - - /// - /// Gets the amount of users that were moved out from the voice channel. - /// - public int UserCount { get; internal set; } -} - -/// -/// Represents a audit log member disconnect entry. -/// -public sealed class DiscordAuditLogMemberDisconnectEntry : DiscordAuditLogEntry -{ - /// - /// Gets the amount of users that were disconnected from the voice channel. - /// - public int UserCount { get; internal set; } -} - -/// -/// Represents a audit log integration entry. -/// -public sealed class DiscordAuditLogIntegrationEntry : DiscordAuditLogEntry -{ - /// - /// The type of integration. - /// - public PropertyChange Type { get; internal set; } - - /// - /// Gets the description of emoticons' change. - /// - public PropertyChange EnableEmoticons { get; internal set; } - - /// - /// Gets the description of expire grace period's change. - /// - public PropertyChange ExpireGracePeriod { get; internal set; } - - /// - /// Gets the description of expire behavior change. - /// - public PropertyChange ExpireBehavior { get; internal set; } -} - -/// -/// Represents a audit log stage entry. -/// -public sealed class DiscordAuditLogStageEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected stage instance - /// - public DiscordStageInstance Target { get; internal set; } - - /// - /// Gets the description of stage instance's topic change. - /// - public PropertyChange TopicChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogStageEntry() { } -} - -/// -/// Represents a audit log event entry. -/// -public sealed class DiscordAuditLogGuildScheduledEventEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected event - /// - public DiscordScheduledEvent Target { get; internal set; } - - /// - /// Gets the channel change. - /// - public PropertyChange ChannelIdChange { get; internal set; } - - /// - /// Gets the name change. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the description change. - /// - public PropertyChange DescriptionChange { get; internal set; } - - /* Will be added https://github.com/discord/discord-api-docs/pull/3586#issuecomment-969137241 - public PropertyChange<> ScheduledStartTimeChange { get; internal set; } - - public PropertyChange<> ScheduledEndTimeChange { get; internal set; } - */ - - /// - /// Gets the location change. - /// - public PropertyChange LocationChange { get; internal set; } - - /// - /// Gets the status change. - /// - public PropertyChange StatusChange { get; internal set; } - - /// - /// Gets the entity type change. - /// - public PropertyChange EntityTypeChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogGuildScheduledEventEntry() { } -} - -/// -/// Represents a audit log thread entry. -/// -public sealed class DiscordAuditLogThreadEntry : DiscordAuditLogEntry -{ - /// - /// Gets the affected thread - /// - public DiscordThreadChannel Target { get; internal set; } - - /// - /// Gets the name of the thread. - /// - public PropertyChange NameChange { get; internal set; } - - /// - /// Gets the type of the thread. - /// - public PropertyChange TypeChange { get; internal set; } - - /// - /// Gets the archived state of the thread. - /// - public PropertyChange ArchivedChange { get; internal set; } - - /// - /// Gets the locked state of the thread. - /// - public PropertyChange LockedChange { get; internal set; } - - /// - /// Gets the invitable state of the thread. - /// - public PropertyChange InvitableChange { get; internal set; } - - /// - /// Gets the new auto archive duration of the thread. - /// - public PropertyChange AutoArchiveDurationChange { get; internal set; } - - /// - /// Gets the new ratelimit of the thread. - /// - public PropertyChange PerUserRateLimitChange { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - internal DiscordAuditLogThreadEntry() { } -} diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.AuditLog.cs b/DisCatSharp/Entities/Guild/DiscordGuild.AuditLog.cs deleted file mode 100644 index e3c780d3fd..0000000000 --- a/DisCatSharp/Entities/Guild/DiscordGuild.AuditLog.cs +++ /dev/null @@ -1,1351 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; - -using DisCatSharp.Enums; -using DisCatSharp.Exceptions; -using DisCatSharp.Net; -using DisCatSharp.Net.Abstractions; - -using Microsoft.Extensions.Logging; - -using Newtonsoft.Json.Linq; - -namespace DisCatSharp.Entities; - -public partial class DiscordGuild -{ - // TODO: Rework audit logs! - - /// - /// Gets audit log entries for this guild. - /// - /// Maximum number of entries to fetch. - /// Filter by member responsible. - /// Filter by action type. - /// A collection of requested audit log entries. - /// Thrown when the client does not have the permission. - /// Thrown when Discord is unable to process the request. - public async Task> GetAuditLogsAsync(int? limit = null, DiscordMember byMember = null, AuditLogActionType? actionType = null) - { - var alrs = new List(); - int ac = 1, tc = 0, rmn = 100; - var last = 0ul; - while (ac > 0) - { - rmn = limit != null ? limit.Value - tc : 100; - rmn = Math.Min(100, rmn); - if (rmn <= 0) break; - - var alr = await this.Discord.ApiClient.GetAuditLogsAsync(this.Id, rmn, null, last == 0 ? null : last, byMember?.Id, (int?)actionType).ConfigureAwait(false); - ac = alr.Entries.Count; - tc += ac; - if (ac > 0) - { - last = alr.Entries[alr.Entries.Count - 1].Id; - alrs.Add(alr); - } - } - - var auditLogResult = await this.ProcessAuditLog(alrs).ConfigureAwait(false); - return auditLogResult; - } - - /// - /// Proceesses audit log objects. - /// - /// A list of raw audit log objects. - /// The processed audit log list as readonly. - internal async Task> ProcessAuditLog(List auditLogApiResult) - { - List amr = new(); - if (auditLogApiResult.Any(ar => ar.Users != null && ar.Users.Any())) - amr = auditLogApiResult.SelectMany(xa => xa.Users) - .GroupBy(xu => xu.Id) - .Select(xgu => xgu.First()).ToList(); - - if (amr.Any()) - foreach (var xau in amr) - { - if (this.Discord.UserCache.ContainsKey(xau.Id)) - continue; - - var xtu = new TransportUser - { - Id = xau.Id, - Username = xau.Username, - Discriminator = xau.Discriminator, - AvatarHash = xau.AvatarHash - }; - var xu = new DiscordUser(xtu) { Discord = this.Discord }; - xu = this.Discord.UserCache.AddOrUpdate(xu.Id, xu, (id, old) => - { - old.Username = xu.Username; - old.Discriminator = xu.Discriminator; - old.AvatarHash = xu.AvatarHash; - old.GlobalName = xu.GlobalName; - return old; - }); - } - - List atgse = new(); - if (auditLogApiResult.Any(ar => ar.ScheduledEvents != null && ar.ScheduledEvents.Any())) - atgse = auditLogApiResult.SelectMany(xa => xa.ScheduledEvents) - .GroupBy(xse => xse.Id) - .Select(xgse => xgse.First()).ToList(); - - List ath = new(); - if (auditLogApiResult.Any(ar => ar.Threads != null && ar.Threads.Any())) - ath = auditLogApiResult.SelectMany(xa => xa.Threads) - .GroupBy(xt => xt.Id) - .Select(xgt => xgt.First()).ToList(); - - List aig = new(); - if (auditLogApiResult.Any(ar => ar.Integrations != null && ar.Integrations.Any())) - aig = auditLogApiResult.SelectMany(xa => xa.Integrations) - .GroupBy(xi => xi.Id) - .Select(xgi => xgi.First()).ToList(); - - List ahr = new(); - if (auditLogApiResult.Any(ar => ar.Webhooks != null && ar.Webhooks.Any())) - ahr = auditLogApiResult.SelectMany(xa => xa.Webhooks) - .GroupBy(xh => xh.Id) - .Select(xgh => xgh.First()).ToList(); - - List ams = new(); - Dictionary amd = new(); - if (amr.Any()) - ams = amr.Select(xau => this.MembersInternal != null && this.MembersInternal.TryGetValue(xau.Id, out var member) ? member : new() { Discord = this.Discord, Id = xau.Id, GuildId = this.Id }).ToList(); - if (ams.Any()) - amd = ams.ToDictionary(xm => xm.Id, xm => xm); - -#pragma warning disable CS0219 - Dictionary dtc = null; - Dictionary di = null; - Dictionary dse = null; -#pragma warning restore - - Dictionary ahd = null; - if (ahr.Any()) - { - var whr = await this.GetWebhooksAsync().ConfigureAwait(false); - var whs = whr.ToDictionary(xh => xh.Id, xh => xh); - - var amh = ahr.Select(xah => whs.TryGetValue(xah.Id, out var webhook) ? webhook : new() { Discord = this.Discord, Name = xah.Name, Id = xah.Id, AvatarHash = xah.AvatarHash, ChannelId = xah.ChannelId, GuildId = xah.GuildId, Token = xah.Token }); - ahd = amh.ToDictionary(xh => xh.Id, xh => xh); - } - - var acs = auditLogApiResult.SelectMany(xa => xa.Entries).OrderByDescending(xa => xa.Id); - var entries = new List(); - foreach (var xac in acs) - { - DiscordAuditLogEntry entry = null; - ulong t1, t2; - int t3, t4; - long t5, t6; - bool p1, p2; - switch (xac.ActionType) - { - case AuditLogActionType.Invalid: - break; - - case AuditLogActionType.GuildUpdate: - entry = new DiscordAuditLogGuildEntry - { - Target = this - }; - - var entrygld = entry as DiscordAuditLogGuildEntry; - foreach (var xc in xac.Changes) - { - PropertyChange GetChannelChange() - { - ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - return new() - { - Before = this.GetChannel(t1) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id }, - After = this.GetChannel(t2) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id } - }; - } - - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entrygld.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "owner_id": - entrygld.OwnerChange = new() - { - Before = this.MembersInternal != null && this.MembersInternal.TryGetValue(xc.OldValueUlong, out var oldMember) ? oldMember : await this.GetMemberAsync(xc.OldValueUlong).ConfigureAwait(false), - After = this.MembersInternal != null && this.MembersInternal.TryGetValue(xc.NewValueUlong, out var newMember) ? newMember : await this.GetMemberAsync(xc.NewValueUlong).ConfigureAwait(false) - }; - break; - - case "icon_hash": - entrygld.IconChange = new() - { - Before = xc.OldValueString != null ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.ICONS}/{this.Id}/{xc.OldValueString}.webp" : null, - After = xc.OldValueString != null ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.ICONS}/{this.Id}/{xc.NewValueString}.webp" : null - }; - break; - - case "verification_level": - entrygld.VerificationLevelChange = new() - { - Before = (VerificationLevel)(long)xc.OldValue, - After = (VerificationLevel)(long)xc.NewValue - }; - break; - - case "afk_channel_id": - entrygld.AfkChannelChange = GetChannelChange(); - break; - - case "system_channel_flags": - entrygld.SystemChannelFlagsChange = new() - { - Before = (SystemChannelFlags)(long)xc.OldValue, - After = (SystemChannelFlags)(long)xc.NewValue - }; - break; - - case "widget_channel_id": - entrygld.WidgetChannelChange = GetChannelChange(); - break; - - case "rules_channel_id": - entrygld.RulesChannelChange = GetChannelChange(); - break; - - case "public_updates_channel_id": - entrygld.PublicUpdatesChannelChange = GetChannelChange(); - break; - - case "splash_hash": - entrygld.SplashChange = new() - { - Before = xc.OldValueString != null ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id}/{xc.OldValueString}.webp?size=2048" : null, - After = xc.NewValueString != null ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id}/{xc.NewValueString}.webp?size=2048" : null - }; - break; - - case "default_message_notifications": - entrygld.NotificationSettingsChange = new() - { - Before = (DefaultMessageNotifications)(long)xc.OldValue, - After = (DefaultMessageNotifications)(long)xc.NewValue - }; - break; - - case "system_channel_id": - entrygld.SystemChannelChange = GetChannelChange(); - break; - - case "explicit_content_filter": - entrygld.ExplicitContentFilterChange = new() - { - Before = (ExplicitContentFilter)(long)xc.OldValue, - After = (ExplicitContentFilter)(long)xc.NewValue - }; - break; - - case "mfa_level": - entrygld.MfaLevelChange = new() - { - Before = (MfaLevel)(long)xc.OldValue, - After = (MfaLevel)(long)xc.NewValue - }; - break; - - case "region": - entrygld.RegionChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "vanity_url_code": - entrygld.VanityUrlCodeChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "premium_progress_bar_enabled": - entrygld.PremiumProgressBarChange = new() - { - Before = (bool)xc.OldValue, - After = (bool)xc.NewValue - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in guild update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.ChannelCreate: - case AuditLogActionType.ChannelDelete: - case AuditLogActionType.ChannelUpdate: - entry = new DiscordAuditLogChannelEntry - { - Target = this.GetChannel(xac.TargetId.Value) ?? new DiscordChannel { Id = xac.TargetId.Value, Discord = this.Discord, GuildId = this.Id } - }; - - var entrychn = entry as DiscordAuditLogChannelEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entrychn.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "type": - p1 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entrychn.TypeChange = new() - { - Before = p1 ? (ChannelType?)t1 : null, - After = p2 ? (ChannelType?)t2 : null - }; - break; - - case "flags": - entrychn.ChannelFlagsChange = new() - { - Before = (ChannelFlags)(long)(xc.OldValue ?? 0L), - After = (ChannelFlags)(long)(xc.NewValue ?? 0L) - }; - break; - - case "permission_overwrites": - var olds = xc.OldValues?.OfType() - ?.Select(xjo => xjo.ToObject()) - ?.Select(xo => { xo.Discord = this.Discord; return xo; }); - - var news = xc.NewValues?.OfType() - ?.Select(xjo => xjo.ToObject()) - ?.Select(xo => { xo.Discord = this.Discord; return xo; }); - - entrychn.OverwriteChange = new() - { - Before = olds != null ? new ReadOnlyCollection(new List(olds)) : null, - After = news != null ? new ReadOnlyCollection(new List(news)) : null - }; - break; - - case "topic": - entrychn.TopicChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "nsfw": - entrychn.NsfwChange = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue - }; - break; - - case "rtc_region": - entrychn.RtcRegionIdChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "bitrate": - entrychn.BitrateChange = new() - { - Before = (int?)(long?)xc.OldValue, - After = (int?)(long?)xc.NewValue - }; - break; - - case "user_limit": - entrychn.UserLimitChange = new() - { - Before = (int?)(long?)xc.OldValue, - After = (int?)(long?)xc.NewValue - }; - break; - - case "rate_limit_per_user": - entrychn.PerUserRateLimitChange = new() - { - Before = (int?)(long?)xc.OldValue, - After = (int?)(long?)xc.NewValue - }; - break; - - case "default_auto_archive_duration": - entrychn.DefaultAutoArchiveDurationChange = new() - { - Before = (ThreadAutoArchiveDuration?)(long?)xc.OldValue, - After = (ThreadAutoArchiveDuration?)(long?)xc.NewValue - }; - break; - case "available_tags": - var oldTags = xc.OldValues?.OfType() - ?.Select(xjo => xjo.ToObject()) - ?.Select(xo => { xo.Discord = this.Discord; return xo; }); - - var newTags = xc.NewValues?.OfType() - ?.Select(xjo => xjo.ToObject()) - ?.Select(xo => { xo.Discord = this.Discord; return xo; }); - - entrychn.AvailableTagsChange = new() - { - Before = oldTags != null ? new List(new List(oldTags)) : null, - After = newTags != null ? new List(new List(newTags)) : null - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in channel update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.OverwriteCreate: - case AuditLogActionType.OverwriteDelete: - case AuditLogActionType.OverwriteUpdate: - entry = new DiscordAuditLogOverwriteEntry - { - Target = this.GetChannel(xac.TargetId.Value)?.PermissionOverwrites.FirstOrDefault(xo => xo.Id == xac.Options.Id), - Channel = this.GetChannel(xac.TargetId.Value) - }; - - var entryovr = entry as DiscordAuditLogOverwriteEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "deny": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entryovr.DenyChange = new() - { - Before = p1 ? (Permissions?)t1 : null, - After = p2 ? (Permissions?)t2 : null - }; - break; - - case "allow": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entryovr.AllowChange = new() - { - Before = p1 ? (Permissions?)t1 : null, - After = p2 ? (Permissions?)t2 : null - }; - break; - - case "type": - entryovr.TypeChange = new() - { - Before = xc.OldValue != null ? (OverwriteType)(long)xc.OldValue : null, - After = xc.NewValue != null ? (OverwriteType)(long)xc.NewValue : null - }; - break; - - case "id": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entryovr.TargetIdChange = new() - { - Before = p1 ? t1 : null, - After = p2 ? t2 : null - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in overwrite update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.Kick: - entry = new DiscordAuditLogKickEntry - { - Target = amd.TryGetValue(xac.TargetId.Value, out var kickMember) ? kickMember : new() { Id = xac.TargetId.Value, Discord = this.Discord, GuildId = this.Id } - }; - break; - - case AuditLogActionType.Prune: - entry = new DiscordAuditLogPruneEntry - { - Days = xac.Options.DeleteMemberDays, - Toll = xac.Options.MembersRemoved - }; - break; - - case AuditLogActionType.Ban: - case AuditLogActionType.Unban: - entry = new DiscordAuditLogBanEntry - { - Target = amd.TryGetValue(xac.TargetId.Value, out var unbanMember) ? unbanMember : new() { Id = xac.TargetId.Value, Discord = this.Discord, GuildId = this.Id } - }; - break; - - case AuditLogActionType.MemberUpdate: - case AuditLogActionType.MemberRoleUpdate: - entry = new DiscordAuditLogMemberUpdateEntry - { - Target = amd.TryGetValue(xac.TargetId.Value, out var roleUpdMember) ? roleUpdMember : new() { Id = xac.TargetId.Value, Discord = this.Discord, GuildId = this.Id } - }; - - var entrymbu = entry as DiscordAuditLogMemberUpdateEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "nick": - entrymbu.NicknameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "deaf": - entrymbu.DeafenChange = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue - }; - break; - - case "mute": - entrymbu.MuteChange = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue - }; - break; - case "communication_disabled_until": - entrymbu.CommunicationDisabledUntilChange = new() - { - Before = (DateTime?)xc.OldValue, - After = (DateTime?)xc.NewValue - }; - break; - - case "$add": - entrymbu.AddedRoles = new ReadOnlyCollection(xc.NewValues.Select(xo => (ulong)xo["id"]).Select(this.GetRole).ToList()); - break; - - case "$remove": - entrymbu.RemovedRoles = new ReadOnlyCollection(xc.NewValues.Select(xo => (ulong)xo["id"]).Select(this.GetRole).ToList()); - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in member update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.RoleCreate: - case AuditLogActionType.RoleDelete: - case AuditLogActionType.RoleUpdate: - entry = new DiscordAuditLogRoleUpdateEntry - { - Target = this.GetRole(xac.TargetId.Value) ?? new DiscordRole { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entryrol = entry as DiscordAuditLogRoleUpdateEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entryrol.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "color": - p1 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t3); - p2 = int.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t4); - - entryrol.ColorChange = new() - { - Before = p1 ? t3 : null, - After = p2 ? t4 : null - }; - break; - - case "permissions": - entryrol.PermissionChange = new() - { - Before = xc.OldValue != null ? (Permissions?)long.Parse((string)xc.OldValue) : null, - After = xc.NewValue != null ? (Permissions?)long.Parse((string)xc.NewValue) : null - }; - break; - - case "position": - entryrol.PositionChange = new() - { - Before = xc.OldValue != null ? (int?)(long)xc.OldValue : null, - After = xc.NewValue != null ? (int?)(long)xc.NewValue : null, - }; - break; - - case "mentionable": - entryrol.MentionableChange = new() - { - Before = xc.OldValue != null ? (bool?)xc.OldValue : null, - After = xc.NewValue != null ? (bool?)xc.NewValue : null - }; - break; - - case "hoist": - entryrol.HoistChange = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue - }; - break; - - case "icon_hash": - entryrol.IconHashChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in role update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.InviteCreate: - case AuditLogActionType.InviteDelete: - case AuditLogActionType.InviteUpdate: - entry = new DiscordAuditLogInviteEntry(); - - var inv = new DiscordInvite - { - Discord = this.Discord, - Guild = new() - { - Discord = this.Discord, - Id = this.Id, - Name = this.Name, - SplashHash = this.SplashHash - } - }; - - var entryinv = entry as DiscordAuditLogInviteEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "max_age": - p1 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t3); - p2 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t4); - - entryinv.MaxAgeChange = new() - { - Before = p1 ? t3 : null, - After = p2 ? t4 : null - }; - break; - - case "code": - inv.Code = xc.OldValueString ?? xc.NewValueString; - - entryinv.CodeChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "temporary": - entryinv.TemporaryChange = new() - { - Before = xc.OldValue != null ? (bool?)xc.OldValue : null, - After = xc.NewValue != null ? (bool?)xc.NewValue : null - }; - break; - - case "inviter_id": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entryinv.InviterChange = new() - { - Before = amd.TryGetValue(t1, out var propBeforeMember) ? propBeforeMember : new() { Id = t1, Discord = this.Discord, GuildId = this.Id }, - After = amd.TryGetValue(t2, out var propAfterMember) ? propAfterMember : new() { Id = t1, Discord = this.Discord, GuildId = this.Id }, - }; - break; - - case "channel_id": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entryinv.ChannelChange = new() - { - Before = p1 ? this.GetChannel(t1) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id } : null, - After = p2 ? this.GetChannel(t2) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id } : null - }; - - var ch = entryinv.ChannelChange.Before ?? entryinv.ChannelChange.After; - var cht = ch?.Type; - inv.Channel = new() - { - Discord = this.Discord, - Id = p1 ? t1 : t2, - Name = ch?.Name, - Type = cht != null ? cht.Value : ChannelType.Unknown - }; - break; - - case "uses": - p1 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t3); - p2 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t4); - - entryinv.UsesChange = new() - { - Before = p1 ? t3 : null, - After = p2 ? t4 : null - }; - break; - - case "max_uses": - p1 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t3); - p2 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t4); - - entryinv.MaxUsesChange = new() - { - Before = p1 ? t3 : null, - After = p2 ? t4 : null - }; - break; - - // TODO: Add changes for target application - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in invite update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - - entryinv.Target = inv; - break; - - case AuditLogActionType.WebhookCreate: - case AuditLogActionType.WebhookDelete: - case AuditLogActionType.WebhookUpdate: - entry = new DiscordAuditLogWebhookEntry - { - Target = ahd.TryGetValue(xac.TargetId.Value, out var webhook) ? webhook : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entrywhk = entry as DiscordAuditLogWebhookEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "application_id": // ??? - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entrywhk.IdChange = new() - { - Before = p1 ? t1 : null, - After = p2 ? t2 : null - }; - break; - - case "name": - entrywhk.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "channel_id": - p1 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entrywhk.ChannelChange = new() - { - Before = p1 ? this.GetChannel(t1) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id } : null, - After = p2 ? this.GetChannel(t2) ?? new DiscordChannel { Id = t1, Discord = this.Discord, GuildId = this.Id } : null - }; - break; - - case "type": // ??? - p1 = int.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t3); - p2 = int.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t4); - - entrywhk.TypeChange = new() - { - Before = p1 ? t3 : null, - After = p2 ? t4 : null - }; - break; - - case "avatar_hash": - entrywhk.AvatarHashChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in webhook update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.EmojiCreate: - case AuditLogActionType.EmojiDelete: - case AuditLogActionType.EmojiUpdate: - entry = new DiscordAuditLogEmojiEntry - { - Target = this.EmojisInternal.TryGetValue(xac.TargetId.Value, out var target) ? target : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entryemo = entry as DiscordAuditLogEmojiEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entryemo.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in emote update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.StageInstanceCreate: - case AuditLogActionType.StageInstanceDelete: - case AuditLogActionType.StageInstanceUpdate: - entry = new DiscordAuditLogStageEntry - { - Target = this.StageInstancesInternal.TryGetValue(xac.TargetId.Value, out var stage) ? stage : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entrysta = entry as DiscordAuditLogStageEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "topic": - entrysta.TopicChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in stage instance update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.StickerCreate: - case AuditLogActionType.StickerDelete: - case AuditLogActionType.StickerUpdate: - entry = new DiscordAuditLogStickerEntry - { - Target = this.StickersInternal.TryGetValue(xac.TargetId.Value, out var sticker) ? sticker : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entrysti = entry as DiscordAuditLogStickerEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entrysti.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - case "description": - entrysti.DescriptionChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - case "tags": - entrysti.TagsChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - case "guild_id": - entrysti.GuildIdChange = new() - { - Before = ulong.TryParse(xc.OldValueString, out var ogid) ? ogid : null, - After = ulong.TryParse(xc.NewValueString, out var ngid) ? ngid : null - }; - break; - case "available": - entrysti.AvailabilityChange = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue, - }; - break; - case "asset": - entrysti.AssetChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - case "id": - entrysti.IdChange = new() - { - Before = ulong.TryParse(xc.OldValueString, out var oid) ? oid : null, - After = ulong.TryParse(xc.NewValueString, out var nid) ? nid : null - }; - break; - case "type": - p1 = long.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t5); - p2 = long.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t6); - entrysti.TypeChange = new() - { - Before = p1 ? (StickerType?)t5 : null, - After = p2 ? (StickerType?)t6 : null - }; - break; - case "format_type": - p1 = long.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t5); - p2 = long.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t6); - entrysti.FormatChange = new() - { - Before = p1 ? (StickerFormat?)t5 : null, - After = p2 ? (StickerFormat?)t6 : null - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in sticker update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - - - case AuditLogActionType.MessageDelete: - case AuditLogActionType.MessageBulkDelete: - { - entry = new DiscordAuditLogMessageEntry(); - - var entrymsg = entry as DiscordAuditLogMessageEntry; - - if (xac.Options != null) - { - entrymsg.Channel = this.GetChannel(xac.Options.ChannelId) ?? new DiscordChannel { Id = xac.Options.ChannelId, Discord = this.Discord, GuildId = this.Id }; - entrymsg.MessageCount = xac.Options.Count; - } - - if (entrymsg.Channel != null) - { - entrymsg.Target = this.Discord is DiscordClient dc - && dc.MessageCache != null - && dc.MessageCache.TryGet(xm => xm.Id == xac.TargetId.Value && xm.ChannelId == entrymsg.Channel.Id, out var msg) - ? msg - : new() { Discord = this.Discord, Id = xac.TargetId.Value }; - } - break; - } - - case AuditLogActionType.MessagePin: - case AuditLogActionType.MessageUnpin: - { - entry = new DiscordAuditLogMessagePinEntry(); - - var entrypin = entry as DiscordAuditLogMessagePinEntry; - - if (this.Discord is not DiscordClient dc) - { - break; - } - - if (xac.Options != null) - { - DiscordMessage message = default; - dc.MessageCache?.TryGet(x => x.Id == xac.Options.MessageId && x.ChannelId == xac.Options.ChannelId, out message); - - entrypin.Channel = this.GetChannel(xac.Options.ChannelId) ?? new DiscordChannel { Id = xac.Options.ChannelId, Discord = this.Discord, GuildId = this.Id }; - entrypin.Message = message ?? new DiscordMessage { Id = xac.Options.MessageId, Discord = this.Discord }; - } - - if (xac.TargetId.HasValue) - { - dc.UserCache.TryGetValue(xac.TargetId.Value, out var user); - entrypin.Target = user ?? new DiscordUser { Id = user.Id, Discord = this.Discord }; - } - - break; - } - - case AuditLogActionType.BotAdd: - { - entry = new DiscordAuditLogBotAddEntry(); - - if (!(this.Discord is DiscordClient dc && xac.TargetId.HasValue)) - { - break; - } - - dc.UserCache.TryGetValue(xac.TargetId.Value, out var bot); - (entry as DiscordAuditLogBotAddEntry).TargetBot = bot ?? new DiscordUser { Id = xac.TargetId.Value, Discord = this.Discord }; - - break; - } - - case AuditLogActionType.MemberMove: - entry = new DiscordAuditLogMemberMoveEntry(); - - if (xac.Options == null) - { - break; - } - - var moveentry = entry as DiscordAuditLogMemberMoveEntry; - - moveentry.UserCount = xac.Options.Count; - moveentry.Channel = this.GetChannel(xac.Options.ChannelId) ?? new DiscordChannel { Id = xac.Options.ChannelId, Discord = this.Discord, GuildId = this.Id }; - break; - - case AuditLogActionType.MemberDisconnect: - entry = new DiscordAuditLogMemberDisconnectEntry - { - UserCount = xac.Options?.Count ?? 0 - }; - break; - - case AuditLogActionType.IntegrationCreate: - case AuditLogActionType.IntegrationDelete: - case AuditLogActionType.IntegrationUpdate: - entry = new DiscordAuditLogIntegrationEntry(); - - var integentry = entry as DiscordAuditLogIntegrationEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "type": - integentry.Type = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - case "enable_emoticons": - integentry.EnableEmoticons = new() - { - Before = (bool?)xc.OldValue, - After = (bool?)xc.NewValue - }; - break; - case "expire_behavior": - integentry.ExpireBehavior = new() - { - Before = (int?)xc.OldValue, - After = (int?)xc.NewValue - }; - break; - case "expire_grace_period": - integentry.ExpireBehavior = new() - { - Before = (int?)xc.OldValue, - After = (int?)xc.NewValue - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in integration update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - case AuditLogActionType.ThreadCreate: - case AuditLogActionType.ThreadDelete: - case AuditLogActionType.ThreadUpdate: - entry = new DiscordAuditLogThreadEntry - { - Target = this.ThreadsInternal.TryGetValue(xac.TargetId.Value, out var thread) ? thread : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entrythr = entry as DiscordAuditLogThreadEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "name": - entrythr.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "type": - p1 = ulong.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t1); - p2 = ulong.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t2); - - entrythr.TypeChange = new() - { - Before = p1 ? (ChannelType?)t1 : null, - After = p2 ? (ChannelType?)t2 : null - }; - break; - - case "archived": - entrythr.ArchivedChange = new() - { - Before = xc.OldValue != null ? (bool?)xc.OldValue : null, - After = xc.NewValue != null ? (bool?)xc.NewValue : null - }; - break; - - case "locked": - entrythr.LockedChange = new() - { - Before = xc.OldValue != null ? (bool?)xc.OldValue : null, - After = xc.NewValue != null ? (bool?)xc.NewValue : null - }; - break; - - case "invitable": - entrythr.InvitableChange = new() - { - Before = xc.OldValue != null ? (bool?)xc.OldValue : null, - After = xc.NewValue != null ? (bool?)xc.NewValue : null - }; - break; - - case "auto_archive_duration": - p1 = long.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t5); - p2 = long.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t6); - - entrythr.AutoArchiveDurationChange = new() - { - Before = p1 ? (ThreadAutoArchiveDuration?)t5 : null, - After = p2 ? (ThreadAutoArchiveDuration?)t6 : null - }; - break; - - case "rate_limit_per_user": - entrythr.PerUserRateLimitChange = new() - { - Before = (int?)(long?)xc.OldValue, - After = (int?)(long?)xc.NewValue - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in thread update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - - case AuditLogActionType.GuildScheduledEventCreate: - case AuditLogActionType.GuildScheduledEventDelete: - case AuditLogActionType.GuildScheduledEventUpdate: - entry = new DiscordAuditLogGuildScheduledEventEntry - { - Target = this.ScheduledEventsInternal.TryGetValue(xac.TargetId.Value, out var scheduledEvent) ? scheduledEvent : new() { Id = xac.TargetId.Value, Discord = this.Discord } - }; - - var entryse = entry as DiscordAuditLogGuildScheduledEventEntry; - foreach (var xc in xac.Changes) - { - switch (xc.Key.ToLowerInvariant()) - { - case "channel_id": - entryse.ChannelIdChange = new() - { - Before = ulong.TryParse(xc.OldValueString, out var ogid) ? ogid : null, - After = ulong.TryParse(xc.NewValueString, out var ngid) ? ngid : null - }; - break; - - case "name": - entryse.NameChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "description": - entryse.DescriptionChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "location": - entryse.LocationChange = new() - { - Before = xc.OldValueString, - After = xc.NewValueString - }; - break; - - case "entity_type": - p1 = long.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t5); - p2 = long.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t6); - - entryse.EntityTypeChange = new() - { - Before = p1 ? (ScheduledEventEntityType?)t5 : null, - After = p2 ? (ScheduledEventEntityType?)t6 : null - }; - break; - - case "status": - p1 = long.TryParse(xc.OldValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t5); - p2 = long.TryParse(xc.NewValue as string, NumberStyles.Integer, CultureInfo.InvariantCulture, out t6); - - entryse.StatusChange = new() - { - Before = p1 ? (ScheduledEventStatus?)t5 : null, - After = p2 ? (ScheduledEventStatus?)t6 : null - }; - break; - - default: - if (this.Discord.Configuration.ReportMissingFields) - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown key in scheduled event update: {Key} - this should be reported to library developers", xc.Key); - break; - } - } - break; - - // TODO: Handle ApplicationCommandPermissionUpdate - case AuditLogActionType.ApplicationCommandPermissionUpdate: - break; - - // TODO: Implement auto mod audit log - case AuditLogActionType.AutoModerationRuleCreate: - case AuditLogActionType.AutoModerationRuleUpdate: - case AuditLogActionType.AutoModerationRuleDelete: - break; - - case AuditLogActionType.AutoModerationBlockMessage: - break; - - case AuditLogActionType.AutoModerationFlagMessage: - break; - - case AuditLogActionType.AutoModerationTimeOutUser: - break; - - case AuditLogActionType.AutoModerationQuarantineUser: - break; - - case AuditLogActionType.OnboardingQuestionCreate: - case AuditLogActionType.OnboardingQuestionUpdate: - case AuditLogActionType.OnboardingUpdate: - case AuditLogActionType.ServerGuideCreate: - case AuditLogActionType.ServerGuideUpdate: - break; - - case AuditLogActionType.VoiceChannelStatusUpdate: - break; - - default: - this.Discord.Logger.LogWarning(LoggerEvents.AuditLog, "Unknown audit log action type: {Key} - this should be reported to library developers", (int)xac.ActionType); - break; - } - - if (entry == null) - continue; - - entry.ActionCategory = xac.ActionType switch - { - AuditLogActionType.ChannelCreate or AuditLogActionType.EmojiCreate or AuditLogActionType.InviteCreate or AuditLogActionType.OverwriteCreate or AuditLogActionType.RoleCreate or AuditLogActionType.WebhookCreate or AuditLogActionType.IntegrationCreate or AuditLogActionType.StickerCreate or AuditLogActionType.StageInstanceCreate or AuditLogActionType.ThreadCreate or AuditLogActionType.GuildScheduledEventCreate or AuditLogActionType.AutoModerationRuleCreate or AuditLogActionType.OnboardingQuestionCreate or AuditLogActionType.ServerGuideCreate => AuditLogActionCategory.Create, - AuditLogActionType.ChannelDelete or AuditLogActionType.EmojiDelete or AuditLogActionType.InviteDelete or AuditLogActionType.MessageDelete or AuditLogActionType.MessageBulkDelete or AuditLogActionType.OverwriteDelete or AuditLogActionType.RoleDelete or AuditLogActionType.WebhookDelete or AuditLogActionType.IntegrationDelete or AuditLogActionType.StickerDelete or AuditLogActionType.StageInstanceDelete or AuditLogActionType.ThreadDelete or AuditLogActionType.GuildScheduledEventDelete or AuditLogActionType.AutoModerationRuleDelete => AuditLogActionCategory.Delete, - AuditLogActionType.ChannelUpdate or AuditLogActionType.EmojiUpdate or AuditLogActionType.InviteUpdate or AuditLogActionType.MemberRoleUpdate or AuditLogActionType.MemberUpdate or AuditLogActionType.OverwriteUpdate or AuditLogActionType.RoleUpdate or AuditLogActionType.WebhookUpdate or AuditLogActionType.IntegrationUpdate or AuditLogActionType.StickerUpdate or AuditLogActionType.StageInstanceUpdate or AuditLogActionType.ThreadUpdate or AuditLogActionType.GuildScheduledEventUpdate or AuditLogActionType.AutoModerationRuleUpdate or AuditLogActionType.OnboardingQuestionUpdate or AuditLogActionType.OnboardingUpdate or AuditLogActionType.ServerGuideUpdate or AuditLogActionType.VoiceChannelStatusUpdate => AuditLogActionCategory.Update, - _ => AuditLogActionCategory.Other, - }; - entry.Discord = this.Discord; - entry.ActionType = xac.ActionType; - entry.Id = xac.Id; - entry.Reason = xac.Reason; - entry.UserResponsible = amd.Any() && amd.TryGetValue(xac.UserId, out var resp) ? resp : this.MembersInternal[xac.UserId]; - entries.Add(entry); - } - - return new ReadOnlyCollection(entries); - } -} diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.Features.cs b/DisCatSharp/Entities/Guild/DiscordGuild.Features.cs index 07da4d43e3..68d2ad49da 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuild.Features.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuild.Features.cs @@ -149,6 +149,7 @@ private static string AddSpacesToWord(string text) { if (string.IsNullOrWhiteSpace(text)) return ""; + var newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (var i = 1; i < text.Length; i++) @@ -157,6 +158,7 @@ private static string AddSpacesToWord(string text) newText.Append(' '); newText.Append(text[i]); } + return newText.ToString(); } } @@ -640,5 +642,5 @@ public enum GuildFeaturesEnum RaidAlertsEnabled, - UsesApplicationCommandsPermissionsV2, + UsesApplicationCommandsPermissionsV2 } diff --git a/DisCatSharp/Entities/Guild/DiscordGuild.cs b/DisCatSharp/Entities/Guild/DiscordGuild.cs index 29dafed49f..003859ca66 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuild.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuild.cs @@ -54,7 +54,7 @@ public string IconUrl /// [JsonIgnore] public string SplashUrl - => !string.IsNullOrWhiteSpace(this.SplashHash) ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.SplashHash}.png?size=1024" : null; + => !string.IsNullOrWhiteSpace(this.SplashHash) ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.SplashHash}.png?size=1024" : null; /// /// Gets the guild discovery splash's hash. @@ -143,6 +143,7 @@ public DiscordChannel AfkChannel [JsonIgnore] public ReadOnlyCollection RegisteredApplicationCommands => new(this.InternalRegisteredApplicationCommands); + [JsonIgnore] internal List InternalRegisteredApplicationCommands { get; set; } = new(); @@ -188,8 +189,8 @@ public ReadOnlyCollection RegisteredApplicationComman [JsonIgnore] public DiscordChannel SystemChannel => this.SystemChannelId.HasValue - ? this.GetChannel(this.SystemChannelId.Value) - : null; + ? this.GetChannel(this.SystemChannelId.Value) + : null; /// /// Gets the settings for this guild's system channel. @@ -215,8 +216,8 @@ public DiscordChannel SystemChannel [JsonIgnore] public DiscordChannel WidgetChannel => this.WidgetChannelId.HasValue - ? this.GetChannel(this.WidgetChannelId.Value) - : null; + ? this.GetChannel(this.WidgetChannelId.Value) + : null; /// /// Gets the safety alerts channel id. @@ -230,8 +231,8 @@ public DiscordChannel WidgetChannel [JsonIgnore, RequiresFeature(Attributes.Features.Community)] public DiscordChannel SafetyAltersChannel => this.SafetyAlertsChannelId.HasValue - ? this.GetChannel(this.SafetyAlertsChannelId.Value) - : null; + ? this.GetChannel(this.SafetyAlertsChannelId.Value) + : null; /// /// Gets the rules channel id. @@ -246,8 +247,8 @@ public DiscordChannel SafetyAltersChannel [JsonIgnore, RequiresFeature(Attributes.Features.Community)] public DiscordChannel RulesChannel => this.RulesChannelId.HasValue - ? this.GetChannel(this.RulesChannelId.Value) - : null; + ? this.GetChannel(this.RulesChannelId.Value) + : null; /// /// Gets the public updates channel id. @@ -262,8 +263,8 @@ public DiscordChannel RulesChannel [JsonIgnore, RequiresFeature(Attributes.Features.Community)] public DiscordChannel PublicUpdatesChannel => this.PublicUpdatesChannelId.HasValue - ? this.GetChannel(this.PublicUpdatesChannelId.Value) - : null; + ? this.GetChannel(this.PublicUpdatesChannelId.Value) + : null; /// /// Gets the application id of this guild if it is bot created. @@ -278,8 +279,7 @@ public DiscordChannel PublicUpdatesChannel public IReadOnlyDictionary Roles => new ReadOnlyConcurrentDictionary(this.RolesInternal); - [JsonProperty("roles", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("roles", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary RolesInternal; /// @@ -289,8 +289,7 @@ public IReadOnlyDictionary Roles public IReadOnlyDictionary Stickers => new ReadOnlyConcurrentDictionary(this.StickersInternal); - [JsonProperty("stickers", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("stickers", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary StickersInternal; /// @@ -300,8 +299,7 @@ public IReadOnlyDictionary Stickers public IReadOnlyDictionary Emojis => new ReadOnlyConcurrentDictionary(this.EmojisInternal); - [JsonProperty("emojis", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("emojis", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary EmojisInternal; /// @@ -389,8 +387,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary VoiceStates => new ReadOnlyConcurrentDictionary(this.VoiceStatesInternal); - [JsonProperty("voice_states", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("voice_states", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary VoiceStatesInternal; /// @@ -399,8 +396,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary Members => new ReadOnlyConcurrentDictionary(this.MembersInternal); - [JsonProperty("members", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("members", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary MembersInternal; /// @@ -409,8 +405,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary Channels => new ReadOnlyConcurrentDictionary(this.ChannelsInternal); - [JsonProperty("channels", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("channels", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary ChannelsInternal; internal ConcurrentDictionary Invites; @@ -421,8 +416,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary Threads { get; internal set; } - [JsonProperty("threads", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("threads", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary ThreadsInternal = new(); /// @@ -431,8 +425,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary StageInstances { get; internal set; } - [JsonProperty("stage_instances", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("stage_instances", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary StageInstancesInternal = new(); /// @@ -441,8 +434,7 @@ public IReadOnlyDictionary Emojis [JsonIgnore] public IReadOnlyDictionary ScheduledEvents { get; internal set; } - [JsonProperty("guild_scheduled_events", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("guild_scheduled_events", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary ScheduledEventsInternal = new(); /// @@ -602,6 +594,7 @@ private Dictionary InternalSortChannels() foreach (var chan in orderedChannel.Value) keyValuePairs.Add(chan.Id, chan); } + return keyValuePairs; } @@ -618,31 +611,23 @@ public Dictionary> GetOrderedChannels() Dictionary> orderedChannels = new() { - { 0, new() } + { + 0, new() + } }; foreach (var channel in rawChannels.Where(c => c.Type == ChannelType.Category).OrderBy(c => c.Position)) - { orderedChannels.Add(channel.Id, new()); - } foreach (var channel in rawChannels.Where(c => c.ParentId.HasValue && (c.Type == ChannelType.Text || c.Type == ChannelType.News || c.Type == ChannelType.Forum)).OrderBy(c => c.Position)) - { orderedChannels[channel.ParentId.Value!].Add(channel); - } foreach (var channel in rawChannels.Where(c => c.ParentId.HasValue && (c.Type == ChannelType.Voice || c.Type == ChannelType.Stage)).OrderBy(c => c.Position)) - { orderedChannels[channel.ParentId.Value!].Add(channel); - } foreach (var channel in rawChannels.Where(c => !c.ParentId.HasValue && c.Type != ChannelType.Category && (c.Type == ChannelType.Text || c.Type == ChannelType.News || c.Type == ChannelType.Forum)).OrderBy(c => c.Position)) - { orderedChannels[0].Add(channel); - } foreach (var channel in rawChannels.Where(c => !c.ParentId.HasValue && c.Type != ChannelType.Category && (c.Type == ChannelType.Voice || c.Type == ChannelType.Stage)).OrderBy(c => c.Position)) - { orderedChannels[0].Add(channel); - } return orderedChannels; } @@ -660,31 +645,23 @@ public async Task>> GetOrderedChannelsAsy Dictionary> orderedChannels = new() { - { 0, new() } + { + 0, new() + } }; foreach (var channel in rawChannels.Where(c => c.Type == ChannelType.Category).OrderBy(c => c.Position)) - { orderedChannels.Add(channel.Id, new()); - } foreach (var channel in rawChannels.Where(c => c.ParentId.HasValue && (c.Type == ChannelType.Text || c.Type == ChannelType.News || c.Type == ChannelType.Forum)).OrderBy(c => c.Position)) - { orderedChannels[channel.ParentId.Value!].Add(channel); - } foreach (var channel in rawChannels.Where(c => c.ParentId.HasValue && (c.Type == ChannelType.Voice || c.Type == ChannelType.Stage)).OrderBy(c => c.Position)) - { orderedChannels[channel.ParentId.Value!].Add(channel); - } foreach (var channel in rawChannels.Where(c => !c.ParentId.HasValue && c.Type != ChannelType.Category && (c.Type == ChannelType.Text || c.Type == ChannelType.News || c.Type == ChannelType.Forum)).OrderBy(c => c.Position)) - { orderedChannels[0].Add(channel); - } foreach (var channel in rawChannels.Where(c => !c.ParentId.HasValue && c.Type != ChannelType.Category && (c.Type == ChannelType.Voice || c.Type == ChannelType.Stage)).OrderBy(c => c.Position)) - { orderedChannels[0].Add(channel); - } return orderedChannels; } @@ -707,7 +684,7 @@ internal DiscordGuild() this.ScheduledEvents = new ReadOnlyConcurrentDictionary(this.ScheduledEventsInternal); } - #region Guild Methods +#region Guild Methods /// /// Gets this guilds onboarding configuration. @@ -730,9 +707,13 @@ public Task GetOnboardingAsync() /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. [RequiresFeature(Attributes.Features.Community)] - public Task ModifyOnboardingAsync(Optional> prompts = default, - Optional> defaultChannelIds = default, Optional enabled = default, Optional mode = default, - string? reason = null) + public Task ModifyOnboardingAsync( + Optional> prompts = default, + Optional> defaultChannelIds = default, + Optional enabled = default, + Optional mode = default, + string? reason = null + ) => this.Discord.ApiClient.ModifyGuildOnboardingAsync(this.Id, prompts, defaultChannelIds, enabled, mode, reason); @@ -782,8 +763,14 @@ public Task> SearchMembersAsync(string name, int? l /// Thrown when the or is not found. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public Task AddMemberAsync(DiscordUser user, string accessToken, string nickname = null, IEnumerable roles = null, - bool muted = false, bool deaf = false) + public Task AddMemberAsync( + DiscordUser user, + string accessToken, + string nickname = null, + IEnumerable roles = null, + bool muted = false, + bool deaf = false + ) => this.Discord.ApiClient.AddGuildMemberAsync(this.Id, user.Id, accessToken, nickname, roles, muted, deaf); /// @@ -811,7 +798,6 @@ public Task EnableMfaAsync(string? reason = null) /// Thrown when the current user is not the guilds owner. /// Thrown when the guild does not exist. /// Thrown when Discord is unable to process the request. - public Task DisableMfaAsync(string? reason = null) => this.IsOwner ? this.Discord.ApiClient.DisableGuildMfaAsync(this.Id, reason) : throw new("The current user does not own the guild."); @@ -875,9 +861,7 @@ public async Task ModifyCommunitySettingsAsync(bool enabled, Disco { var verificationLevel = this.VerificationLevel; if (this.VerificationLevel != VerificationLevel.Highest) - { verificationLevel = VerificationLevel.High; - } var explicitContentFilter = ExplicitContentFilter.AllMembers; @@ -893,13 +877,9 @@ public async Task ModifyCommunitySettingsAsync(bool enabled, Disco var rfeatures = this.RawFeatures.ToList(); if (!this.RawFeatures.Contains("COMMUNITY") && enabled) - { rfeatures.Add("COMMUNITY"); - } else if (this.RawFeatures.Contains("COMMUNITY") && !enabled) - { rfeatures.Remove("COMMUNITY"); - } return await this.Discord.ApiClient.ModifyGuildCommunitySettingsAsync(this.Id, rfeatures, rulesChannelId, publicUpdatesChannelId, preferredLocale, description, defaultMessageNotifications, explicitContentFilter, verificationLevel, reason).ConfigureAwait(false); } @@ -937,13 +917,9 @@ public async Task ModifySafetyAlertsSettingsAsync(bool enabled, Di var rfeatures = this.RawFeatures.ToList(); if (!this.RawFeatures.Contains("RAID_ALERTS_ENABLED") && enabled) - { rfeatures.Add("RAID_ALERTS_ENABLED"); - } else if (this.RawFeatures.Contains("RAID_ALERTS_ENABLED") && !enabled) - { rfeatures.Remove("RAID_ALERTS_ENABLED"); - } return await this.Discord.ApiClient.ModifyGuildSafetyAlertsSettingsAsync(this.Id, rfeatures, safetyAlertsChannelId, reason).ConfigureAwait(false); } @@ -1161,7 +1137,6 @@ public Task GetBanAsync(ulong userId) } } - /// /// Gets a ban for a specific user. /// @@ -1222,11 +1197,20 @@ public Task GetAutomodRuleAsync(ulong ruleId) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. [RequiresFeature(Attributes.Features.Community)] - public async Task CreateAutomodRuleAsync(string name, AutomodEventType eventType, AutomodTriggerType triggerType, IEnumerable actions, - AutomodTriggerMetadata triggerMetadata = null, bool enabled = false, IEnumerable exemptRoles = null, IEnumerable exemptChannels = null, string reason = null) + public async Task CreateAutomodRuleAsync( + string name, + AutomodEventType eventType, + AutomodTriggerType triggerType, + IEnumerable actions, + AutomodTriggerMetadata triggerMetadata = null, + bool enabled = false, + IEnumerable exemptRoles = null, + IEnumerable exemptChannels = null, + string reason = null + ) => await this.Discord.ApiClient.CreateAutomodRuleAsync(this.Id, name, eventType, triggerType, actions, triggerMetadata, enabled, exemptRoles, exemptChannels, reason).ConfigureAwait(false); - #region Scheduled Events +#region Scheduled Events /// /// Creates a scheduled event. @@ -1270,7 +1254,6 @@ public async Task CreateExternalScheduledEventAsync(strin return await this.Discord.ApiClient.CreateGuildScheduledEventAsync(this.Id, null, new(location), name, scheduledStartTime, scheduledEndTime, description, ScheduledEventEntityType.External, coverb64, reason).ConfigureAwait(false); } - /// /// Gets a specific scheduled events. /// @@ -1345,7 +1328,8 @@ public async Task GetScheduledEventAsync(DiscordScheduled /// Thrown when Discord is unable to process the request. public async Task> GetScheduledEventsAsync(bool? withUserCount = null) => await this.Discord.ApiClient.ListGuildScheduledEventsAsync(this.Id, withUserCount).ConfigureAwait(false); - #endregion + +#endregion /// /// Creates a new text channel in this guild. @@ -1388,8 +1372,21 @@ public Task CreateTextChannelAsync(string name, DiscordChannel p /// Thrown when the guild does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public Task CreateForumChannelAsync(string name, DiscordChannel parent = null, Optional topic = default, IEnumerable overwrites = null, bool? nsfw = null, Optional defaultReactionEmoji = default, Optional perUserRateLimit = default, Optional postCreateUserRateLimit = default, ThreadAutoArchiveDuration defaultAutoArchiveDuration = ThreadAutoArchiveDuration.OneDay, Optional defaultSortOrder = default, Optional flags = default, string reason = null) - => this.Discord.ApiClient.CreateForumChannelAsync(this.Id, name, parent?.Id, topic, null, nsfw, defaultReactionEmoji, perUserRateLimit, postCreateUserRateLimit, defaultSortOrder, defaultAutoArchiveDuration, overwrites, flags, reason); + public Task CreateForumChannelAsync( + string name, + DiscordChannel parent = null, + Optional topic = default, + IEnumerable overwrites = null, + bool? nsfw = null, + Optional defaultReactionEmoji = default, + Optional perUserRateLimit = default, + Optional postCreateUserRateLimit = default, + ThreadAutoArchiveDuration defaultAutoArchiveDuration = ThreadAutoArchiveDuration.OneDay, + Optional defaultSortOrder = default, + Optional flags = default, + string reason = null + ) + => this.Discord.ApiClient.CreateForumChannelAsync(this.Id, name, parent?.Id, topic, null, nsfw, defaultReactionEmoji, perUserRateLimit, postCreateUserRateLimit, defaultSortOrder, defaultAutoArchiveDuration, overwrites, flags, reason); /// /// Creates a new channel category in this guild. @@ -1479,7 +1476,21 @@ public Task CreateVoiceChannelAsync(string name, DiscordChannel /// Thrown when the guild does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. - public Task CreateChannelAsync(string name, ChannelType type, DiscordChannel parent = null, Optional topic = default, int? bitrate = null, int? userLimit = null, IEnumerable overwrites = null, bool? nsfw = null, Optional perUserRateLimit = default, VideoQualityMode? qualityMode = null, ThreadAutoArchiveDuration? defaultAutoArchiveDuration = null, Optional flags = default, string reason = null) => + public Task CreateChannelAsync( + string name, + ChannelType type, + DiscordChannel parent = null, + Optional topic = default, + int? bitrate = null, + int? userLimit = null, + IEnumerable overwrites = null, + bool? nsfw = null, + Optional perUserRateLimit = default, + VideoQualityMode? qualityMode = null, + ThreadAutoArchiveDuration? defaultAutoArchiveDuration = null, + Optional flags = default, + string reason = null + ) => // technically you can create news/store channels but not always type != ChannelType.Text && type != ChannelType.Voice && type != ChannelType.Category && type != ChannelType.News && type != ChannelType.Store && type != ChannelType.Stage ? throw new ArgumentException("Channel type must be text, voice, stage, or category.", nameof(type)) @@ -1654,10 +1665,8 @@ public async Task> GetInvitesAsync() var intents = this.Discord.Configuration.Intents; if (!intents.HasIntent(DiscordIntents.GuildInvites)) - { foreach (var r in res) this.Invites[r.Code] = r; - } return res; } @@ -1693,7 +1702,7 @@ public string GetWidgetImage(WidgetType bannerType = WidgetType.Shield) WidgetType.Banner2 => "banner2", WidgetType.Banner3 => "banner3", WidgetType.Banner4 => "banner4", - _ => "shield", + _ => "shield" }; return $"{Endpoints.BASE_URI}{Endpoints.GUILDS}/{this.Id}{Endpoints.WIDGET_PNG}?style={param}"; } @@ -1716,12 +1725,8 @@ public async Task GetMemberAsync(ulong userId, bool fetch = false var intents = this.Discord.Configuration.Intents; if (intents.HasIntent(DiscordIntents.GuildMembers)) - { if (this.MembersInternal != null) - { this.MembersInternal[userId] = mbr; - } - } return mbr; } @@ -1747,7 +1752,10 @@ public async Task> GetAllMembersAsync() foreach (var xtm in tms) { - var usr = new DiscordUser(xtm.User) { Discord = this.Discord }; + var usr = new DiscordUser(xtm.User) + { + Discord = this.Discord + }; usr = this.Discord.UserCache.AddOrUpdate(xtm.User.Id, usr, (id, old) => { @@ -1763,7 +1771,10 @@ public async Task> GetAllMembersAsync() old.GlobalName = usr.GlobalName; return old; }); - var mbr = new DiscordMember(xtm) { Discord = this.Discord, GuildId = this.Id }; + var mbr = new DiscordMember(xtm) + { + Discord = this.Discord, GuildId = this.Id + }; recmbr.Add(mbr); if (hasIntent) this.MembersInternal[usr.Id] = mbr; @@ -1808,8 +1819,7 @@ public async Task RequestMembersAsync(string query = "", int limit = 0, bool? pr var payload = new GatewayPayload { - OpCode = GatewayOpCode.RequestGuildMembers, - Data = grgm + OpCode = GatewayOpCode.RequestGuildMembers, Data = grgm }; var payloadStr = JsonConvert.SerializeObject(payload, Formatting.None); @@ -1961,7 +1971,6 @@ public async Task> GetStickersAsync() var stickers = await this.Discord.ApiClient.GetGuildStickersAsync(this.Id).ConfigureAwait(false); foreach (var xstr in stickers) - { this.StickersInternal.AddOrUpdate(xstr.Id, xstr, (id, old) => { old.Name = xstr.Name; @@ -1969,7 +1978,6 @@ public async Task> GetStickersAsync() old.InternalTags = xstr.InternalTags; return old; }); - } return stickers; } @@ -2018,10 +2026,10 @@ public Task CreateStickerAsync(string name, string description, return emoji.Id is not 0 ? throw new InvalidOperationException("Only unicode emoji can be used for stickers.") : name.Length < 2 || name.Length > 30 - ? throw new ArgumentOutOfRangeException(nameof(name), "Sticker name needs to be between 2 and 30 characters long.") - : description.Length < 1 || description.Length > 100 - ? throw new ArgumentOutOfRangeException(nameof(description), "Sticker description needs to be between 1 and 100 characters long.") - : this.Discord.ApiClient.CreateGuildStickerAsync(this.Id, name, description, emoji.GetDiscordName().Replace(":", ""), new("sticker", file, null, fileExt, contentType), reason); + ? throw new ArgumentOutOfRangeException(nameof(name), "Sticker name needs to be between 2 and 30 characters long.") + : description.Length < 1 || description.Length > 100 + ? throw new ArgumentOutOfRangeException(nameof(description), "Sticker description needs to be between 1 and 100 characters long.") + : this.Discord.ApiClient.CreateGuildStickerAsync(this.Id, name, description, emoji.GetDiscordName().Replace(":", ""), new("sticker", file, null, fileExt, contentType), reason); } /// @@ -2054,7 +2062,6 @@ public async Task ModifyStickerAsync(ulong sticker, Optional ModifyWelcomeScreenAsync(Action + /// Gets audit log entries for this guild. + /// + /// Maximum number of entries to fetch. + /// Filter by member responsible. + /// Filter by action type. + /// A collection of requested audit log entries. + /// Thrown when the client does not have the permission. + /// Thrown when Discord is unable to process the request. + public async Task> GetAuditLogsAsync(int? limit = null, DiscordMember? byMember = null, AuditLogActionType? actionType = null) + { + var alrs = new List(); + int ac = 1, tc = 0; + var last = 0ul; + while (ac > 0) + { + var rmn = limit != null ? limit.Value - tc : 100; + rmn = Math.Min(100, rmn); + if (rmn <= 0) break; + + var alr = await this.Discord.ApiClient.GetAuditLogsAsync(this.Id, rmn, null, last == 0 ? null : last, byMember?.Id, (int?)actionType).ConfigureAwait(false); + ac = alr.Entries.Count; + tc += ac; + if (ac <= 0) + continue; + + last = alr.Entries[^1].Id; + alr.Entries.ForEach(x => x.Discord = (DiscordClient)this.Discord); + alrs.Add(alr); + } + + return alrs; + } + +#endregion /// /// Returns a string representation of this guild. @@ -2318,7 +2360,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Guild/DiscordGuildInventorySettings.cs b/DisCatSharp/Entities/Guild/DiscordGuildInventorySettings.cs index b7b6e3e2b2..7813487cd9 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuildInventorySettings.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuildInventorySettings.cs @@ -1,4 +1,3 @@ - using Newtonsoft.Json; namespace DisCatSharp.Entities; diff --git a/DisCatSharp/Entities/Guild/DiscordGuildPreview.cs b/DisCatSharp/Entities/Guild/DiscordGuildPreview.cs index 47bb15d62a..39e171088f 100644 --- a/DisCatSharp/Entities/Guild/DiscordGuildPreview.cs +++ b/DisCatSharp/Entities/Guild/DiscordGuildPreview.cs @@ -45,7 +45,7 @@ public string IconUrl /// [JsonIgnore] public string SplashUrl - => !string.IsNullOrWhiteSpace(this.SplashHash) ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.SplashHash}.png?size=1024" : null; + => !string.IsNullOrWhiteSpace(this.SplashHash) ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.SPLASHES}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.SplashHash}.png?size=1024" : null; /// /// Gets the guild discovery splash's hash. @@ -66,8 +66,7 @@ public string DiscoverySplashUrl [JsonIgnore] public IReadOnlyDictionary Emojis => new ReadOnlyConcurrentDictionary(this.EmojisInternal); - [JsonProperty("emojis", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("emojis", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary EmojisInternal; /// @@ -76,11 +75,9 @@ public string DiscoverySplashUrl [JsonIgnore] public IReadOnlyDictionary Stickers => new ReadOnlyConcurrentDictionary(this.StickersInternal); - [JsonProperty("stickers", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("stickers", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary StickersInternal; - /// /// Gets a collection of this guild's features. /// diff --git a/DisCatSharp/Entities/Guild/DiscordMember.cs b/DisCatSharp/Entities/Guild/DiscordMember.cs index 4809bfec33..8a6072806e 100644 --- a/DisCatSharp/Entities/Guild/DiscordMember.cs +++ b/DisCatSharp/Entities/Guild/DiscordMember.cs @@ -135,7 +135,7 @@ public override DiscordColor? BannerColor /// [JsonIgnore] public string DisplayName - => this.Nickname ?? (this.IsMigrated ? (this.GlobalName ?? this.Username) : this.Username); + => this.Nickname ?? (this.IsMigrated ? this.GlobalName ?? this.Username : this.Username); /// /// List of role ids @@ -146,6 +146,7 @@ internal IReadOnlyList RoleIds [JsonProperty("roles", NullValueHandling = NullValueHandling.Ignore)] internal List RoleIdsInternal; + [JsonIgnore] private readonly Lazy> _roleIdsLazy; @@ -207,7 +208,6 @@ public bool IsCommunicationDisabled public bool HasUnusualDmActivity => this.UnusualDmActivityUntil != null && this.UnusualDmActivityUntil.Value.ToUniversalTime() > DateTime.UtcNow; - /// /// If the user is deafened /// @@ -255,7 +255,11 @@ public bool IsOwner /// [JsonIgnore] public int Hierarchy - => this.IsOwner ? int.MaxValue : this.RoleIds.Count == 0 ? 0 : this.Roles.Max(x => x.Position); + => this.IsOwner + ? int.MaxValue + : this.RoleIds.Count == 0 + ? 0 + : this.Roles.Max(x => x.Position); /// /// Gets the permissions for the current member. @@ -270,7 +274,7 @@ public int Hierarchy public Permissions Permissions => this.InteractionPermissions ?? this.GetPermissions(); - #region Overridden user properties +#region Overridden user properties /// /// Gets the user. @@ -433,7 +437,7 @@ public override UserFlags? Flags internal set => this.User.Flags = value; } - #endregion +#endregion /// /// Sets this member's voice mute status. @@ -491,11 +495,9 @@ await this.Discord.ApiClient.ModifyGuildMemberAsync(this.Guild.Id, this.Id, Opti mdl.VoiceChannel.Map(e => e?.Id), default, this.MemberFlags, mdl.AuditLogReason).ConfigureAwait(false); } else - { await this.Discord.ApiClient.ModifyGuildMemberAsync(this.Guild.Id, this.Id, mdl.Nickname, mdl.Roles.Map(e => e.Select(xr => xr.Id)), mdl.Muted, mdl.Deafened, mdl.VoiceChannel.Map(e => e?.Id), default, this.MemberFlags, mdl.AuditLogReason).ConfigureAwait(false); - } } /// @@ -731,7 +733,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(DiscordMember e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id && this.GuildId == e.GuildId)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id && this.GuildId == e.GuildId); /// /// Gets the hash code for this . @@ -741,8 +743,8 @@ public override int GetHashCode() { var hash = 13; - hash = (hash * 7) + this.Id.GetHashCode(); - hash = (hash * 7) + this.GuildId.GetHashCode(); + hash = hash * 7 + this.Id.GetHashCode(); + hash = hash * 7 + this.GuildId.GetHashCode(); return hash; } @@ -758,7 +760,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || (e1.Id == e2.Id && e1.GuildId == e2.GuildId)); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id && e1.GuildId == e2.GuildId); } /// diff --git a/DisCatSharp/Entities/Guild/DiscordRole.cs b/DisCatSharp/Entities/Guild/DiscordRole.cs index 6381e8846d..5b9a511bac 100644 --- a/DisCatSharp/Entities/Guild/DiscordRole.cs +++ b/DisCatSharp/Entities/Guild/DiscordRole.cs @@ -148,7 +148,7 @@ public string Mention public IReadOnlyList> Members => this.Guild.Members.Where(x => x.Value.RoleIds.Any(x => x == this.Id)).ToList(); - #region Methods +#region Methods /// /// Modifies this role's position. @@ -168,7 +168,9 @@ public Task ModifyPositionAsync(int position, string reason = null) RoleId = x.Id, Position = x.Id == this.Id ? position - : x.Position <= position ? x.Position - 1 : x.Position + : x.Position <= position + ? x.Position - 1 + : x.Position }); return this.Discord.ApiClient.ModifyGuildRolePositionAsync(this.GuildId, roles, reason); @@ -194,44 +196,33 @@ public Task ModifyAsync(string name = null, Permissions? permissions = null, Dis /// Updates this role. /// /// The action. - /// Thrown when the client does not have the permission. + /// Thrown when the client does not have the permission. /// Thrown when the role does not exist. /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. + /// A delegate callback throws an exception. public Task ModifyAsync(Action action) { var mdl = new RoleEditModel(); action(mdl); var canContinue = true; - if ((mdl.Icon.HasValue && mdl.Icon.Value != null) || (mdl.UnicodeEmoji.HasValue && mdl.UnicodeEmoji.Value != null)) + if (mdl.Icon is { HasValue: true, Value: not null } || mdl.UnicodeEmoji is { HasValue: true, Value: not null }) canContinue = this.Guild.Features.HasFeature(GuildFeaturesEnum.CanSetRoleIcons); - var iconb64 = Optional.FromNullable(null); - if (mdl.Icon.HasValue && mdl.Icon.Value != null) - iconb64 = ImageTool.Base64FromStream(mdl.Icon); - else if (mdl.Icon.HasValue) - iconb64 = Optional.Some(null); - else - iconb64 = Optional.None; - - var emoji = Optional.FromNullable(null); + var iconb64 = mdl.Icon.HasValue switch + { + true when mdl.Icon.Value != null => ImageTool.Base64FromStream(mdl.Icon), + true => Optional.Some(null), + _ => (Optional)Optional.None + }; - switch (mdl.UnicodeEmoji.HasValue) + var emoji = mdl.UnicodeEmoji.HasValue switch { - case true when mdl.UnicodeEmoji.Value != null: - emoji = mdl.UnicodeEmoji - .MapOrNull(e => e.Id == 0 - ? e.Name - : throw new ArgumentException("Emoji must be unicode")); - break; - case true: - emoji = Optional.Some(null); - break; - case false: - emoji = Optional.None; - break; - } + true when mdl.UnicodeEmoji.Value != null => mdl.UnicodeEmoji.MapOrNull(e => e.Id == 0 ? e.Name : throw new ArgumentException("Emoji must be unicode")), + true => Optional.Some(null), + false => Optional.None + }; return canContinue ? this.Discord.ApiClient.ModifyGuildRoleAsync(this.GuildId, this.Id, mdl.Name, mdl.Permissions, mdl.Color?.Value, mdl.Hoist, mdl.Mentionable, iconb64, emoji, mdl.AuditLogReason) : throw new NotSupportedException($"Cannot modify role icon. Guild needs boost tier two."); } @@ -248,7 +239,7 @@ public Task ModifyAsync(Action action) public Task DeleteAsync(string reason = null) => this.Discord.ApiClient.DeleteRoleAsync(this.GuildId, this.Id, reason); - #endregion +#endregion /// /// Initializes a new instance of the class. @@ -306,7 +297,7 @@ public override int GetHashCode() /// Whether the two roles are equal. public static bool operator ==(DiscordRole e1, DiscordRole e2) => e1 is null == e2 is null - && ((e1 is null && e2 is null) || e1.Id == e2.Id); + && (e1 is null && e2 is null || e1.Id == e2.Id); /// /// Gets whether the two objects are not equal. diff --git a/DisCatSharp/Entities/Guild/DiscordRoleTags.cs b/DisCatSharp/Entities/Guild/DiscordRoleTags.cs index 86961458e5..36cddbd409 100644 --- a/DisCatSharp/Entities/Guild/DiscordRoleTags.cs +++ b/DisCatSharp/Entities/Guild/DiscordRoleTags.cs @@ -25,6 +25,7 @@ public class DiscordRoleTags : ObservableApiObject [JsonIgnore] public bool IsPremiumSubscriber => this.PremiumSubscriber.HasValue && this.PremiumSubscriber.Value; + [JsonProperty("premium_subscriber", NullValueHandling = NullValueHandling.Include)] internal bool? PremiumSubscriber = false; diff --git a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboarding.cs b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboarding.cs index 4f5cf6ff96..6e2c4606e8 100644 --- a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboarding.cs +++ b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboarding.cs @@ -58,6 +58,9 @@ public DiscordGuild Guild /// Constructs a new onboarding configuration. /// internal DiscordOnboarding() - :base(new() { "responses", "onboarding_prompts_seen", "onboarding_responses_seen" }) + : base(new() + { + "responses", "onboarding_prompts_seen", "onboarding_responses_seen" + }) { } } diff --git a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPrompt.cs b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPrompt.cs index 0c97c188fd..a4c5f57074 100644 --- a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPrompt.cs +++ b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPrompt.cs @@ -56,9 +56,14 @@ public sealed class DiscordOnboardingPrompt : SnowflakeObject /// Whether the prompt is required. Defaults to . /// Whether the prompt is shown in onboarding. Defaults to . /// The prompt type. Defaults to . - public DiscordOnboardingPrompt(string title, List options, - bool singleSelect = false, bool required = true, - bool inOnboarding = true, PromptType type = PromptType.MultipleChoice) + public DiscordOnboardingPrompt( + string title, + List options, + bool singleSelect = false, + bool required = true, + bool inOnboarding = true, + PromptType type = PromptType.MultipleChoice + ) { this.Title = title; this.Options = options; diff --git a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPromptOption.cs b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPromptOption.cs index 95bc016f80..570ec980c0 100644 --- a/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPromptOption.cs +++ b/DisCatSharp/Entities/Guild/Onboarding/DiscordOnboardingPromptOption.cs @@ -32,7 +32,7 @@ public sealed class DiscordOnboardingPromptOption : SnowflakeObject /// [JsonProperty("role_ids", NullValueHandling = NullValueHandling.Ignore)] public List? RoleIds { get; internal set; } - + /// /// Gets the option's channel ids. /// @@ -48,8 +48,13 @@ public sealed class DiscordOnboardingPromptOption : SnowflakeObject /// The emoji. Defaults to . /// The role ids. Defaults to . /// The channel ids. Defaults to . - public DiscordOnboardingPromptOption(string title, string? description = null, - DiscordEmoji? emoji = null, List? roleIds = null, List? channelIds = null) + public DiscordOnboardingPromptOption( + string title, + string? description = null, + DiscordEmoji? emoji = null, + List? roleIds = null, + List? channelIds = null + ) { this.Title = title; this.Description = description; diff --git a/DisCatSharp/Entities/Guild/Onboarding/DiscordServerGuide.cs b/DisCatSharp/Entities/Guild/Onboarding/DiscordServerGuide.cs index 91eac9cd11..acd511494c 100644 --- a/DisCatSharp/Entities/Guild/Onboarding/DiscordServerGuide.cs +++ b/DisCatSharp/Entities/Guild/Onboarding/DiscordServerGuide.cs @@ -1,4 +1,3 @@ - using System.Collections.Generic; using Newtonsoft.Json; diff --git a/DisCatSharp/Entities/Guild/Onboarding/WelcomeMessage.cs b/DisCatSharp/Entities/Guild/Onboarding/WelcomeMessage.cs index 89fe92fed8..98baaad92b 100644 --- a/DisCatSharp/Entities/Guild/Onboarding/WelcomeMessage.cs +++ b/DisCatSharp/Entities/Guild/Onboarding/WelcomeMessage.cs @@ -38,7 +38,10 @@ public ulong AuthorId /// The message. Use [@username] to mention the new member. Required. public WelcomeMessage(ulong authorId, string message) { - this.AuthorIds = new() { authorId }; + this.AuthorIds = new() + { + authorId + }; this.Message = message; } diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs index 8f0cab38d8..af74c3e9d7 100644 --- a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEvent.cs @@ -93,8 +93,7 @@ public string CoverImageUrl /// [JsonIgnore] public DateTimeOffset? ScheduledStartTime - => !string.IsNullOrWhiteSpace(this.ScheduledStartTimeRaw) && DateTimeOffset.TryParse(this.ScheduledStartTimeRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.ScheduledStartTimeRaw) && DateTimeOffset.TryParse(this.ScheduledStartTimeRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the scheduled start time of the scheduled event as raw string. @@ -107,8 +106,7 @@ public DateTimeOffset? ScheduledStartTime /// [JsonIgnore] public DateTimeOffset? ScheduledEndTime - => !string.IsNullOrWhiteSpace(this.ScheduledEndTimeRaw) && DateTimeOffset.TryParse(this.ScheduledEndTimeRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.ScheduledEndTimeRaw) && DateTimeOffset.TryParse(this.ScheduledEndTimeRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the scheduled end time of the scheduled event as raw string. @@ -159,11 +157,13 @@ public DateTimeOffset? ScheduledEndTime /// Initializes a new instance of the class. /// internal DiscordScheduledEvent() - : base(new() { "sku_ids" }) + : base(new() + { + "sku_ids" + }) { } - #region Methods - +#region Methods #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -196,7 +196,6 @@ public async Task ModifyAsync(Action action) await this.Discord.ApiClient.ModifyGuildScheduledEventAsync(this.GuildId, this.Id, channelId, this.EntityType == ScheduledEventEntityType.External ? new DiscordScheduledEventEntityMetadata(mdl.Location.Value) : null, mdl.Name, mdl.ScheduledStartTime, scheduledEndTime, mdl.Description, mdl.EntityType, mdl.Status, coverb64, mdl.AuditLogReason).ConfigureAwait(false); } - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Starts the current scheduled event. @@ -209,7 +208,6 @@ public async Task StartAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Status == ScheduledEventStatus.Scheduled ? await this.Discord.ApiClient.ModifyGuildScheduledEventStatusAsync(this.GuildId, this.Id, ScheduledEventStatus.Active, reason).ConfigureAwait(false) : throw new InvalidOperationException("You can only start scheduled events"); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Cancels the current scheduled event. @@ -223,7 +221,6 @@ public async Task CancelAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Status == ScheduledEventStatus.Scheduled ? await this.Discord.ApiClient.ModifyGuildScheduledEventStatusAsync(this.GuildId, this.Id, ScheduledEventStatus.Canceled, reason).ConfigureAwait(false) : throw new InvalidOperationException("You can only cancel scheduled events"); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Ends the current scheduled event. @@ -237,7 +234,6 @@ public async Task EndAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Status == ScheduledEventStatus.Active ? await this.Discord.ApiClient.ModifyGuildScheduledEventStatusAsync(this.GuildId, this.Id, ScheduledEventStatus.Completed, reason).ConfigureAwait(false) : throw new InvalidOperationException("You can only stop active events"); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Gets a list of users RSVP'd to the scheduled event. @@ -254,7 +250,6 @@ public async Task> GetUser #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => await this.Discord.ApiClient.GetGuildScheduledEventRspvUsersAsync(this.GuildId, this.Id, limit, before, after, withMember).ConfigureAwait(false); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes a scheduled event. @@ -268,7 +263,7 @@ public async Task DeleteAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => await this.Discord.ApiClient.DeleteGuildScheduledEventAsync(this.GuildId, this.Id, reason).ConfigureAwait(false); - #endregion +#endregion /// /// Checks whether this is equal to another object. @@ -304,7 +299,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventEntityMetadata.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventEntityMetadata.cs index 89b71a37e0..9653751909 100644 --- a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventEntityMetadata.cs +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventEntityMetadata.cs @@ -9,7 +9,6 @@ namespace DisCatSharp.Entities; /// public class DiscordScheduledEventEntityMetadata : ObservableApiObject { - /// /// External location if event type is . /// diff --git a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventUser.cs b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventUser.cs index 3546da29fd..29f29580c6 100644 --- a/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventUser.cs +++ b/DisCatSharp/Entities/Guild/ScheduledEvent/DiscordScheduledEventUser.cs @@ -87,7 +87,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || HashCode.Combine(e1.User.Id, e1.EventId) == HashCode.Combine(e2.User.Id, e2.EventId)); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || HashCode.Combine(e1.User.Id, e1.EventId) == HashCode.Combine(e2.User.Id, e2.EventId)); } /// diff --git a/DisCatSharp/Entities/Guild/Stage/DiscordStageInstance.cs b/DisCatSharp/Entities/Guild/Stage/DiscordStageInstance.cs index 4fa2dd93bb..0107d82a07 100644 --- a/DisCatSharp/Entities/Guild/Stage/DiscordStageInstance.cs +++ b/DisCatSharp/Entities/Guild/Stage/DiscordStageInstance.cs @@ -76,7 +76,7 @@ public bool Equals(DiscordStageInstance e) var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannel.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannel.cs index 505423b0da..dc3c05f4b9 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannel.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannel.cs @@ -65,8 +65,7 @@ public class DiscordThreadChannel : DiscordChannel [JsonIgnore] public IReadOnlyDictionary ThreadMembers => new ReadOnlyConcurrentDictionary(this.ThreadMembersInternal); - [JsonProperty("thread_member", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("thread_member", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary ThreadMembersInternal; /// @@ -94,10 +93,13 @@ public IReadOnlyList AppliedTags /// Initializes a new instance of the class. /// internal DiscordThreadChannel() - : base(new() { "hashes", "guild_hashes" }) + : base(new() + { + "hashes", "guild_hashes" + }) { } - #region Methods +#region Methods /// /// Modifies the current thread. @@ -128,9 +130,12 @@ public Task ModifyAsync(Action action) /// Thrown when an invalid parameter was provided. /// Thrown when Discord is unable to process the request. public Task AddTagAsync(ForumPostTag tag, string reason = null) - => this.AppliedTagIds.Count == 5 ? - throw new NotSupportedException("Cannot have more than 5 applied tags.") : - this.Discord.ApiClient.ModifyThreadAsync(this.Id, this.Parent.Type, null, null, null, null, null, null, new List(this.AppliedTags) { tag }, null, reason); + => this.AppliedTagIds.Count == 5 + ? throw new NotSupportedException("Cannot have more than 5 applied tags.") + : this.Discord.ApiClient.ModifyThreadAsync(this.Id, this.Parent.Type, null, null, null, null, null, null, new List(this.AppliedTags) + { + tag + }, null, reason); /// /// Remove a tag from the current thread. @@ -188,7 +193,6 @@ public Task LockAsync(string reason = null) public Task UnlockAsync(string reason = null) => this.Discord.ApiClient.ModifyThreadAsync(this.Id, this.Parent.Type, null, false, true, null, null, null, null, null, reason); - /// /// Gets the members of a thread. Needs the intent. /// @@ -232,7 +236,6 @@ public Task AddMemberAsync(DiscordMember member) public Task GetMemberAsync(ulong memberId, bool withMember = false) => this.Discord.ApiClient.GetThreadMemberAsync(this.Id, memberId, withMember); - /// /// Tries to get a member in this thread. /// @@ -315,9 +318,7 @@ public async Task AddRoleAsync(ulong roleId) var members = await this.Guild.GetAllMembersAsync().ConfigureAwait(false); var roleMembers = members.Where(m => m.Roles.Contains(role)); foreach (var member in roleMembers) - { await this.Discord.ApiClient.AddThreadMemberAsync(this.Id, member.Id).ConfigureAwait(false); - } } /// @@ -343,9 +344,7 @@ public async Task RemoveRoleAsync(ulong roleId) var members = await this.Guild.GetAllMembersAsync().ConfigureAwait(false); var roleMembers = members.Where(m => m.Roles.Contains(role)); foreach (var member in roleMembers) - { await this.Discord.ApiClient.RemoveThreadMemberAsync(this.Id, member.Id).ConfigureAwait(false); - } } /// @@ -388,7 +387,8 @@ public override string ToString() ChannelType.NewsThread => $"News thread {this.Name} ({this.Id})", ChannelType.PublicThread => $"Thread {this.Name} ({this.Id})", ChannelType.PrivateThread => $"Private thread {this.Name} ({this.Id})", - _ => $"Thread {this.Name} ({this.Id})", + _ => $"Thread {this.Name} ({this.Id})" }; - #endregion + +#endregion } diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMember.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMember.cs index 45eec812db..b7d863e5df 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMember.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMember.cs @@ -35,8 +35,7 @@ public class DiscordThreadChannelMember : SnowflakeObject, IEquatable [JsonIgnore] public DateTimeOffset? JoinTimeStamp - => !string.IsNullOrWhiteSpace(this.JoinTimeStampRaw) && DateTimeOffset.TryParse(this.JoinTimeStampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.JoinTimeStampRaw) && DateTimeOffset.TryParse(this.JoinTimeStampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the timestamp when the user joined the thread as raw string. @@ -81,7 +80,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(DiscordThreadChannelMember e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id && this.UserId == e.UserId)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id && this.UserId == e.UserId); /// /// Gets the hash code for this . @@ -101,7 +100,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || (e1.Id == e2.Id && e1.UserId == e2.UserId)); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id && e1.UserId == e2.UserId); } /// @@ -117,6 +116,9 @@ public override int GetHashCode() /// Initializes a new instance of the class. /// internal DiscordThreadChannelMember() - : base(new() { "muted", "mute_config", "guild_id" }) + : base(new() + { + "muted", "mute_config", "guild_id" + }) { } } diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMetadata.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMetadata.cs index efc53ba44f..ae028037a9 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMetadata.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadChannelMetadata.cs @@ -35,8 +35,7 @@ public class DiscordThreadChannelMetadata : ObservableApiObject /// [JsonIgnore] public DateTimeOffset? ArchiveTimestamp - => !string.IsNullOrWhiteSpace(this.ArchiveTimestampRaw) && DateTimeOffset.TryParse(this.ArchiveTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.ArchiveTimestampRaw) && DateTimeOffset.TryParse(this.ArchiveTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the timestamp when it was archived as raw string. @@ -62,8 +61,7 @@ public DateTimeOffset? ArchiveTimestamp /// [JsonIgnore] public DateTimeOffset? CreateTimestamp - => !string.IsNullOrWhiteSpace(this.CreateTimestampRaw) && DateTimeOffset.TryParse(this.CreateTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.CreateTimestampRaw) && DateTimeOffset.TryParse(this.CreateTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the timestamp when the thread was created as raw string. diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadResult.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadResult.cs index 14a2d06c4a..53d8b6e67e 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadResult.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/DiscordThreadResult.cs @@ -15,7 +15,13 @@ public class DiscordThreadResult : ObservableApiObject /// [JsonIgnore] public Dictionary ReturnedThreads - => this.Threads == null || !this.Threads.Any() ? new() : this.Threads.Select(t => new { t.Id, t }).ToDictionary(t => t.Id, t => t.t); + => this.Threads == null || !this.Threads.Any() + ? new() + : this.Threads.Select(t => new + { + t.Id, t + }).ToDictionary(t => t.Id, t => t.t); + [JsonProperty("threads", NullValueHandling = NullValueHandling.Ignore)] internal List Threads { get; set; } diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/ForumPostTag.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/ForumPostTag.cs index f51d982874..4ab0d7cd05 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/ForumPostTag.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/ForumPostTag.cs @@ -43,7 +43,6 @@ public class ForumPostTag : NullableSnowflakeObject, IEquatable [JsonProperty("emoji_name", NullValueHandling = NullValueHandling.Include)] public string? UnicodeEmojiString { get; internal set; } - /// /// Gets whether the tag can only be used by moderators. /// @@ -122,7 +121,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(ForumPostTag e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id && this.Name == e.Name)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id && this.Name == e.Name); /// /// Gets the hash code for this . @@ -142,7 +141,7 @@ public override int GetHashCode() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Guild/ThreadAndForum/ForumReactionEmoji.cs b/DisCatSharp/Entities/Guild/ThreadAndForum/ForumReactionEmoji.cs index 978183626e..743780a435 100644 --- a/DisCatSharp/Entities/Guild/ThreadAndForum/ForumReactionEmoji.cs +++ b/DisCatSharp/Entities/Guild/ThreadAndForum/ForumReactionEmoji.cs @@ -33,5 +33,4 @@ public ForumReactionEmoji(ulong? emojiId = null, string unicodeEmojiString = nul /// public DiscordEmoji GetEmoji(DiscordClient client) => this.EmojiName != null ? DiscordEmoji.FromName(client, $":{this.EmojiName}:", false) : DiscordEmoji.FromGuildEmote(client, this.EmojiId.Value); - } diff --git a/DisCatSharp/Entities/Interaction/Components/Button/DiscordButtonComponent.cs b/DisCatSharp/Entities/Interaction/Components/Button/DiscordButtonComponent.cs index 13e5f19037..39b56e7a23 100644 --- a/DisCatSharp/Entities/Interaction/Components/Button/DiscordButtonComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/Button/DiscordButtonComponent.cs @@ -105,6 +105,7 @@ public DiscordButtonComponent(ButtonStyle style, string customId = null, string this.Label = label ?? throw new ArgumentException("Label can only be null if emoji is set."); this.Emoji = null; } + this.Type = ComponentType.Button; } } diff --git a/DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs b/DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs index ef684fac13..62d1aa5150 100644 --- a/DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/DiscordEmojiComponent.cs @@ -43,6 +43,7 @@ public DiscordComponentEmoji(string name) { if (!DiscordEmoji.IsValidUnicode(name)) throw new ArgumentException("Only unicode emojis can be passed."); + this.Name = name; } diff --git a/DisCatSharp/Entities/Interaction/Components/Select/DiscordBaseSelectComponent.cs b/DisCatSharp/Entities/Interaction/Components/Select/DiscordBaseSelectComponent.cs index 66654d2ded..e5a13f53db 100644 --- a/DisCatSharp/Entities/Interaction/Components/Select/DiscordBaseSelectComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/Select/DiscordBaseSelectComponent.cs @@ -62,7 +62,8 @@ public class DiscordBaseSelectComponent : DiscordComponent internal DiscordBaseSelectComponent(ComponentType type, string placeholder, string customId = null, int minOptions = 1, int maxOptions = 1, bool disabled = false, IEnumerable? defaultValues = null) { this.Type = type; - this.CustomId = customId ?? Guid.NewGuid().ToString(); ; + this.CustomId = customId ?? Guid.NewGuid().ToString(); + ; this.Disabled = disabled; this.Placeholder = placeholder; this.MinimumSelectedValues = minOptions; @@ -80,6 +81,7 @@ internal DiscordBaseSelectComponent(ComponentType type, string placeholder, stri if (type == ComponentType.RoleSelect && defaultValues.Any(x => x.Type != "role")) throw new ArgumentException("The default values for a role select menus must be of type role.", nameof(defaultValues)); } + this.DefaultValues = defaultValues?.ToList(); } @@ -98,7 +100,8 @@ internal DiscordBaseSelectComponent(ComponentType type, string label, string pla { this.Type = type; this.Label = label; - this.CustomId = customId ?? Guid.NewGuid().ToString(); ; + this.CustomId = customId ?? Guid.NewGuid().ToString(); + ; this.Disabled = disabled; this.Placeholder = placeholder; this.MinimumSelectedValues = minOptions; @@ -116,11 +119,10 @@ internal DiscordBaseSelectComponent(ComponentType type, string label, string pla if (type == ComponentType.RoleSelect && defaultValues.Any(x => x.Type != "role")) throw new ArgumentException("The default values for a role select menus must be of type role.", nameof(defaultValues)); } + this.DefaultValues = defaultValues?.ToList(); } internal DiscordBaseSelectComponent() - { - - } + { } } diff --git a/DisCatSharp/Entities/Interaction/Components/Select/DiscordChannelSelectComponent.cs b/DisCatSharp/Entities/Interaction/Components/Select/DiscordChannelSelectComponent.cs index 050ebc8404..132f98e51c 100644 --- a/DisCatSharp/Entities/Interaction/Components/Select/DiscordChannelSelectComponent.cs +++ b/DisCatSharp/Entities/Interaction/Components/Select/DiscordChannelSelectComponent.cs @@ -52,7 +52,7 @@ public DiscordChannelSelectComponent Disable() /// Whether this select component should be initialized as being disabled. User sees a greyed out select component that cannot be interacted with. /// The default values of this select menu. public DiscordChannelSelectComponent(string placeholder, IEnumerable channelTypes = null, string customId = null, int minOptions = 1, int maxOptions = 1, bool disabled = false, IEnumerable? defaultValues = null) - : base(ComponentType.ChannelSelect, placeholder, customId, minOptions, maxOptions, disabled, defaultValues) + : base(ComponentType.ChannelSelect, placeholder, customId, minOptions, maxOptions, disabled, defaultValues) { this.ChannelTypes = channelTypes?.ToArray() ?? Array.Empty(); } diff --git a/DisCatSharp/Entities/Interaction/Components/Select/DiscordSelectDefaultValue.cs b/DisCatSharp/Entities/Interaction/Components/Select/DiscordSelectDefaultValue.cs index 95d6fd5d6f..b74bf85113 100644 --- a/DisCatSharp/Entities/Interaction/Components/Select/DiscordSelectDefaultValue.cs +++ b/DisCatSharp/Entities/Interaction/Components/Select/DiscordSelectDefaultValue.cs @@ -66,6 +66,5 @@ public DiscordSelectDefaultValue(DiscordChannel channel) /// Constructs a new for a channel. /// internal DiscordSelectDefaultValue() - { - } + { } } diff --git a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs index 110cd23e3c..d5a46d1e10 100644 --- a/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordFollowupMessageBuilder.cs @@ -27,6 +27,7 @@ public bool IsEphemeral this.FlagsChanged = true; } } + private bool EPH { get; set; } /// @@ -41,6 +42,7 @@ public bool EmbedsSuppressed this.FlagsChanged = true; } } + private bool EMB_SUP { get; set; } /// @@ -55,6 +57,7 @@ public bool NotificationsSuppressed this.FlagsChanged = true; } } + private bool NOTI_SUP { get; set; } /// @@ -72,35 +75,40 @@ public string Content { if (value != null && value.Length > 2000) throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); + this._content = value; } } + private string _content; /// /// Embeds to send on followup message. /// public IReadOnlyList Embeds => this._embeds; + private readonly List _embeds = new(); /// /// Files to send on this followup message. /// public IReadOnlyList Files => this._files; + private readonly List _files = new(); /// /// Components to send on this followup message. /// public IReadOnlyList Components => this._components; + private readonly List _components = new(); /// /// Mentions to send on this followup message. /// public IReadOnlyList Mentions => this._mentions; - private readonly List _mentions = new(); + private readonly List _mentions = new(); /// /// Appends a collection of components to the message. @@ -147,6 +155,7 @@ public DiscordFollowupMessageBuilder AddComponents(IEnumerable this._components.Add(arc); return this; } + /// /// Indicates if the followup message must use text-to-speech. /// @@ -260,7 +269,6 @@ public DiscordFollowupMessageBuilder AddFiles(Dictionary files, this._files.Add(new(file.Key, file.Value, null)); } - return this; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteraction.cs b/DisCatSharp/Entities/Interaction/DiscordInteraction.cs index 2b4c8e04a2..b1b1dd3fc3 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteraction.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteraction.cs @@ -50,7 +50,15 @@ public DiscordGuild Guild /// [JsonIgnore] // TODO: Is now also partial "channel" public DiscordChannel Channel - => (this.Discord as DiscordClient).InternalGetCachedChannel(this.ChannelId) ?? (DiscordChannel)(this.Discord as DiscordClient).InternalGetCachedThread(this.ChannelId) ?? (this.Guild == null ? new DiscordDmChannel { Id = this.ChannelId, Type = ChannelType.Private, Discord = this.Discord } : new DiscordChannel() { Id = this.ChannelId, Discord = this.Discord }); + => (this.Discord as DiscordClient).InternalGetCachedChannel(this.ChannelId) ?? (DiscordChannel)(this.Discord as DiscordClient).InternalGetCachedThread(this.ChannelId) ?? (this.Guild == null + ? new DiscordDmChannel + { + Id = this.ChannelId, Type = ChannelType.Private, Discord = this.Discord + } + : new DiscordChannel() + { + Id = this.ChannelId, Discord = this.Discord + }); /// /// Gets the user that invoked this interaction. @@ -161,14 +169,10 @@ public async Task EditOriginalResponseAsync(DiscordWebhookBuilde { var attachments = this.Discord.ApiClient.GetOriginalInteractionResponseAsync(this.Discord.CurrentApplication.Id, this.Token).Result.Attachments; if (attachments?.Count > 0) - { builder.AttachmentsInternal.AddRange(attachments); - } } else if (builder.KeepAttachmentsInternal.HasValue) - { builder.AttachmentsInternal.Clear(); - } return await this.Discord.ApiClient.EditOriginalInteractionResponseAsync(this.Discord.CurrentApplication.Id, this.Token, builder).ConfigureAwait(false); } @@ -212,14 +216,10 @@ public async Task EditFollowupMessageAsync(ulong messageId, Disc { var attachments = this.Discord.ApiClient.GetFollowupMessageAsync(this.Discord.CurrentApplication.Id, this.Token, messageId).Result.Attachments; if (attachments?.Count > 0) - { builder.AttachmentsInternal.AddRange(attachments); - } } else if (builder.KeepAttachmentsInternal.HasValue) - { builder.AttachmentsInternal.Clear(); - } return await this.Discord.ApiClient.EditFollowupMessageAsync(this.Discord.CurrentApplication.Id, this.Token, messageId, builder).ConfigureAwait(false); } @@ -232,6 +232,13 @@ public Task DeleteFollowupMessageAsync(ulong messageId) => this.Discord.ApiClient.DeleteFollowupMessageAsync(this.Discord.CurrentApplication.Id, this.Token, messageId); internal DiscordInteraction() - : base(new() { "member", "guild_id", "channel_id", "channel", "guild" }) + : base(new() + { + "member", + "guild_id", + "channel_id", + "channel", + "guild" + }) { } } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionDataOption.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionDataOption.cs index 56fe7844df..9f80371278 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionDataOption.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionDataOption.cs @@ -56,7 +56,7 @@ public sealed class DiscordInteractionDataOption : ObservableApiObject ApplicationCommandOptionType.Mentionable => ulong.Parse(this.RawValue), ApplicationCommandOptionType.Number => double.Parse(this.RawValue), ApplicationCommandOptionType.Attachment => ulong.Parse(this.RawValue), - _ => this.RawValue, + _ => this.RawValue }; /// diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs index c3b1522564..44686bcd51 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionModalBuilder.cs @@ -19,9 +19,11 @@ public string Title { if (value != null && value.Length > 128) throw new ArgumentException("Title length cannot exceed 128 characters.", nameof(value)); + this._title = value; } } + private string _title; /// @@ -33,6 +35,7 @@ public string Title /// Components to send on this interaction response. /// public IReadOnlyList ModalComponents => this._components; + private readonly List _components = new(); /// @@ -107,7 +110,10 @@ public DiscordInteractionModalBuilder AddModalComponents(params DiscordComponent throw new ArgumentException($"You try to add too many components. We already have {this._components.Count}."); foreach (var ar in ara) - this._components.Add(new(new List() { ar })); + this._components.Add(new(new List() + { + ar + })); return this; } @@ -138,7 +144,10 @@ public DiscordInteractionModalBuilder AddModalComponents(IEnumerableThe current builder to chain calls with. internal DiscordInteractionModalBuilder AddModalComponents(DiscordComponent component) { - this._components.Add(new(new List() { component })); + this._components.Add(new(new List() + { + component + })); return this; } diff --git a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs index 4fa8437daa..e2fcc30fa0 100644 --- a/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs +++ b/DisCatSharp/Entities/Interaction/DiscordInteractionResponseBuilder.cs @@ -27,6 +27,7 @@ public bool IsEphemeral this.FlagsChanged = true; } } + private bool EPH { get; set; } /// @@ -41,6 +42,7 @@ public bool EmbedsSuppressed this.FlagsChanged = true; } } + private bool EMB_SUP { get; set; } /// @@ -55,6 +57,7 @@ public bool NotificationsSuppressed this.FlagsChanged = true; } } + private bool NOTI_SUP { get; set; } /// @@ -72,28 +75,32 @@ public string Content { if (value != null && value.Length > 2000) throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); + this._content = value; } } + private string _content; /// /// Embeds to send on this interaction response. /// public IReadOnlyList Embeds => this._embeds; - private readonly List _embeds = new(); + private readonly List _embeds = new(); /// /// Files to send on this interaction response. /// public IReadOnlyList Files => this._files; + private readonly List _files = new(); /// /// Components to send on this interaction response. /// public IReadOnlyList Components => this._components; + private readonly List _components = new(); /// @@ -101,13 +108,14 @@ public string Content /// Mutually exclusive with content, embed, and components. /// public IReadOnlyList Choices => this._choices; - private readonly List _choices = new(); + private readonly List _choices = new(); /// /// Mentions to send on this interaction response. /// public IReadOnlyList Mentions => this._mentions; + private readonly List _mentions = new(); /// @@ -115,7 +123,6 @@ public string Content /// public DiscordInteractionResponseBuilder() { } - /// /// Constructs a new based on an existing . /// @@ -128,7 +135,6 @@ public DiscordInteractionResponseBuilder(DiscordMessageBuilder builder) this._components.AddRange(builder.Components); } - /// /// Appends a collection of components to the builder. Each call will append to a new row. /// @@ -315,7 +321,6 @@ public DiscordInteractionResponseBuilder AddFiles(Dictionary fil this._files.Add(new(file.Key, file.Value, null)); } - return this; } diff --git a/DisCatSharp/Entities/Invite/DiscordInvite.cs b/DisCatSharp/Entities/Invite/DiscordInvite.cs index 099049784a..17185ae4e9 100644 --- a/DisCatSharp/Entities/Invite/DiscordInvite.cs +++ b/DisCatSharp/Entities/Invite/DiscordInvite.cs @@ -155,7 +155,10 @@ public class DiscordInvite : ObservableApiObject /// Initializes a new instance of the class. /// internal DiscordInvite() - : base(new() { "guild_id", "channel_id" }) + : base(new() + { + "guild_id", "channel_id" + }) { } /// diff --git a/DisCatSharp/Entities/Invite/DiscordInviteStage.cs b/DisCatSharp/Entities/Invite/DiscordInviteStage.cs index dde94c2d67..7bd8b8ed48 100644 --- a/DisCatSharp/Entities/Invite/DiscordInviteStage.cs +++ b/DisCatSharp/Entities/Invite/DiscordInviteStage.cs @@ -18,8 +18,7 @@ public class DiscordInviteStage : SnowflakeObject [JsonIgnore] public IReadOnlyDictionary Members { get; internal set; } - [JsonProperty("members", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] + [JsonProperty("members", NullValueHandling = NullValueHandling.Ignore), JsonConverter(typeof(SnowflakeArrayAsDictionaryJsonConverter))] internal ConcurrentDictionary MembersInternal = new(); /// diff --git a/DisCatSharp/Entities/Message/DiscordMentions.cs b/DisCatSharp/Entities/Message/DiscordMentions.cs index 8b4dcdec4a..d776dee75a 100644 --- a/DisCatSharp/Entities/Message/DiscordMentions.cs +++ b/DisCatSharp/Entities/Message/DiscordMentions.cs @@ -72,16 +72,13 @@ internal DiscordMentions(IEnumerable mentions, bool mention = false, b } if (mention) - { this.RepliedUser = repliedUser; - } var roles = new HashSet(); var users = new HashSet(); var parse = new HashSet(); foreach (var m in mentions) - { switch (m) { default: @@ -109,7 +106,6 @@ internal DiscordMentions(IEnumerable mentions, bool mention = false, b this.RepliedUser = repliedUser; break; } - } if (!parse.Contains(PARSE_USERS) && users.Count > 0) this.Users = users.ToArray(); diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index dbdc118f09..dbadef8337 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -25,8 +25,8 @@ internal DiscordMessage() this._attachmentsLazy = new(() => new ReadOnlyCollection(this.AttachmentsInternal)); this._embedsLazy = new(() => new ReadOnlyCollection(this.EmbedsInternal)); this._mentionedChannelsLazy = new(() => this.MentionedChannelsInternal != null - ? new ReadOnlyCollection(this.MentionedChannelsInternal) - : Array.Empty()); + ? new ReadOnlyCollection(this.MentionedChannelsInternal) + : Array.Empty()); this._mentionedRolesLazy = new(() => this.MentionedRolesInternal != null ? new ReadOnlyCollection(this.MentionedRolesInternal) : Array.Empty()); this.MentionedUsersLazy = new(() => new ReadOnlyCollection(this.MentionedUsersInternal)); this._reactionsLazy = new(() => new ReadOnlyCollection(this.ReactionsInternal)); @@ -38,10 +38,10 @@ internal DiscordMessage() gid = this.Channel is DiscordDmChannel ? "@me" : this.Channel is DiscordThreadChannel - ? this.INTERNAL_THREAD?.GuildId?.ToString(CultureInfo.InvariantCulture) - : this.GuildId.HasValue - ? this.GuildId.Value.ToString(CultureInfo.InvariantCulture) - : this.Channel.GuildId?.ToString(CultureInfo.InvariantCulture); + ? this.INTERNAL_THREAD?.GuildId?.ToString(CultureInfo.InvariantCulture) + : this.GuildId.HasValue + ? this.GuildId.Value.ToString(CultureInfo.InvariantCulture) + : this.Channel.GuildId?.ToString(CultureInfo.InvariantCulture); var cid = this.ChannelId.ToString(CultureInfo.InvariantCulture); var mid = this.Id.ToString(CultureInfo.InvariantCulture); @@ -141,8 +141,7 @@ private DiscordThreadChannel INTERNAL_THREAD [JsonProperty("author", NullValueHandling = NullValueHandling.Ignore)] public DiscordUser Author { get; internal set; } - [JsonProperty("member", NullValueHandling = NullValueHandling.Ignore)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "")] + [JsonProperty("member", NullValueHandling = NullValueHandling.Ignore), System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "")] private TransportMember TRANSPORT_MEMBER { get; set; } /// @@ -156,8 +155,7 @@ private DiscordThreadChannel INTERNAL_THREAD /// [JsonIgnore] public DateTimeOffset Timestamp - => !string.IsNullOrWhiteSpace(this.TimestampRaw) && DateTimeOffset.TryParse(this.TimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : this.CreationTimestamp; + => !string.IsNullOrWhiteSpace(this.TimestampRaw) && DateTimeOffset.TryParse(this.TimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : this.CreationTimestamp; /// /// Gets the message's creation timestamp as raw string. @@ -170,8 +168,7 @@ public DateTimeOffset Timestamp /// [JsonIgnore] public DateTimeOffset? EditedTimestamp - => !string.IsNullOrWhiteSpace(this.EditedTimestampRaw) && DateTimeOffset.TryParse(this.EditedTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? - dto : null; + => !string.IsNullOrWhiteSpace(this.EditedTimestampRaw) && DateTimeOffset.TryParse(this.EditedTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; /// /// Gets the message's edit timestamp as raw string. Will be null if the message was not edited. @@ -207,6 +204,7 @@ public IReadOnlyList MentionedUsers [JsonProperty("mentions", NullValueHandling = NullValueHandling.Ignore)] internal List MentionedUsersInternal; + [JsonIgnore] internal readonly Lazy> MentionedUsersLazy; @@ -237,6 +235,7 @@ public IReadOnlyList MentionedChannels [JsonIgnore] internal List MentionedChannelsInternal; + [JsonIgnore] private readonly Lazy> _mentionedChannelsLazy; @@ -249,6 +248,7 @@ public IReadOnlyList Attachments [JsonProperty("attachments", NullValueHandling = NullValueHandling.Ignore)] internal List AttachmentsInternal = new(); + [JsonIgnore] private readonly Lazy> _attachmentsLazy; @@ -261,6 +261,7 @@ public IReadOnlyList Embeds [JsonProperty("embeds", NullValueHandling = NullValueHandling.Ignore)] internal List EmbedsInternal = new(); + [JsonIgnore] private readonly Lazy> _embedsLazy; @@ -273,6 +274,7 @@ public IReadOnlyList Reactions [JsonProperty("reactions", NullValueHandling = NullValueHandling.Ignore)] internal List ReactionsInternal = new(); + [JsonIgnore] private readonly Lazy> _reactionsLazy; @@ -282,7 +284,6 @@ public IReadOnlyList Reactions [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] public string Nonce { get; internal set; } - /// /// Gets whether the message is pinned. /// @@ -350,6 +351,7 @@ public bool WebhookMessage /// [JsonIgnore] public Uri JumpLink => this._jumpLink.Value; + private readonly Lazy _jumpLink; /// @@ -361,6 +363,7 @@ public IReadOnlyList Stickers [JsonProperty("sticker_items", NullValueHandling = NullValueHandling.Ignore)] internal List StickersInternal = new(); + [JsonIgnore] private readonly Lazy> _stickersLazy; @@ -377,7 +380,6 @@ public IReadOnlyList Stickers public DiscordGuild Guild => this.GuildId.HasValue && this.Discord.Guilds.TryGetValue(this.GuildId.Value, out var guild) ? guild : null; - /// /// Gets the message object for the referenced message /// @@ -396,7 +398,11 @@ public DiscordGuild Guild /// [JsonIgnore] public DiscordThreadChannel Thread - => this._startedThread != null! ? this._startedThread! : this.GuildId.HasValue && this.Guild.ThreadsInternal.TryGetValue(this.Id, out var thread) ? thread! : null!; + => this._startedThread != null! + ? this._startedThread! + : this.GuildId.HasValue && this.Guild.ThreadsInternal.TryGetValue(this.Id, out var thread) + ? thread! + : null!; [JsonProperty("thread", NullValueHandling = NullValueHandling.Ignore)] #pragma warning disable CS0649 // Field 'DiscordMessage._startedThread' is never assigned to, and will always have its default value null @@ -420,8 +426,7 @@ internal DiscordMessageReference InternalBuildMessageReference() ? g : new() { - Id = guildId.Value, - Discord = client + Id = guildId.Value, Discord = client }; var channel = client.InternalGetCachedChannel(channelId.Value); @@ -430,8 +435,7 @@ internal DiscordMessageReference InternalBuildMessageReference() { reference.Channel = new() { - Id = channelId.Value, - Discord = client + Id = channelId.Value, Discord = client }; if (guildId.HasValue) @@ -447,8 +451,7 @@ internal DiscordMessageReference InternalBuildMessageReference() { reference.Message = new() { - ChannelId = this.ChannelId, - Discord = client + ChannelId = this.ChannelId, Discord = client }; if (messageId.HasValue) @@ -458,7 +461,6 @@ internal DiscordMessageReference InternalBuildMessageReference() return reference; } - /// /// Gets the mentions. /// @@ -491,7 +493,6 @@ internal void PopulateMentions() var mentionedUsers = new HashSet(new DiscordUserComparer()); if (guild != null) - { foreach (var usr in this.MentionedUsersInternal) { usr.Discord = this.Discord; @@ -506,9 +507,8 @@ internal void PopulateMentions() mentionedUsers.Add(guild.MembersInternal.TryGetValue(usr.Id, out var member) ? member : usr); } - } + if (!string.IsNullOrWhiteSpace(this.Content)) - { //mentionedUsers.UnionWith(Utilities.GetUserMentions(this).Select(this.Discord.GetCachedOrEmptyUserInternal)); if (guild != null) { @@ -516,12 +516,10 @@ internal void PopulateMentions() this.MentionedRolesInternal = this.MentionedRolesInternal.Union(this.MentionedRoleIds.Select(xid => guild.GetRole(xid))).ToList(); this.MentionedChannelsInternal = this.MentionedChannelsInternal.Union(Utilities.GetChannelMentions(this).Select(xid => guild.GetChannel(xid))).ToList(); } - } this.MentionedUsersInternal = mentionedUsers.ToList(); } - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Edits the message. @@ -535,7 +533,6 @@ public Task ModifyAsync(Optional content) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, default, this.GetMentions(), default, default, Array.Empty(), default); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Edits the message. @@ -547,8 +544,10 @@ public Task ModifyAsync(Optional content) /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional embed = default) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] { v }).ValueOr(Array.Empty()), this.GetMentions(), default, default, Array.Empty(), default); - + => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, embed.Map(v => new[] + { + v + }).ValueOr(Array.Empty()), this.GetMentions(), default, default, Array.Empty(), default); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -562,8 +561,10 @@ public Task ModifyAsync(Optional embed = default) /// Thrown when Discord is unable to process the request. public Task ModifyAsync(Optional content, Optional embed = default) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] { v }).ValueOr(Array.Empty()), this.GetMentions(), default, default, Array.Empty(), default); - + => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embed.Map(v => new[] + { + v + }).ValueOr(Array.Empty()), this.GetMentions(), default, default, Array.Empty(), default); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -579,7 +580,6 @@ public Task ModifyAsync(Optional content, Optional this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, content, embeds, this.GetMentions(), default, default, Array.Empty(), default); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Edits the message. @@ -593,10 +593,13 @@ public async Task ModifyAsync(DiscordMessageBuilder builder) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved { builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() : Optional.None).ConfigureAwait(false); + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + ? Optional.Some(builder.Attachments.AsEnumerable()) + : builder.KeepAttachmentsInternal.HasValue + ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() + : Optional.None).ConfigureAwait(false); } - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Edits the message embed suppression. @@ -617,7 +620,6 @@ public Task ModifySuppressionAsync(bool suppress = false) public Task ClearAttachmentsAsync() => this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, default, default, this.GetMentions(), default, default, default, Array.Empty()); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Edits the message. @@ -633,10 +635,13 @@ public async Task ModifyAsync(Action acti var builder = new DiscordMessageBuilder(); action(builder); builder.Validate(true); - return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 ? Optional.Some(builder.Attachments.AsEnumerable()) : builder.KeepAttachmentsInternal.HasValue ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() : Optional.None).ConfigureAwait(false); + return await this.Discord.ApiClient.EditMessageAsync(this.ChannelId, this.Id, builder.Content, Optional.Some(builder.Embeds.AsEnumerable()), builder.Mentions, builder.Components, builder.Suppressed, builder.Files, builder.Attachments.Count > 0 + ? Optional.Some(builder.Attachments.AsEnumerable()) + : builder.KeepAttachmentsInternal.HasValue + ? builder.KeepAttachmentsInternal.Value && this.Attachments is not null ? Optional.Some(this.Attachments.AsEnumerable()) : Array.Empty() + : Optional.None).ConfigureAwait(false); } - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes the message. @@ -649,7 +654,6 @@ public Task DeleteAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.DeleteMessageAsync(this.ChannelId, this.Id, reason); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Creates a thread. @@ -670,7 +674,6 @@ public async Task CreateThreadAsync(string name, ThreadAut : throw new NotSupportedException($"Cannot modify ThreadAutoArchiveDuration. Guild needs boost tier {(autoArchiveDuration == ThreadAutoArchiveDuration.ThreeDays ? "one" : "two")}."); #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Pins the message in its channel. @@ -683,7 +686,6 @@ public Task PinAsync() #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.PinMessageAsync(this.ChannelId, this.Id); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Unpins the message in its channel. @@ -696,7 +698,6 @@ public Task UnpinAsync() #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.UnpinMessageAsync(this.ChannelId, this.Id); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Responds to the message. This produces a reply. @@ -709,8 +710,7 @@ public Task UnpinAsync() /// Thrown when Discord is unable to process the request. public Task RespondAsync(string content) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, content, null, sticker: null, replyMessageId: this.Id, mentionReply: false, failOnInvalidReply: false); - + => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, content, null, null, this.Id, false, false); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -724,8 +724,12 @@ public Task RespondAsync(string content) /// Thrown when Discord is unable to process the request. public Task RespondAsync(DiscordEmbed embed) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, null, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: this.Id, mentionReply: false, failOnInvalidReply: false); - + => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, null, embed != null + ? new[] + { + embed + } + : null, null, this.Id, false, false); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -740,8 +744,12 @@ public Task RespondAsync(DiscordEmbed embed) /// Thrown when Discord is unable to process the request. public Task RespondAsync(string content, DiscordEmbed embed) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, content, embed != null ? new[] { embed } : null, sticker: null, replyMessageId: this.Id, mentionReply: false, failOnInvalidReply: false); - + => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, content, embed != null + ? new[] + { + embed + } + : null, null, this.Id, false, false); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -755,8 +763,7 @@ public Task RespondAsync(string content, DiscordEmbed embed) /// Thrown when Discord is unable to process the request. public Task RespondAsync(DiscordMessageBuilder builder) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, builder.WithReply(this.Id, mention: false, failOnInvalidReply: false)); - + => this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, builder.WithReply(this.Id, false, false)); #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// @@ -773,10 +780,9 @@ public Task RespondAsync(Action action) { var builder = new DiscordMessageBuilder(); action(builder); - return this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, builder.WithReply(this.Id, mention: false, failOnInvalidReply: false)); + return this.Discord.ApiClient.CreateMessageAsync(this.ChannelId, builder.WithReply(this.Id, false, false)); } - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Creates a reaction to this message. @@ -790,7 +796,6 @@ public Task CreateReactionAsync(DiscordEmoji emoji) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.CreateReactionAsync(this.ChannelId, this.Id, emoji.ToReactionString()); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes your own reaction @@ -803,7 +808,6 @@ public Task DeleteOwnReactionAsync(DiscordEmoji emoji) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.DeleteOwnReactionAsync(this.ChannelId, this.Id, emoji.ToReactionString()); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes another user's reaction. @@ -819,7 +823,6 @@ public Task DeleteReactionAsync(DiscordEmoji emoji, DiscordUser user, string rea #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.DeleteUserReactionAsync(this.ChannelId, this.Id, user.Id, emoji.ToReactionString(), reason); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Gets users that reacted with this emoji. @@ -834,7 +837,6 @@ public Task> GetReactionsAsync(DiscordEmoji emoji, in #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.GetReactionsInternalAsync(emoji, limit, after); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes all reactions for this message. @@ -848,7 +850,6 @@ public Task DeleteAllReactionsAsync(string reason = null) #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved => this.Discord.ApiClient.DeleteAllReactionsAsync(this.ChannelId, this.Id, reason); - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes all reactions of a specific reaction for this message. @@ -917,7 +918,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(DiscordMessage e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id && this.ChannelId == e.ChannelId)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id && this.ChannelId == e.ChannelId); /// /// Gets the hash code for this . @@ -927,8 +928,8 @@ public override int GetHashCode() { var hash = 13; - hash = (hash * 7) + this.Id.GetHashCode(); - hash = (hash * 7) + this.ChannelId.GetHashCode(); + hash = hash * 7 + this.Id.GetHashCode(); + hash = hash * 7 + this.ChannelId.GetHashCode(); return hash; } @@ -945,8 +946,8 @@ public override int GetHashCode() var o2 = e2 as object; return (o1 != null || o2 == null) - && (o1 == null || o2 != null) - && ((o1 == null && o2 == null) || (e1.Id == e2.Id && e1.ChannelId == e2.ChannelId)); + && (o1 == null || o2 != null) + && (o1 == null && o2 == null || e1.Id == e2.Id && e1.ChannelId == e2.ChannelId); } /// diff --git a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs index 7486a5bc50..bf7622700f 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageBuilder.cs @@ -21,9 +21,11 @@ public string Content { if (value != null && value.Length > 2000) throw new ArgumentException("Content cannot exceed 2000 characters.", nameof(value)); + this._content = value; } } + private string _content; /// @@ -48,6 +50,7 @@ public DiscordEmbed Embed /// Gets the Embeds to be sent. /// public IReadOnlyList Embeds => this._embeds; + private readonly List _embeds = new(); /// @@ -69,18 +72,21 @@ public DiscordEmbed Embed /// Gets the Files to be sent in the Message. /// public IReadOnlyCollection Files => this.FilesInternal; + internal readonly List FilesInternal = new(); /// /// Gets the components that will be attached to the message. /// public IReadOnlyList Components => this.ComponentsInternal; + internal readonly List ComponentsInternal = new(5); /// /// Gets the Attachments to be sent in the Message. /// public IReadOnlyList Attachments => this.AttachmentsInternal; + internal readonly List AttachmentsInternal = new(); /// @@ -136,7 +142,6 @@ public DiscordMessageBuilder WithSticker(DiscordSticker sticker) public DiscordMessageBuilder AddComponents(params DiscordComponent[] components) => this.AddComponents((IEnumerable)components); - /// /// Appends several rows of components to the message /// @@ -212,6 +217,7 @@ public DiscordMessageBuilder AddEmbed(DiscordEmbed embed) { if (embed == null) return this; //Providing null embeds will produce a 400 response from Discord.// + this._embeds.Add(embed); return this; } @@ -237,7 +243,10 @@ public DiscordMessageBuilder WithAllowedMention(IMention allowedMention) if (this.Mentions != null) this.Mentions.Add(allowedMention); else - this.Mentions = new() { allowedMention }; + this.Mentions = new() + { + allowedMention + }; return this; } @@ -333,9 +342,7 @@ public DiscordMessageBuilder AddGcpAttachment(GcpAttachmentUploadInformation gcp { this.AttachmentsInternal.Add(new() { - Filename = gcpAttachment.Filename, - UploadedFilename = gcpAttachment.UploadFilename, - Description = gcpAttachment.Description + Filename = gcpAttachment.Filename, UploadedFilename = gcpAttachment.UploadFilename, Description = gcpAttachment.Description }); return this; @@ -384,7 +391,6 @@ public DiscordMessageBuilder WithReply(ulong messageId, bool mention = false, bo return this; } - /// /// Sends the Message to a specific channel /// diff --git a/DisCatSharp/Entities/Message/GcpAttachment.cs b/DisCatSharp/Entities/Message/GcpAttachment.cs index fcaa54eb6f..2599788c46 100644 --- a/DisCatSharp/Entities/Message/GcpAttachment.cs +++ b/DisCatSharp/Entities/Message/GcpAttachment.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.IO; diff --git a/DisCatSharp/Entities/Message/Mentions.cs b/DisCatSharp/Entities/Message/Mentions.cs index 61406b354f..9952aa5811 100644 --- a/DisCatSharp/Entities/Message/Mentions.cs +++ b/DisCatSharp/Entities/Message/Mentions.cs @@ -6,8 +6,8 @@ namespace DisCatSharp.Entities; /// /// Interface for mentionables /// -public interface IMention { } - +public interface IMention +{ } /// /// Allows a reply to ping the user being replied to. @@ -101,7 +101,10 @@ public static class Mentions /// /// All possible mentions - @everyone + @here, users, and roles. /// - public static IReadOnlyList All { get; } = new IMention[] { EveryoneMention.All, UserMention.All, RoleMention.All }; + public static IReadOnlyList All { get; } = new IMention[] + { + EveryoneMention.All, UserMention.All, RoleMention.All + }; /// /// No mentions allowed. diff --git a/DisCatSharp/Entities/Optional.cs b/DisCatSharp/Entities/Optional.cs index 24888cb658..8748fd0b85 100644 --- a/DisCatSharp/Entities/Optional.cs +++ b/DisCatSharp/Entities/Optional.cs @@ -222,7 +222,7 @@ public override bool Equals(object obj) => { T t => this.Equals(t), Optional opt => this.Equals(opt), - _ => false, + _ => false }; /// @@ -230,7 +230,7 @@ public override bool Equals(object obj) => /// /// to compare to. /// Whether the is equal to this . - public bool Equals(Optional e) => (!this.HasValue && !e.HasValue) || (this.HasValue == e.HasValue && this.Value.Equals(e.Value)); + public bool Equals(Optional e) => !this.HasValue && !e.HasValue || this.HasValue == e.HasValue && this.Value.Equals(e.Value); /// /// Checks whether the value of this is equal to specified object. @@ -339,17 +339,13 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s var val = (value as IOptional).RawValue; // JToken.FromObject will throw if `null` so we manually write a null value. if (val == null) - { // you can read serializer.NullValueHandling here, but unfortunately you can **not** skip serialization // here, or else you will get a nasty JsonWriterException, so we just ignore its value and manually // write the null. writer.WriteToken(JsonToken.Null); - } else - { // convert the value to a JSON object and write it to the property value. JToken.FromObject(val).WriteTo(writer); - } } /// @@ -359,15 +355,22 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The object type. /// The existing value. /// The serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) + public override object ReadJson( + JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer + ) { var genericType = objectType.GenericTypeArguments[0]; var constructor = objectType.GetTypeInfo().DeclaredConstructors .FirstOrDefault(e => e.GetParameters()[0].ParameterType == genericType); - return constructor.Invoke(new[] { serializer.Deserialize(reader, genericType) }); + return constructor.Invoke(new[] + { + serializer.Deserialize(reader, genericType) + }); } /// diff --git a/DisCatSharp/Entities/Sticker/DiscordSticker.cs b/DisCatSharp/Entities/Sticker/DiscordSticker.cs index 9425a83361..5cfd420c1a 100644 --- a/DisCatSharp/Entities/Sticker/DiscordSticker.cs +++ b/DisCatSharp/Entities/Sticker/DiscordSticker.cs @@ -138,7 +138,6 @@ public bool Equals(DiscordSticker other) /// public override string ToString() => $"Sticker {this.Id}; {this.Name}; {this.FormatType}"; - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Modifies the sticker @@ -164,7 +163,6 @@ public Task ModifyAsync(Optional name, Optional : this.Discord.ApiClient.ModifyGuildStickerAsync(this.GuildId.Value, this.Id, name, description, tags, reason); #pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved - #pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// /// Deletes the sticker diff --git a/DisCatSharp/Entities/Store/DiscordStoreSku.cs b/DisCatSharp/Entities/Store/DiscordStoreSku.cs index 09aabe3884..e729128105 100644 --- a/DisCatSharp/Entities/Store/DiscordStoreSku.cs +++ b/DisCatSharp/Entities/Store/DiscordStoreSku.cs @@ -41,7 +41,7 @@ public override bool Equals(object obj) /// to compare to. /// Whether the is equal to this . public bool Equals(DiscordStoreSku e) - => e is not null && (ReferenceEquals(this, e) || (this.Id == e.Id)); + => e is not null && (ReferenceEquals(this, e) || this.Id == e.Id); /// /// Gets the hash code for this . @@ -62,8 +62,8 @@ public override int GetHashCode() var o2 = e2 as object; return (o1 != null || o2 == null) - && (o1 == null || o2 != null) - && ((o1 == null && o2 == null) || (e1.Id == e2.Id)); + && (o1 == null || o2 != null) + && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/User/DiscordActivity.cs b/DisCatSharp/Entities/User/DiscordActivity.cs index 49642665ed..9d2b155a1e 100644 --- a/DisCatSharp/Entities/User/DiscordActivity.cs +++ b/DisCatSharp/Entities/User/DiscordActivity.cs @@ -59,7 +59,6 @@ internal sealed class UserStatusConverter : JsonConverter public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value is UserStatus status) - { switch (status) // reader.Value can be a string, DateTime or DateTimeOffset (yes, it's weird) { case UserStatus.Online: @@ -87,7 +86,6 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s writer.WriteValue("offline"); return; } - } } /// @@ -107,7 +105,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist "dnd" => UserStatus.DoNotDisturb, "invisible" => UserStatus.Invisible, "streaming" => UserStatus.Streaming, - _ => UserStatus.Offline, + _ => UserStatus.Offline }; /// @@ -258,14 +256,13 @@ internal void UpdateWith(TransportActivity rawActivity) if (rawActivity?.IsCustomStatus() == true && this.CustomStatus != null) this.CustomStatus.UpdateWith(rawActivity.State, rawActivity.Emoji); - else this.CustomStatus = rawActivity?.IsCustomStatus() == true - ? new DiscordCustomStatus - { - Name = rawActivity.Name!, - State = rawActivity.State, - Emoji = rawActivity.Emoji - } - : null; + else + this.CustomStatus = rawActivity?.IsCustomStatus() == true + ? new DiscordCustomStatus + { + Name = rawActivity.Name!, State = rawActivity.State, Emoji = rawActivity.Emoji + } + : null; } } @@ -456,7 +453,12 @@ internal void UpdateWith(TransportActivity rawGame) { this.Details = rawGame?.Details; this.State = rawGame?.State; - this.Application = rawGame?.ApplicationId != null ? new DiscordApplication { Id = rawGame.ApplicationId.Value } : null; + this.Application = rawGame?.ApplicationId != null + ? new DiscordApplication + { + Id = rawGame.ApplicationId.Value + } + : null; this.Instance = rawGame?.Instance; this.LargeImageText = rawGame?.Assets?.LargeImageText; this.SmallImageText = rawGame?.Assets?.SmallImageText; @@ -475,18 +477,30 @@ internal void UpdateWith(TransportActivity rawGame) if (lid != null) { if (lid.StartsWith("spotify:")) - this.LargeImage = new DiscordSpotifyAsset { Id = lid }; + this.LargeImage = new DiscordSpotifyAsset + { + Id = lid + }; else if (ulong.TryParse(lid, NumberStyles.Number, CultureInfo.InvariantCulture, out var ulid)) - this.LargeImage = new DiscordApplicationAsset { Id = lid, Application = this.Application, Type = ApplicationAssetType.LargeImage }; + this.LargeImage = new DiscordApplicationAsset + { + Id = lid, Application = this.Application, Type = ApplicationAssetType.LargeImage + }; } var sid = rawGame?.Assets?.SmallImage; if (sid != null) { if (sid.StartsWith("spotify:")) - this.SmallImage = new DiscordSpotifyAsset { Id = sid }; + this.SmallImage = new DiscordSpotifyAsset + { + Id = sid + }; else if (ulong.TryParse(sid, NumberStyles.Number, CultureInfo.InvariantCulture, out var usid)) - this.SmallImage = new DiscordApplicationAsset { Id = sid, Application = this.Application, Type = ApplicationAssetType.LargeImage }; + this.SmallImage = new DiscordApplicationAsset + { + Id = sid, Application = this.Application, Type = ApplicationAssetType.LargeImage + }; } } } diff --git a/DisCatSharp/Entities/User/DiscordPresence.cs b/DisCatSharp/Entities/User/DiscordPresence.cs index d242042c50..fa4b8566b5 100644 --- a/DisCatSharp/Entities/User/DiscordPresence.cs +++ b/DisCatSharp/Entities/User/DiscordPresence.cs @@ -87,7 +87,10 @@ public DiscordGuild Guild /// // TODO: Add broadcast field internal DiscordPresence() - : base(new() { "broadcast" }) + : base(new() + { + "broadcast" + }) { } /// @@ -95,7 +98,10 @@ internal DiscordPresence() /// /// The other. internal DiscordPresence(DiscordPresence other) - : base(new() { "broadcast" }) + : base(new() + { + "broadcast" + }) { this.Discord = other.Discord; this.Activity = other.Activity; diff --git a/DisCatSharp/Entities/User/DiscordUser.cs b/DisCatSharp/Entities/User/DiscordUser.cs index df61dbbbbd..e2bfd961cf 100644 --- a/DisCatSharp/Entities/User/DiscordUser.cs +++ b/DisCatSharp/Entities/User/DiscordUser.cs @@ -23,7 +23,10 @@ public class DiscordUser : SnowflakeObject, IEquatable /// Initializes a new instance of the class. /// internal DiscordUser() - : base(new() { "display_name", "linked_users", "banner_color" }) + : base(new() + { + "display_name", "linked_users", "banner_color" + }) { } /// @@ -65,7 +68,11 @@ internal DiscordUser(TransportUser transport) /// [JsonIgnore, DiscordDeprecated("We will internally use the GlobalName if a user is already migrated. This will be removed in future. Consider switching to UsernameWithGlobalName then.")] public virtual string UsernameWithDiscriminator - => this.IsMigrated ? this.UsernameWithGlobalName : $"{this.Username}#{this.Discriminator}"; + => this.IsMigrated + ? this.UsernameWithGlobalName + : !string.IsNullOrEmpty(this.Username) && !string.IsNullOrEmpty(this.Discriminator) + ? $"{this.Username}#{this.Discriminator}" + : string.Empty; /// /// Gets the username with the global name. @@ -271,7 +278,7 @@ public string Mention public bool IsCurrent => this.Id == this.Discord.CurrentUser.Id; - #region Extension of DiscordUser +#region Extension of DiscordUser /// /// Whether this member is a @@ -279,7 +286,7 @@ public bool IsCurrent /// [JsonIgnore] public bool IsMod - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.CertifiedModerator); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.CertifiedModerator); /// /// Whether this member is a @@ -287,7 +294,7 @@ public bool IsMod /// [JsonIgnore] public bool IsPartner - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Partner); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Partner); /// /// Whether this member is a @@ -295,7 +302,7 @@ public bool IsPartner /// [JsonIgnore] public bool IsVerifiedBot - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedBot); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedBot); /// /// Whether this member is a @@ -303,7 +310,7 @@ public bool IsVerifiedBot /// [JsonIgnore] public bool IsBotDev - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedDeveloper); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedDeveloper); /// /// Whether this member is a @@ -311,7 +318,7 @@ public bool IsBotDev /// [JsonIgnore] public bool IsActiveDeveloper - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.ActiveDeveloper); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.ActiveDeveloper); /// /// Whether this member is a @@ -319,9 +326,9 @@ public bool IsActiveDeveloper /// [JsonIgnore] public bool IsStaff - => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Staff); + => this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Staff); - #endregion +#endregion /// /// Fetches the user from the API. @@ -358,7 +365,6 @@ public async Task IsInGuild(DiscordGuild guild) { var member = await guild.GetMemberAsync(this.Id).ConfigureAwait(false); return member is not null; - } catch (NotFoundException) { @@ -430,7 +436,7 @@ public string GetAvatarUrl(ImageFormat fmt, ushort size = 1024) ImageFormat.Png => "png", ImageFormat.WebP => "webp", ImageFormat.Auto => !string.IsNullOrWhiteSpace(this.AvatarHash) ? this.AvatarHash.StartsWith("a_") ? "gif" : "png" : "png", - _ => throw new ArgumentOutOfRangeException(nameof(fmt)), + _ => throw new ArgumentOutOfRangeException(nameof(fmt)) }; var ssize = size.ToString(CultureInfo.InvariantCulture); if (!string.IsNullOrWhiteSpace(this.AvatarHash)) @@ -567,7 +573,7 @@ public override string ToString() var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Voice/DiscordVoiceRegion.cs b/DisCatSharp/Entities/Voice/DiscordVoiceRegion.cs index cf659885f5..f005338e5a 100644 --- a/DisCatSharp/Entities/Voice/DiscordVoiceRegion.cs +++ b/DisCatSharp/Entities/Voice/DiscordVoiceRegion.cs @@ -78,7 +78,7 @@ public bool Equals(DiscordVoiceRegion region) var o1 = left as object; var o2 = right as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || left.Id == right.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || left.Id == right.Id); } /// diff --git a/DisCatSharp/Entities/Voice/DiscordVoiceState.cs b/DisCatSharp/Entities/Voice/DiscordVoiceState.cs index bc1872d640..513232978f 100644 --- a/DisCatSharp/Entities/Voice/DiscordVoiceState.cs +++ b/DisCatSharp/Entities/Voice/DiscordVoiceState.cs @@ -129,7 +129,12 @@ public DiscordUser User /// [JsonIgnore] public DiscordMember Member - => this.Guild.Members.TryGetValue(this.TransportMember.User.Id, out var member) ? member : new(this.TransportMember) { Discord = this.Discord }; + => this.Guild.Members.TryGetValue(this.TransportMember.User.Id, out var member) + ? member + : new(this.TransportMember) + { + Discord = this.Discord + }; /// /// Gets the transport member. diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhook.cs b/DisCatSharp/Entities/Webhook/DiscordWebhook.cs index a1def3c8dd..9018864e68 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhook.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhook.cs @@ -86,11 +86,16 @@ public string AvatarUrl [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] public string Token { get; internal set; } + /// + /// Gets the type of this webhook. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public WebhookType Type { get; internal set; } + /// /// Initializes a new instance of the class. /// internal DiscordWebhook() - : base(new() { "type" }) { } /// @@ -223,13 +228,9 @@ public async Task EditMessageAsync(ulong messageId, DiscordWebho { builder.Validate(true); if (builder.KeepAttachmentsInternal.HasValue && builder.KeepAttachmentsInternal.Value) - { builder.AttachmentsInternal.AddRange(this.ApiClient.GetWebhookMessageAsync(this.Id, this.Token, messageId.ToString(), threadId).Result.Attachments); - } else if (builder.KeepAttachmentsInternal.HasValue) - { builder.AttachmentsInternal.Clear(); - } return await (this.Discord?.ApiClient ?? this.ApiClient).EditWebhookMessageAsync(this.Id, this.Token, messageId.ToString(), builder, threadId).ConfigureAwait(false); } @@ -285,7 +286,7 @@ public Task DeleteMessageAsync(ulong messageId, ulong threadId) var o1 = e1 as object; var o2 = e2 as object; - return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id); + return (o1 != null || o2 == null) && (o1 == null || o2 != null) && (o1 == null && o2 == null || e1.Id == e2.Id); } /// diff --git a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs index 40ca2ac1e4..b53437832c 100644 --- a/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs +++ b/DisCatSharp/Entities/Webhook/DiscordWebhookBuilder.cs @@ -53,9 +53,11 @@ public string Content { if (value != null && value.Length > 2000) throw new ArgumentException("Content length cannot exceed 2000 characters.", nameof(value)); + this._content = value; } } + private string _content; /// @@ -64,7 +66,6 @@ public string Content /// public string ThreadName { get; set; } - /// /// Whether to keep previous attachments. /// @@ -74,31 +75,35 @@ public string Content /// Embeds to send on this webhook request. /// public IReadOnlyList Embeds => this._embeds; + private readonly List _embeds = new(); /// /// Files to send on this webhook request. /// public IReadOnlyList Files => this._files; + private readonly List _files = new(); /// /// Mentions to send on this webhook request. /// public IReadOnlyList Mentions => this._mentions; + private readonly List _mentions = new(); /// /// Gets the components. /// public IReadOnlyList Components => this._components; - private readonly List _components = new(); + private readonly List _components = new(); /// /// Attachments to keep on this webhook request. /// public IReadOnlyList Attachments => this.AttachmentsInternal; + internal List AttachmentsInternal = new(); /// @@ -316,7 +321,6 @@ public DiscordWebhookBuilder AddFiles(Dictionary files, bool res this._files.Add(new(file.Key, file.Value, null)); } - return this; } diff --git a/DisCatSharp/Enums/Application/ApplicationCommandContexts.cs b/DisCatSharp/Enums/Application/ApplicationCommandContexts.cs index a989953163..7ab12b70bb 100644 --- a/DisCatSharp/Enums/Application/ApplicationCommandContexts.cs +++ b/DisCatSharp/Enums/Application/ApplicationCommandContexts.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationCommandIntegrationTypes.cs b/DisCatSharp/Enums/Application/ApplicationCommandIntegrationTypes.cs index 6e5de27a26..51e7c346cc 100644 --- a/DisCatSharp/Enums/Application/ApplicationCommandIntegrationTypes.cs +++ b/DisCatSharp/Enums/Application/ApplicationCommandIntegrationTypes.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationCommandOptionType.cs b/DisCatSharp/Enums/Application/ApplicationCommandOptionType.cs index 983352a5e4..1639e4e80a 100644 --- a/DisCatSharp/Enums/Application/ApplicationCommandOptionType.cs +++ b/DisCatSharp/Enums/Application/ApplicationCommandOptionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationCommandType.cs b/DisCatSharp/Enums/Application/ApplicationCommandType.cs index a0ff17514d..dafa2f9ac7 100644 --- a/DisCatSharp/Enums/Application/ApplicationCommandType.cs +++ b/DisCatSharp/Enums/Application/ApplicationCommandType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationDiscoverabilityState.cs b/DisCatSharp/Enums/Application/ApplicationDiscoverabilityState.cs index 29ce733499..ad7bbe5393 100644 --- a/DisCatSharp/Enums/Application/ApplicationDiscoverabilityState.cs +++ b/DisCatSharp/Enums/Application/ApplicationDiscoverabilityState.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationDiscoveryEligibilityFlags.cs b/DisCatSharp/Enums/Application/ApplicationDiscoveryEligibilityFlags.cs index 7b58c5a471..d862b5d1bd 100644 --- a/DisCatSharp/Enums/Application/ApplicationDiscoveryEligibilityFlags.cs +++ b/DisCatSharp/Enums/Application/ApplicationDiscoveryEligibilityFlags.cs @@ -25,85 +25,85 @@ public enum ApplicationDiscoveryEligibilityFlags : long /// /// Application is verified. /// - Verified = 1<<0, + Verified = 1 << 0, /// /// Application has at least one tag set. /// - Tag = 1<<1, + Tag = 1 << 1, /// /// Application has a description. /// - Description = 1<<2, + Description = 1 << 2, /// /// Applications has a terms of service. /// - TermsOfService = 1<<3, + TermsOfService = 1 << 3, /// /// Application has a privacy policy. /// - PrivacyPolicy = 1<<4, + PrivacyPolicy = 1 << 4, /// /// Application has custom install url or install params. /// - InstallParams = 1<<5, + InstallParams = 1 << 5, /// /// Application's name is safe for work. /// - SafeName = 1<<6, + SafeName = 1 << 6, /// /// Application's description is safe for work. /// - SafeDescription = 1<<7, + SafeDescription = 1 << 7, /// /// Application has the message content approved or utilizes application commands. /// - ApprovedCommandsOrMessageContent = 1<<8, + ApprovedCommandsOrMessageContent = 1 << 8, /// /// Application has a support guild set. /// - SupportGuild = 1<<9, + SupportGuild = 1 << 9, /// /// Application's commands are safe for work. /// - SafeCommands = 1<<10, + SafeCommands = 1 << 10, /// /// Application's owner has MFA enabled. /// - Mfa = 1<<11, + Mfa = 1 << 11, /// /// Application's directory long description is safe for work. /// - SafeDirectoryOverview = 1<<12, + SafeDirectoryOverview = 1 << 12, /// /// Application has at least one supported locale set. /// - SupportedLocales = 1<<13, + SupportedLocales = 1 << 13, /// /// Application's directory short description is safe for work. /// - SafeShortDescription = 1<<14, + SafeShortDescription = 1 << 14, /// /// Application's role connections metadata is safe for work. /// - SafeRoleConnections = 1<<15, + SafeRoleConnections = 1 << 15, /// /// Application has met all criteria and is eligible for discovery. /// - Eligible = 1<<16 + Eligible = 1 << 16 } diff --git a/DisCatSharp/Enums/Application/ApplicationFlags.cs b/DisCatSharp/Enums/Application/ApplicationFlags.cs index 48f2a3e5aa..372c01bd6b 100644 --- a/DisCatSharp/Enums/Application/ApplicationFlags.cs +++ b/DisCatSharp/Enums/Application/ApplicationFlags.cs @@ -42,22 +42,22 @@ public enum ApplicationFlags : long /// /// Unknown. /// - AutoModerationRuleCreateBadge = 1<<6, + AutoModerationRuleCreateBadge = 1 << 6, /// /// Allows the application to create activity assets. /// - AllowAssets = 1L<<8, + AllowAssets = 1L << 8, /// /// Allows the application to enable activity spectating. /// - AllowActivityActionSpectate = 1L<<9, + AllowActivityActionSpectate = 1L << 9, /// /// Allows the application to enable join requests for activities. /// - AllowActivityActionJoinRequest = 1L<<10, + AllowActivityActionJoinRequest = 1L << 10, /// /// The application has connected to RPC. diff --git a/DisCatSharp/Enums/Application/ApplicationInteractionsVersion.cs b/DisCatSharp/Enums/Application/ApplicationInteractionsVersion.cs index 10c122f48b..7a80356c11 100644 --- a/DisCatSharp/Enums/Application/ApplicationInteractionsVersion.cs +++ b/DisCatSharp/Enums/Application/ApplicationInteractionsVersion.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationMonetizationEligibilityFlags.cs b/DisCatSharp/Enums/Application/ApplicationMonetizationEligibilityFlags.cs index ea94fdbf47..9d1b2ea59d 100644 --- a/DisCatSharp/Enums/Application/ApplicationMonetizationEligibilityFlags.cs +++ b/DisCatSharp/Enums/Application/ApplicationMonetizationEligibilityFlags.cs @@ -25,95 +25,95 @@ public enum ApplicationMonetizationEligibilityFlags : long /// /// This application is verified /// - Verified = 1<<0, + Verified = 1 << 0, /// /// This application is owned by a team /// - HasTeam = 1<<1, + HasTeam = 1 << 1, /// /// This application has the message content intent approved or utilizes application commands /// - ApprovedCommandsOrMessageContent = 1<<2, + ApprovedCommandsOrMessageContent = 1 << 2, /// /// This application has terms of service set /// - TermsOfService = 1<<3, + TermsOfService = 1 << 3, /// /// This application has a privacy policy set /// - PrivacyPolicy = 1<<4, + PrivacyPolicy = 1 << 4, /// /// This application's name is safe for work /// - SafeName = 1<<5, + SafeName = 1 << 5, /// /// This application's description is safe for work /// - SafeDescription = 1<<6, + SafeDescription = 1 << 6, /// /// This application's role connections metadata is safe for work /// - HasSafeRoleConnections = 1<<7, + HasSafeRoleConnections = 1 << 7, /// /// The user is the owner of the team that owns the application /// - UserIsTeamOwner = 1<<8, + UserIsTeamOwner = 1 << 8, /// /// This application is not quarantined /// - NotQuarantined = 1<<9, + NotQuarantined = 1 << 9, /// /// The user's locale is supported by monetization /// - UserLocaleSupported = 1<<10, + UserLocaleSupported = 1 << 10, /// /// The user is old enough to use monetization /// - UserAgeSupported = 1<<11, + UserAgeSupported = 1 << 11, /// /// The user has a date of birth defined on their account /// - UserDateOfBirthDefined = 1<<12, + UserDateOfBirthDefined = 1 << 12, /// /// The user has MFA enabled /// - UserMfaEnabled = 1<<13, + UserMfaEnabled = 1 << 13, /// /// The user's email is verified /// - UserEmailVerified = 1<<14, + UserEmailVerified = 1 << 14, /// /// All members of the team that owns the application have verified emails /// - TeamMembersEmailVerified = 1<<15, + TeamMembersEmailVerified = 1 << 15, /// /// All members of the team that owns the application have MFA enabled /// - TeamMembersMfaEnabled = 1<<16, + TeamMembersMfaEnabled = 1 << 16, /// /// This application has no issues blocking monetization /// - NoBlockingIssues = 1<<17, + NoBlockingIssues = 1 << 17, /// /// The team has a valid payout status /// - ValidPayoutStatus = 1<<18, + ValidPayoutStatus = 1 << 18 } diff --git a/DisCatSharp/Enums/Application/ApplicationMonetizationState.cs b/DisCatSharp/Enums/Application/ApplicationMonetizationState.cs index a4b17e4ebd..fb6d58e97d 100644 --- a/DisCatSharp/Enums/Application/ApplicationMonetizationState.cs +++ b/DisCatSharp/Enums/Application/ApplicationMonetizationState.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationRoleConnectionMetadataType.cs b/DisCatSharp/Enums/Application/ApplicationRoleConnectionMetadataType.cs index d62386c4fe..074aac0323 100644 --- a/DisCatSharp/Enums/Application/ApplicationRoleConnectionMetadataType.cs +++ b/DisCatSharp/Enums/Application/ApplicationRoleConnectionMetadataType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ApplicationVerificationState.cs b/DisCatSharp/Enums/Application/ApplicationVerificationState.cs index 1f7dbb7d93..a601629a63 100644 --- a/DisCatSharp/Enums/Application/ApplicationVerificationState.cs +++ b/DisCatSharp/Enums/Application/ApplicationVerificationState.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/ExplicitContentFilterLevel.cs b/DisCatSharp/Enums/Application/ExplicitContentFilterLevel.cs index 58d2c90e7c..e69667b5fb 100644 --- a/DisCatSharp/Enums/Application/ExplicitContentFilterLevel.cs +++ b/DisCatSharp/Enums/Application/ExplicitContentFilterLevel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/RpcApplicationState.cs b/DisCatSharp/Enums/Application/RpcApplicationState.cs index 73aba9c71a..cd4cb5582b 100644 --- a/DisCatSharp/Enums/Application/RpcApplicationState.cs +++ b/DisCatSharp/Enums/Application/RpcApplicationState.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Application/StoreApplicationState.cs b/DisCatSharp/Enums/Application/StoreApplicationState.cs index 6a6f3ea7be..66850834bc 100644 --- a/DisCatSharp/Enums/Application/StoreApplicationState.cs +++ b/DisCatSharp/Enums/Application/StoreApplicationState.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Channel/ChannelFlags.cs b/DisCatSharp/Enums/Channel/ChannelFlags.cs index ea1e319f27..f7a1f6cddd 100644 --- a/DisCatSharp/Enums/Channel/ChannelFlags.cs +++ b/DisCatSharp/Enums/Channel/ChannelFlags.cs @@ -31,6 +31,7 @@ public enum ChannelFlags : long /// [DiscordDeprecated] RemovedFromHome = 1L << 0, + [DiscordDeprecated] RemovedFromHighlights = RemovedFromHome, @@ -105,7 +106,7 @@ public enum ChannelFlags : long /// [DiscordInExperiment] IsBroadcasting = 1L << 14, - + /// /// Hides the media download options for channels. /// diff --git a/DisCatSharp/Enums/Channel/ChannelType.cs b/DisCatSharp/Enums/Channel/ChannelType.cs index 6a5670d87d..c0754c946e 100644 --- a/DisCatSharp/Enums/Channel/ChannelType.cs +++ b/DisCatSharp/Enums/Channel/ChannelType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Channel/DirectoryCategory.cs b/DisCatSharp/Enums/Channel/DirectoryCategory.cs index 10f8528a6d..32aa3e432f 100644 --- a/DisCatSharp/Enums/Channel/DirectoryCategory.cs +++ b/DisCatSharp/Enums/Channel/DirectoryCategory.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Channel/OverwriteType.cs b/DisCatSharp/Enums/Channel/OverwriteType.cs index db593cf7c4..4f31968dd5 100644 --- a/DisCatSharp/Enums/Channel/OverwriteType.cs +++ b/DisCatSharp/Enums/Channel/OverwriteType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -14,5 +13,5 @@ public enum OverwriteType : int /// /// Specifies that this overwrite applies to a member. /// - Member = 1, + Member = 1 } diff --git a/DisCatSharp/Enums/Channel/VideoQualityMode.cs b/DisCatSharp/Enums/Channel/VideoQualityMode.cs index a75ed8b7a0..2c310e5df7 100644 --- a/DisCatSharp/Enums/Channel/VideoQualityMode.cs +++ b/DisCatSharp/Enums/Channel/VideoQualityMode.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -14,5 +13,5 @@ public enum VideoQualityMode : int /// /// Indicates that the video quality is 720p. /// - Full = 2, + Full = 2 } diff --git a/DisCatSharp/Enums/Discord/ApiChannel.cs b/DisCatSharp/Enums/Discord/ApiChannel.cs index fbc2a40896..e6e0381186 100644 --- a/DisCatSharp/Enums/Discord/ApiChannel.cs +++ b/DisCatSharp/Enums/Discord/ApiChannel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Discord/DiscordDomain.cs b/DisCatSharp/Enums/Discord/DiscordDomain.cs index 30f2fc11a4..f27cb1cec9 100644 --- a/DisCatSharp/Enums/Discord/DiscordDomain.cs +++ b/DisCatSharp/Enums/Discord/DiscordDomain.cs @@ -120,8 +120,7 @@ public enum CoreDomain /// cdn.discordapp.com /// [DomainHelp("CDN", "cdn.discordapp.com")] - DiscordCdn = 19, - + DiscordCdn = 19 } /// @@ -162,15 +161,13 @@ public enum UnusedDomain /// /// discordapp.io /// - [Obsolete("Not in use.", false)] - [DomainHelp("IO domain for discord", "discordapp.io")] + [Obsolete("Not in use.", false), DomainHelp("IO domain for discord", "discordapp.io")] DiscordAppIo = 1, /// /// discordcdn.com /// - [Obsolete("Not in use.", false)] - [DomainHelp("Alternative CDN domain", "discordcdn.com")] + [Obsolete("Not in use.", false), DomainHelp("Alternative CDN domain", "discordcdn.com")] DiscordCdnCom = 2 } diff --git a/DisCatSharp/Enums/Discord/DiscordEvent.cs b/DisCatSharp/Enums/Discord/DiscordEvent.cs index e9f903e1c4..a0aa49ed99 100644 --- a/DisCatSharp/Enums/Discord/DiscordEvent.cs +++ b/DisCatSharp/Enums/Discord/DiscordEvent.cs @@ -1,4 +1,3 @@ - #nullable enable using System; @@ -27,7 +26,8 @@ public EventAttribute(DiscordEvent evtn) /// Classes marked with this attribute will be considered for event handler registration from an assembly. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] -public class EventHandlerAttribute : Attribute { } +public class EventHandlerAttribute : Attribute +{ } /// /// All events available in for use with . @@ -120,7 +120,7 @@ public enum DiscordEvent AutomodRuleDeleted, AutomodActionExecuted, GuildAuditLogEntryCreated, - VoiceChannelStatusUpdated, + VoiceChannelStatusUpdated, EntitlementCreated, EntitlementUpdated, EntitlementDeleted diff --git a/DisCatSharp/Enums/Discord/DiscordIntents.cs b/DisCatSharp/Enums/Discord/DiscordIntents.cs index b402e91710..f7dfffac34 100644 --- a/DisCatSharp/Enums/Discord/DiscordIntents.cs +++ b/DisCatSharp/Enums/Discord/DiscordIntents.cs @@ -41,7 +41,6 @@ public static DiscordIntents RemoveIntent(this DiscordIntents intents, DiscordIn internal static bool HasAllPrivilegedIntents(this DiscordIntents intents) => intents.HasIntent(DiscordIntents.GuildMembers | DiscordIntents.GuildPresences | DiscordIntents.MessageContent); - /// /// Whether it has all v9 privileged intents. /// @@ -192,7 +191,7 @@ public enum DiscordIntents /// These are all intents excluding , and . /// AllUnprivileged = Guilds | GuildModeration | GuildEmojisAndStickers | GuildIntegrations | GuildWebhooks | GuildInvites | GuildVoiceStates | GuildMessages | - GuildMessageReactions | GuildMessageTyping | DirectMessages | DirectMessageReactions | DirectMessageTyping | GuildScheduledEvents | AutoModerationConfiguration | AutoModerationExecution, + GuildMessageReactions | GuildMessageTyping | DirectMessages | DirectMessageReactions | DirectMessageTyping | GuildScheduledEvents | AutoModerationConfiguration | AutoModerationExecution, /// /// Includes all intents. diff --git a/DisCatSharp/Enums/Discord/DiscordShortlink.cs b/DisCatSharp/Enums/Discord/DiscordShortlink.cs index 435120ed78..43da6e4ea5 100644 --- a/DisCatSharp/Enums/Discord/DiscordShortlink.cs +++ b/DisCatSharp/Enums/Discord/DiscordShortlink.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Discord/GatewayCompressionLevel.cs b/DisCatSharp/Enums/Discord/GatewayCompressionLevel.cs index d30a86220f..e4a949fdcc 100644 --- a/DisCatSharp/Enums/Discord/GatewayCompressionLevel.cs +++ b/DisCatSharp/Enums/Discord/GatewayCompressionLevel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Discord/OAuth.cs b/DisCatSharp/Enums/Discord/OAuth.cs index feeb5b366f..c8f386484c 100644 --- a/DisCatSharp/Enums/Discord/OAuth.cs +++ b/DisCatSharp/Enums/Discord/OAuth.cs @@ -1,4 +1,3 @@ - // ReSharper disable InconsistentNaming namespace DisCatSharp.Enums; @@ -57,9 +56,10 @@ public static string ResolveScopes(OAuthScopes scope) => OAuthScopes.IDENTIFY_BASIC => IDENTIFY_BASIC, OAuthScopes.IDENTIFY_EXTENDED => IDENTIFY_EXTENDED, OAuthScopes.ALL => ALL, - _ => BOT_DEFAULT, + _ => BOT_DEFAULT }; } + /// /// The oauth scopes. /// diff --git a/DisCatSharp/Enums/Discord/TokenType.cs b/DisCatSharp/Enums/Discord/TokenType.cs index d380835d82..9af2e3172b 100644 --- a/DisCatSharp/Enums/Discord/TokenType.cs +++ b/DisCatSharp/Enums/Discord/TokenType.cs @@ -11,7 +11,7 @@ public enum TokenType /// User token type /// [Obsolete("Logging in with a user token may result in your account being terminated, and is therefore highly unrecommended." + - "\nIf anything goes wrong with this, we will not provide any support!", true)] + "\nIf anything goes wrong with this, we will not provide any support!", true)] User = 0, /// diff --git a/DisCatSharp/Enums/Guild/AuditLogActionCategory.cs b/DisCatSharp/Enums/Guild/AuditLog/AuditLogActionCategory.cs similarity index 99% rename from DisCatSharp/Enums/Guild/AuditLogActionCategory.cs rename to DisCatSharp/Enums/Guild/AuditLog/AuditLogActionCategory.cs index cfc78901d5..c8ea06cffc 100644 --- a/DisCatSharp/Enums/Guild/AuditLogActionCategory.cs +++ b/DisCatSharp/Enums/Guild/AuditLog/AuditLogActionCategory.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/AuditLogActionType.cs b/DisCatSharp/Enums/Guild/AuditLog/AuditLogActionType.cs similarity index 57% rename from DisCatSharp/Enums/Guild/AuditLogActionType.cs rename to DisCatSharp/Enums/Guild/AuditLog/AuditLogActionType.cs index 4b4824045c..0ff4d2978b 100644 --- a/DisCatSharp/Enums/Guild/AuditLogActionType.cs +++ b/DisCatSharp/Enums/Guild/AuditLog/AuditLogActionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -17,72 +16,72 @@ public enum AuditLogActionType GuildUpdate = 1, /// - /// Indicates that the channel was created. + /// Indicates that a channel was created. /// ChannelCreate = 10, /// - /// Indicates that the channel was updated. + /// Indicates that a channel was updated. /// ChannelUpdate = 11, /// - /// Indicates that the channel was deleted. + /// Indicates that a channel was deleted. /// ChannelDelete = 12, /// - /// Indicates that the channel permission overwrite was created. + /// Indicates that a channel permission overwrite was created. /// - OverwriteCreate = 13, + ChannelOverwriteCreate = 13, /// - /// Indicates that the channel permission overwrite was updated. + /// Indicates that a channel permission overwrite was updated. /// - OverwriteUpdate = 14, + ChannelOverwriteUpdate = 14, /// - /// Indicates that the channel permission overwrite was deleted. + /// Indicates that a channel permission overwrite was deleted. /// - OverwriteDelete = 15, + ChannelOverwriteDelete = 15, /// - /// Indicates that the user was kicked. + /// Indicates that a user was kicked. /// - Kick = 20, + MemberKick = 20, /// /// Indicates that users were pruned. /// - Prune = 21, + MemberPrune = 21, /// - /// Indicates that the user was banned. + /// Indicates that a user was banned. /// - Ban = 22, + MemberBanAdd = 22, /// - /// Indicates that the user was unbanned. + /// Indicates that a user was unbanned. /// - Unban = 23, + MemberBanRemove = 23, /// - /// Indicates that the member was updated. + /// Indicates that a member was updated. /// MemberUpdate = 24, /// - /// Indicates that the member's roles were updated. + /// Indicates that a member's roles were updated. /// MemberRoleUpdate = 25, /// - /// Indicates that the member has moved to another voice channel. + /// Indicates that a member was moved to another voice channel. /// MemberMove = 26, /// - /// Indicates that the member has disconnected from a voice channel. + /// Indicates that a member was disconnected from a voice channel. /// MemberDisconnect = 27, @@ -92,47 +91,47 @@ public enum AuditLogActionType BotAdd = 28, /// - /// Indicates that the role was created. + /// Indicates that a role was created. /// RoleCreate = 30, /// - /// Indicates that the role was updated. + /// Indicates that a role was updated. /// RoleUpdate = 31, /// - /// Indicates that the role was deleted. + /// Indicates that a role was deleted. /// RoleDelete = 32, /// - /// Indicates that the invite was created. + /// Indicates that an invite was created. /// InviteCreate = 40, /// - /// Indicates that the invite was updated. + /// Indicates that an invite was updated. /// InviteUpdate = 41, /// - /// Indicates that the invite was deleted. + /// Indicates that an invite was deleted. /// InviteDelete = 42, /// - /// Indicates that the webhook was created. + /// Indicates that a webhook was created. /// WebhookCreate = 50, /// - /// Indicates that the webook was updated. + /// Indicates that a webook was updated. /// WebhookUpdate = 51, /// - /// Indicates that the webhook was deleted. + /// Indicates that a webhook was deleted. /// WebhookDelete = 52, @@ -152,7 +151,7 @@ public enum AuditLogActionType EmojiDelete = 62, /// - /// Indicates that the message was deleted. + /// Indicates that a message was deleted. /// MessageDelete = 72, @@ -187,32 +186,32 @@ public enum AuditLogActionType IntegrationDelete = 82, /// - /// Indicates that an stage instance was created. + /// Indicates that a stage instance was created. /// StageInstanceCreate = 83, /// - /// Indicates that an stage instance was updated. + /// Indicates that a stage instance was updated. /// StageInstanceUpdate = 84, /// - /// Indicates that an stage instance was deleted. + /// Indicates that a stage instance was deleted. /// StageInstanceDelete = 85, /// - /// Indicates that an sticker was created. + /// Indicates that a sticker was created. /// StickerCreate = 90, /// - /// Indicates that an sticker was updated. + /// Indicates that a sticker was updated. /// StickerUpdate = 91, /// - /// Indicates that an sticker was deleted. + /// Indicates that a sticker was deleted. /// StickerDelete = 92, @@ -232,37 +231,37 @@ public enum AuditLogActionType GuildScheduledEventDelete = 102, /// - /// Indicates that an thread was created. + /// Indicates that a thread was created. /// ThreadCreate = 110, /// - /// Indicates that an thread was updated. + /// Indicates that a thread was updated. /// ThreadUpdate = 111, /// - /// Indicates that an thread was deleted. + /// Indicates that a thread was deleted. /// ThreadDelete = 112, /// - /// Indicates that the permissions for an application command was updated. + /// Indicates that permissions for an application command were updated. /// ApplicationCommandPermissionUpdate = 121, /// - /// Indicates that a new automod rule has been added. + /// Indicates that an automod rule has been added. /// AutoModerationRuleCreate = 140, /// - /// Indicates that a automod rule has been updated. + /// Indicates that an automod rule has been updated. /// AutoModerationRuleUpdate = 141, /// - /// Indicates that a automod rule has been deleted. + /// Indicates that an automod rule has been deleted. /// AutoModerationRuleDelete = 142, @@ -274,22 +273,66 @@ public enum AuditLogActionType /// /// Indicates that automod flagged a message. /// - AutoModerationFlagMessage = 144, + AutoModerationFlagToChannel = 144, /// /// Indicates that automod timed out a user. /// - AutoModerationTimeOutUser = 145, + AutoModerationUserCommunicationDisabled = 145, /// /// Indicates that automod quarantined a user. /// AutoModerationQuarantineUser = 146, + /// + /// Indicates that a creator monetization request was created. + /// + CreatorMonetizationRequestCreated = 150, + + /// + /// Indicates that the creator monetization terms were accepted. + /// + CreatorMonetizationTermsAccepted = 151, + + /// + /// Indicates that an onboarding question was created. + /// OnboardingQuestionCreate = 163, + + /// + /// Indicates that an onboarding question was updated. + /// OnboardingQuestionUpdate = 164, + + /// + /// Indicates that the onboarding was updated. + /// OnboardingUpdate = 167, + + /// + /// Indicates that the server guide was created. + /// ServerGuideCreate = 190, + + /// + /// Indicates that the server guide was updated. + /// ServerGuideUpdate = 191, - VoiceChannelStatusUpdate = 192 + + /// + /// Indicates that a voice channel status was updated. + /// + VoiceChannelStatusUpdate = 192, + + /// + /// Indicates that a voice channel status was deleted. + /// + VoiceChannelStatusDelete = 193, + + /// + /// Indicates that the Clyde AI profile was updated. + /// + // ReSharper disable once InconsistentNaming + ClydeAIProfileUpdate = 194 } diff --git a/DisCatSharp/Enums/Guild/Automod/AutomodActionType.cs b/DisCatSharp/Enums/Guild/Automod/AutomodActionType.cs index 9302de1f9f..4972a3aa68 100644 --- a/DisCatSharp/Enums/Guild/Automod/AutomodActionType.cs +++ b/DisCatSharp/Enums/Guild/Automod/AutomodActionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/Automod/AutomodEventType.cs b/DisCatSharp/Enums/Guild/Automod/AutomodEventType.cs index 20b46b8401..dfdbda0f48 100644 --- a/DisCatSharp/Enums/Guild/Automod/AutomodEventType.cs +++ b/DisCatSharp/Enums/Guild/Automod/AutomodEventType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/Automod/AutomodKeywordPresetType.cs b/DisCatSharp/Enums/Guild/Automod/AutomodKeywordPresetType.cs index e980a98f08..a72215af00 100644 --- a/DisCatSharp/Enums/Guild/Automod/AutomodKeywordPresetType.cs +++ b/DisCatSharp/Enums/Guild/Automod/AutomodKeywordPresetType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/DefaultMessageNotifications.cs b/DisCatSharp/Enums/Guild/DefaultMessageNotifications.cs index 49562bb672..789166c8c9 100644 --- a/DisCatSharp/Enums/Guild/DefaultMessageNotifications.cs +++ b/DisCatSharp/Enums/Guild/DefaultMessageNotifications.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/ExplicitContentFilter.cs b/DisCatSharp/Enums/Guild/ExplicitContentFilter.cs index 6f000602c7..1fad0381c3 100644 --- a/DisCatSharp/Enums/Guild/ExplicitContentFilter.cs +++ b/DisCatSharp/Enums/Guild/ExplicitContentFilter.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/HubType.cs b/DisCatSharp/Enums/Guild/HubType.cs index 2818366b2b..a02b68cf4d 100644 --- a/DisCatSharp/Enums/Guild/HubType.cs +++ b/DisCatSharp/Enums/Guild/HubType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/MemberFlags.cs b/DisCatSharp/Enums/Guild/MemberFlags.cs index 13895a729d..d44e3b3ddd 100644 --- a/DisCatSharp/Enums/Guild/MemberFlags.cs +++ b/DisCatSharp/Enums/Guild/MemberFlags.cs @@ -45,6 +45,7 @@ public enum MemberFlags : long /// [DiscordInExperiment] BypassesVerification = 1 << 2, + [DiscordInExperiment] Verified = BypassesVerification, @@ -77,12 +78,11 @@ public enum MemberFlags : long /// Members username or nickname contains words that are not allowed. /// [DiscordInExperiment] - AutomodQuarantinedUsernameOrGuildNickname = 1<<7, + AutomodQuarantinedUsernameOrGuildNickname = 1 << 7, /// /// Members user or guild bio contains words that are not allowed. /// [DiscordInExperiment] - AutomodQuarantinedBio = 1<<8 + AutomodQuarantinedBio = 1 << 8 } - diff --git a/DisCatSharp/Enums/Guild/MfaLevel.cs b/DisCatSharp/Enums/Guild/MfaLevel.cs index 2000bb2f5b..d9cf269137 100644 --- a/DisCatSharp/Enums/Guild/MfaLevel.cs +++ b/DisCatSharp/Enums/Guild/MfaLevel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/NsfwLevel.cs b/DisCatSharp/Enums/Guild/NsfwLevel.cs index f129f0f384..15514a9fd6 100644 --- a/DisCatSharp/Enums/Guild/NsfwLevel.cs +++ b/DisCatSharp/Enums/Guild/NsfwLevel.cs @@ -1,4 +1,3 @@ - // ReSharper disable InconsistentNaming namespace DisCatSharp.Enums; diff --git a/DisCatSharp/Enums/Guild/Onboarding/NewMemberActionType.cs b/DisCatSharp/Enums/Guild/Onboarding/NewMemberActionType.cs index 4054629d5e..68a74b728b 100644 --- a/DisCatSharp/Enums/Guild/Onboarding/NewMemberActionType.cs +++ b/DisCatSharp/Enums/Guild/Onboarding/NewMemberActionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/Onboarding/OnboardingMode.cs b/DisCatSharp/Enums/Guild/Onboarding/OnboardingMode.cs index 85cd1b3f2c..27b8e8246d 100644 --- a/DisCatSharp/Enums/Guild/Onboarding/OnboardingMode.cs +++ b/DisCatSharp/Enums/Guild/Onboarding/OnboardingMode.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/Onboarding/PromptType.cs b/DisCatSharp/Enums/Guild/Onboarding/PromptType.cs index 239850aac5..101c34b654 100644 --- a/DisCatSharp/Enums/Guild/Onboarding/PromptType.cs +++ b/DisCatSharp/Enums/Guild/Onboarding/PromptType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/Permission.cs b/DisCatSharp/Enums/Guild/Permission.cs index c3105a26c6..c1a66d4d10 100644 --- a/DisCatSharp/Enums/Guild/Permission.cs +++ b/DisCatSharp/Enums/Guild/Permission.cs @@ -138,7 +138,7 @@ public enum Permissions : long /// Allows the user to go live. /// [PermissionString("Allow Stream")] - Stream = 1L << 9, + Stream = 1L << 9, /// /// Allows accessing text and voice channels. Disabling this permission hides channels. @@ -366,7 +366,7 @@ public enum Permissions : long /// Allows members to interact with the Clyde AI bot. /// [PermissionString("Use Clyde AI"), DiscordInExperiment] - UseClydeAi = 1L<<47, + UseClydeAi = 1L << 47, /// /// Allows members to create and edit voice channel status. diff --git a/DisCatSharp/Enums/Guild/PremiumTier.cs b/DisCatSharp/Enums/Guild/PremiumTier.cs index 532c5702f5..4e56289a2a 100644 --- a/DisCatSharp/Enums/Guild/PremiumTier.cs +++ b/DisCatSharp/Enums/Guild/PremiumTier.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/PriceTierType.cs b/DisCatSharp/Enums/Guild/PriceTierType.cs index 88a1c2697a..b8ba1258c6 100644 --- a/DisCatSharp/Enums/Guild/PriceTierType.cs +++ b/DisCatSharp/Enums/Guild/PriceTierType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/RoleFlags.cs b/DisCatSharp/Enums/Guild/RoleFlags.cs index 51ce13d745..febce8d2eb 100644 --- a/DisCatSharp/Enums/Guild/RoleFlags.cs +++ b/DisCatSharp/Enums/Guild/RoleFlags.cs @@ -16,6 +16,5 @@ public enum RoleFlags /// /// This role is in a prompt. /// - InPrompt = 1 << 0, + InPrompt = 1 << 0 } - diff --git a/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventEntityType.cs b/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventEntityType.cs index fd3d1420a1..eaceed2a60 100644 --- a/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventEntityType.cs +++ b/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventEntityType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventStatus.cs b/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventStatus.cs index 32b465c2e2..9b66613adf 100644 --- a/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventStatus.cs +++ b/DisCatSharp/Enums/Guild/ScheduledEvent/ScheduledEventStatus.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/SystemChannelFlags.cs b/DisCatSharp/Enums/Guild/SystemChannelFlags.cs index 322992f241..3845e6299f 100644 --- a/DisCatSharp/Enums/Guild/SystemChannelFlags.cs +++ b/DisCatSharp/Enums/Guild/SystemChannelFlags.cs @@ -45,10 +45,10 @@ public enum SystemChannelFlags /// /// Role subscription purchase messages are disabled. /// - SuppressRoleSubbscriptionPurchaseNotification = 1<<4, + SuppressRoleSubbscriptionPurchaseNotification = 1 << 4, /// /// Suppress role subscription purchase sticker replies. /// - SuppressRoleSubbscriptionPurchaseNotificationReplies = 1<<5, + SuppressRoleSubbscriptionPurchaseNotificationReplies = 1 << 5 } diff --git a/DisCatSharp/Enums/Guild/ThreadAndForum/ForumLayout.cs b/DisCatSharp/Enums/Guild/ThreadAndForum/ForumLayout.cs index 0dfdc50f73..ec214c4d86 100644 --- a/DisCatSharp/Enums/Guild/ThreadAndForum/ForumLayout.cs +++ b/DisCatSharp/Enums/Guild/ThreadAndForum/ForumLayout.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/ThreadAndForum/ForumPostSortOrder.cs b/DisCatSharp/Enums/Guild/ThreadAndForum/ForumPostSortOrder.cs index 8e4976a92b..d1c4aebe7e 100644 --- a/DisCatSharp/Enums/Guild/ThreadAndForum/ForumPostSortOrder.cs +++ b/DisCatSharp/Enums/Guild/ThreadAndForum/ForumPostSortOrder.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadAutoArchiveDuration.cs b/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadAutoArchiveDuration.cs index f4a640723f..99c0ec91ab 100644 --- a/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadAutoArchiveDuration.cs +++ b/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadAutoArchiveDuration.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadMemberFlags.cs b/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadMemberFlags.cs index d2477b20f4..5fabe5f5f1 100644 --- a/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadMemberFlags.cs +++ b/DisCatSharp/Enums/Guild/ThreadAndForum/ThreadMemberFlags.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/VerificationLevel.cs b/DisCatSharp/Enums/Guild/VerificationLevel.cs index f4f39c98c8..ab35c87164 100644 --- a/DisCatSharp/Enums/Guild/VerificationLevel.cs +++ b/DisCatSharp/Enums/Guild/VerificationLevel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Guild/WidgetType.cs b/DisCatSharp/Enums/Guild/WidgetType.cs index d96add0487..9694ce9e93 100644 --- a/DisCatSharp/Enums/Guild/WidgetType.cs +++ b/DisCatSharp/Enums/Guild/WidgetType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Integration/IntegrationExpireBehavior.cs b/DisCatSharp/Enums/Integration/IntegrationExpireBehavior.cs index 4d572ea160..3a2cf352cc 100644 --- a/DisCatSharp/Enums/Integration/IntegrationExpireBehavior.cs +++ b/DisCatSharp/Enums/Integration/IntegrationExpireBehavior.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Interaction/ButtonStyle.cs b/DisCatSharp/Enums/Interaction/ButtonStyle.cs index f6ddb5d129..990883fbba 100644 --- a/DisCatSharp/Enums/Interaction/ButtonStyle.cs +++ b/DisCatSharp/Enums/Interaction/ButtonStyle.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -19,7 +18,7 @@ public enum ButtonStyle : int /// /// Green button. /// - Success = 3, + Success = 3, /// /// Red button. diff --git a/DisCatSharp/Enums/Interaction/ComponentType.cs b/DisCatSharp/Enums/Interaction/ComponentType.cs index 709448047a..ce2b063cb6 100644 --- a/DisCatSharp/Enums/Interaction/ComponentType.cs +++ b/DisCatSharp/Enums/Interaction/ComponentType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -44,5 +43,5 @@ public enum ComponentType /// /// A select menu to select channels. /// - ChannelSelect = 8, + ChannelSelect = 8 } diff --git a/DisCatSharp/Enums/Interaction/IFrameModalSize.cs b/DisCatSharp/Enums/Interaction/IFrameModalSize.cs index 22f0e62821..276f8cbca0 100644 --- a/DisCatSharp/Enums/Interaction/IFrameModalSize.cs +++ b/DisCatSharp/Enums/Interaction/IFrameModalSize.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -19,5 +18,5 @@ public enum IframeModalSize : int /// /// Sends a big iFrame. /// - Big = 3 + Big = 3 } diff --git a/DisCatSharp/Enums/Interaction/InteractionResponseType.cs b/DisCatSharp/Enums/Interaction/InteractionResponseType.cs index 0f44cab0b7..d25209ac7b 100644 --- a/DisCatSharp/Enums/Interaction/InteractionResponseType.cs +++ b/DisCatSharp/Enums/Interaction/InteractionResponseType.cs @@ -51,7 +51,7 @@ public enum InteractionResponseType /// /// Responds to the interaction with an iframe. - /// Can only be used if you are whitelisted.. + /// Can only be used if you are whitelisted. /// [DiscordInExperiment("Currently in closed beta."), Experimental("We provide this type but can't provide support.")] Iframe = 11 diff --git a/DisCatSharp/Enums/Interaction/InteractionType.cs b/DisCatSharp/Enums/Interaction/InteractionType.cs index 462cbda360..5d519e99b6 100644 --- a/DisCatSharp/Enums/Interaction/InteractionType.cs +++ b/DisCatSharp/Enums/Interaction/InteractionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Interaction/TextComponentStyle.cs b/DisCatSharp/Enums/Interaction/TextComponentStyle.cs index a6a96fec6f..610941dc4f 100644 --- a/DisCatSharp/Enums/Interaction/TextComponentStyle.cs +++ b/DisCatSharp/Enums/Interaction/TextComponentStyle.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Invite/InviteFlags.cs b/DisCatSharp/Enums/Invite/InviteFlags.cs index c37b19a4b3..2bf2cfe511 100644 --- a/DisCatSharp/Enums/Invite/InviteFlags.cs +++ b/DisCatSharp/Enums/Invite/InviteFlags.cs @@ -28,10 +28,10 @@ public enum InviteFlags : int /// Invite grants temporary guest membership. /// All channels but the one invited to are hidden and user gets kicked if they leave the voice. /// - GuestMembership = 1<<0, + GuestMembership = 1 << 0, /// /// The invite has been viewed by any user (has been retrieved using the get invite endpoint). /// - Viewed = 1<<1 + Viewed = 1 << 1 } diff --git a/DisCatSharp/Enums/Invite/InviteType.cs b/DisCatSharp/Enums/Invite/InviteType.cs index 37d1c582d4..dccd50b0ad 100644 --- a/DisCatSharp/Enums/Invite/InviteType.cs +++ b/DisCatSharp/Enums/Invite/InviteType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Invite/TargetType.cs b/DisCatSharp/Enums/Invite/TargetType.cs index cb56c16e6a..15537c069c 100644 --- a/DisCatSharp/Enums/Invite/TargetType.cs +++ b/DisCatSharp/Enums/Invite/TargetType.cs @@ -1,8 +1,7 @@ - namespace DisCatSharp.Enums; /// -/// Represents the invite type . +/// Represents the invite type. /// public enum TargetType { diff --git a/DisCatSharp/Enums/Message/AttachmentFlags.cs b/DisCatSharp/Enums/Message/AttachmentFlags.cs index b4bd60aa6d..b5c32954a0 100644 --- a/DisCatSharp/Enums/Message/AttachmentFlags.cs +++ b/DisCatSharp/Enums/Message/AttachmentFlags.cs @@ -52,5 +52,5 @@ public enum AttachmentFlags /// /// This attachment contains explicit media. /// - ContainsExplicitMedia = 1 << 4, + ContainsExplicitMedia = 1 << 4 } diff --git a/DisCatSharp/Enums/Message/MentionType.cs b/DisCatSharp/Enums/Message/MentionType.cs index 0ce715e9e9..923c8a392e 100644 --- a/DisCatSharp/Enums/Message/MentionType.cs +++ b/DisCatSharp/Enums/Message/MentionType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Message/MessageActivityType.cs b/DisCatSharp/Enums/Message/MessageActivityType.cs index 63c801105b..6a70e68235 100644 --- a/DisCatSharp/Enums/Message/MessageActivityType.cs +++ b/DisCatSharp/Enums/Message/MessageActivityType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Message/MessageType.cs b/DisCatSharp/Enums/Message/MessageType.cs index 14028a8c7a..17cca04e9b 100644 --- a/DisCatSharp/Enums/Message/MessageType.cs +++ b/DisCatSharp/Enums/Message/MessageType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// @@ -206,6 +205,11 @@ public enum MessageType : int /// GuildIncidentReportFalseAlarm = 39, + /// + /// Message indicating a poll was created. + /// + Poll = 43, + /// /// Message indicating that a user bought something from the server shop. /// diff --git a/DisCatSharp/Enums/Message/TimestampFormat.cs b/DisCatSharp/Enums/Message/TimestampFormat.cs index 6bd16d0c01..8f2d5812f6 100644 --- a/DisCatSharp/Enums/Message/TimestampFormat.cs +++ b/DisCatSharp/Enums/Message/TimestampFormat.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Store/EntitlementOwnerType.cs b/DisCatSharp/Enums/Store/EntitlementOwnerType.cs index 0017e696cb..42c9308bf7 100644 --- a/DisCatSharp/Enums/Store/EntitlementOwnerType.cs +++ b/DisCatSharp/Enums/Store/EntitlementOwnerType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Store/EntitlementType.cs b/DisCatSharp/Enums/Store/EntitlementType.cs index 1b681891e8..f560443d14 100644 --- a/DisCatSharp/Enums/Store/EntitlementType.cs +++ b/DisCatSharp/Enums/Store/EntitlementType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Store/SkuAccessType.cs b/DisCatSharp/Enums/Store/SkuAccessType.cs index c8cd661367..d015124dfc 100644 --- a/DisCatSharp/Enums/Store/SkuAccessType.cs +++ b/DisCatSharp/Enums/Store/SkuAccessType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/Store/SkuType.cs b/DisCatSharp/Enums/Store/SkuType.cs index 3fa5805304..e70c02c7bb 100644 --- a/DisCatSharp/Enums/Store/SkuType.cs +++ b/DisCatSharp/Enums/Store/SkuType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/User/ConnectionMetadataVisibilityType.cs b/DisCatSharp/Enums/User/ConnectionMetadataVisibilityType.cs index 63a5a473dc..53a9990f81 100644 --- a/DisCatSharp/Enums/User/ConnectionMetadataVisibilityType.cs +++ b/DisCatSharp/Enums/User/ConnectionMetadataVisibilityType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/User/ConnectionVisibilityType.cs b/DisCatSharp/Enums/User/ConnectionVisibilityType.cs index bf7acf3097..baa4afb1e4 100644 --- a/DisCatSharp/Enums/User/ConnectionVisibilityType.cs +++ b/DisCatSharp/Enums/User/ConnectionVisibilityType.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Enums; /// diff --git a/DisCatSharp/Enums/User/UserFlags.cs b/DisCatSharp/Enums/User/UserFlags.cs index 1913e9dc9f..4d01070f04 100644 --- a/DisCatSharp/Enums/User/UserFlags.cs +++ b/DisCatSharp/Enums/User/UserFlags.cs @@ -195,5 +195,5 @@ public enum UserFlags : long /// /// User is a restricted collaborator and has staff permissions. /// - RestrictedCollaborator = 1L << 51, + RestrictedCollaborator = 1L << 51 } diff --git a/DisCatSharp/Enums/Voice/SpeakingFlags.cs b/DisCatSharp/Enums/Voice/SpeakingFlags.cs index c4dc766fd9..b1aee236c0 100644 --- a/DisCatSharp/Enums/Voice/SpeakingFlags.cs +++ b/DisCatSharp/Enums/Voice/SpeakingFlags.cs @@ -27,15 +27,15 @@ public enum SpeakingFlags : int /// /// Normal transmission of voice audio. /// - Microphone = 1<<0, + Microphone = 1 << 0, /// /// Transmission of context audio for video, no speaking indicator. /// - Soundshare = 1<<1, + Soundshare = 1 << 1, /// /// Priority speaker, lowering audio of other speakers. /// - Priority = 1<<2 + Priority = 1 << 2 } diff --git a/DisCatSharp/Enums/Webhook/WebhookType.cs b/DisCatSharp/Enums/Webhook/WebhookType.cs new file mode 100644 index 0000000000..c81392b172 --- /dev/null +++ b/DisCatSharp/Enums/Webhook/WebhookType.cs @@ -0,0 +1,22 @@ +namespace DisCatSharp.Enums; + +/// +/// Represents the type of a webhook. +/// +public enum WebhookType : int +{ + /// + /// Incoming webhooks can post messages to channels with a generated token. + /// + Incoming = 1, + + /// + /// Channel follower webhooks are internal webhooks used with channel following to post new messages into channels. + /// + ChannelFollower = 2, + + /// + /// Application webhooks are webhooks used with interactions. + /// + Application = 3 +} diff --git a/DisCatSharp/EventArgs/Guild/Member/GuildMemberUpdateEventArgs.cs b/DisCatSharp/EventArgs/Guild/Member/GuildMemberUpdateEventArgs.cs index 4c3c21bafb..9a0b7b4cef 100644 --- a/DisCatSharp/EventArgs/Guild/Member/GuildMemberUpdateEventArgs.cs +++ b/DisCatSharp/EventArgs/Guild/Member/GuildMemberUpdateEventArgs.cs @@ -86,13 +86,12 @@ public string GuildAvatarUrlAfter public virtual string AvatarHashBefore { get; internal set; } public string AvatarUrlBefore - => string.IsNullOrWhiteSpace(this.AvatarHashBefore) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.GUILDS}/{this.Guild.Id.ToString(CultureInfo.InvariantCulture)}{Endpoints.USERS}/{this.Member.Id.ToString(CultureInfo.InvariantCulture)}{Endpoints.AVATARS}/{this.AvatarHashBefore}.{(this.AvatarHashBefore.StartsWith("a_") ? "gif" : "png")}?size=1024"; + => string.IsNullOrWhiteSpace(this.AvatarHashBefore) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.AVATARS}/{this.Member.Id.ToString(CultureInfo.InvariantCulture)}/{this.AvatarHashBefore}.{(this.AvatarHashBefore.StartsWith("a_") ? "gif" : "png")}?size=1024"; public virtual string AvatarHashAfter { get; internal set; } public string AvatarUrlAfter - => string.IsNullOrWhiteSpace(this.AvatarHashAfter) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.GUILDS}/{this.Guild.Id.ToString(CultureInfo.InvariantCulture)}{Endpoints.USERS}/{this.Member.Id.ToString(CultureInfo.InvariantCulture)}{Endpoints.AVATARS}/{this.AvatarHashAfter}.{(this.AvatarHashAfter.StartsWith("a_") ? "gif" : "png")}?size=1024"; - + => string.IsNullOrWhiteSpace(this.AvatarHashAfter) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.AVATARS}/{this.Member.Id.ToString(CultureInfo.InvariantCulture)}/{this.AvatarHashAfter}.{(this.AvatarHashAfter.StartsWith("a_") ? "gif" : "png")}?size=1024"; /// /// Initializes a new instance of the class. diff --git a/DisCatSharp/EventArgs/Guild/Thread/ThreadMembersUpdateEventArgs.cs b/DisCatSharp/EventArgs/Guild/Thread/ThreadMembersUpdateEventArgs.cs index a784d64863..cadc20d091 100644 --- a/DisCatSharp/EventArgs/Guild/Thread/ThreadMembersUpdateEventArgs.cs +++ b/DisCatSharp/EventArgs/Guild/Thread/ThreadMembersUpdateEventArgs.cs @@ -20,7 +20,6 @@ public class ThreadMembersUpdateEventArgs : DiscordEventArgs /// public IReadOnlyList RemovedMembers { get; internal set; } - /// /// Gets the users who were added to the thread. /// diff --git a/DisCatSharp/EventArgs/PayloadReceivedEventArgs.cs b/DisCatSharp/EventArgs/PayloadReceivedEventArgs.cs index 8b965a0998..28918c1d7d 100644 --- a/DisCatSharp/EventArgs/PayloadReceivedEventArgs.cs +++ b/DisCatSharp/EventArgs/PayloadReceivedEventArgs.cs @@ -23,6 +23,7 @@ public string Json } private string _json; + /// /// Gets or sets the payload object. /// diff --git a/DisCatSharp/Formatter.cs b/DisCatSharp/Formatter.cs index b9b64f0050..07b220011d 100644 --- a/DisCatSharp/Formatter.cs +++ b/DisCatSharp/Formatter.cs @@ -17,6 +17,7 @@ public static class Formatter /// Gets the md sanitize regex. /// private static Regex s_mdSanitizeRegex { get; } = new(@"([`\*_~<>\[\]\(\)""@\!\&#:\|])", RegexOptions.ECMAScript); + /// /// Gets the md strip regex. /// @@ -197,8 +198,8 @@ public static string Strip(this string text) /// Formatted mention. public static string Mention(this DiscordUser user, bool nickname = false) => nickname - ? $"<@!{user.Id.ToString(CultureInfo.InvariantCulture)}>" - : $"<@{user.Id.ToString(CultureInfo.InvariantCulture)}>"; + ? $"<@!{user.Id.ToString(CultureInfo.InvariantCulture)}>" + : $"<@{user.Id.ToString(CultureInfo.InvariantCulture)}>"; /// /// Creates a mention for specified channel. diff --git a/DisCatSharp/GlobalSuppressions.cs b/DisCatSharp/GlobalSuppressions.cs index aa23ef6025..ff710c3729 100644 --- a/DisCatSharp/GlobalSuppressions.cs +++ b/DisCatSharp/GlobalSuppressions.cs @@ -82,3 +82,4 @@ [assembly: SuppressMessage("Usage", "DCS0200:[Discord] Requires Features", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Entities.DiscordGuild.PublicUpdatesChannel")] [assembly: SuppressMessage("Usage", "DCS0200:[Discord] Requires Features", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Entities.DiscordGuild.RulesChannel")] [assembly: SuppressMessage("Usage", "DCS0200:[Discord] Requires Features", Justification = "", Scope = "member", Target = "~P:DisCatSharp.Entities.DiscordGuild.SafetyAltersChannel")] +[assembly: SuppressMessage("Style", "IDE0048:Add parentheses for clarity", Justification = "", Scope = "member", Target = "~M:DisCatSharp.Entities.DiscordRole.op_Equality(DisCatSharp.Entities.DiscordRole,DisCatSharp.Entities.DiscordRole)~System.Boolean")] diff --git a/DisCatSharp/ImageTool.cs b/DisCatSharp/ImageTool.cs index 093b243b62..f29175d344 100644 --- a/DisCatSharp/ImageTool.cs +++ b/DisCatSharp/ImageTool.cs @@ -15,26 +15,32 @@ public sealed class ImageTool : IDisposable /// The png magic . /// private const ulong PNG_MAGIC = 0x0A1A_0A0D_474E_5089; + /// /// The jpeg magic 1. /// private const ushort JPEG_MAGIC_1 = 0xD8FF; + /// /// The jpeg magic 2. /// private const ushort JPEG_MAGIC_2 = 0xD9FF; + /// /// The gif magic 1 /// private const ulong GIF_MAGIC_1 = 0x0000_6139_3846_4947; + /// /// The gif magic 2. /// private const ulong GIF_MAGIC_2 = 0x0000_6137_3846_4947; + /// /// The webp magic 1. /// private const uint WEBP_MAGIC_1 = 0x4646_4952; + /// /// The webp magic 2. /// @@ -44,10 +50,12 @@ public sealed class ImageTool : IDisposable /// The gif mask. /// private const ulong GIF_MASK = 0x0000_FFFF_FFFF_FFFF; + /// /// The mask 32. /// private const ulong MASK32 = 0x0000_0000_FFFF_FFFF; + /// /// The mask 16. /// diff --git a/DisCatSharp/Logging/DefaultLogger.cs b/DisCatSharp/Logging/DefaultLogger.cs index 394780c120..04c57f593d 100644 --- a/DisCatSharp/Logging/DefaultLogger.cs +++ b/DisCatSharp/Logging/DefaultLogger.cs @@ -86,6 +86,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except Console.ForegroundColor = ConsoleColor.Black; break; } + Console.Write(logLevel switch { LogLevel.Trace => "[Trace] ", diff --git a/DisCatSharp/Logging/DefaultLoggerFactory.cs b/DisCatSharp/Logging/DefaultLoggerFactory.cs index 9d0597ce1b..32a6b53158 100644 --- a/DisCatSharp/Logging/DefaultLoggerFactory.cs +++ b/DisCatSharp/Logging/DefaultLoggerFactory.cs @@ -14,6 +14,7 @@ internal class DefaultLoggerFactory : ILoggerFactory /// Gets the providers. /// private readonly List _providers = new(); + private bool _isDisposed; /// @@ -40,6 +41,7 @@ public void Dispose() { if (this._isDisposed) return; + this._isDisposed = true; foreach (var provider in this._providers) diff --git a/DisCatSharp/Net/Abstractions/AuditLogAbstractions.cs b/DisCatSharp/Net/Abstractions/AuditLogAbstractions.cs index 41070d3c4d..eb98eca75b 100644 --- a/DisCatSharp/Net/Abstractions/AuditLogAbstractions.cs +++ b/DisCatSharp/Net/Abstractions/AuditLogAbstractions.cs @@ -547,6 +547,9 @@ internal sealed class AuditLog : ObservableApiObject public IReadOnlyList ApplicationCommands { get; set; } */ internal AuditLog() - : base(new() { "application_commands", "auto_moderation_rules" }) + : base(new() + { + "application_commands", "auto_moderation_rules" + }) { } } diff --git a/DisCatSharp/Net/Abstractions/ClientProperties.cs b/DisCatSharp/Net/Abstractions/ClientProperties.cs index 00d5bce53c..25bed502f0 100644 --- a/DisCatSharp/Net/Abstractions/ClientProperties.cs +++ b/DisCatSharp/Net/Abstractions/ClientProperties.cs @@ -40,7 +40,12 @@ public string OperatingSystem return "miros bsd"; else if (plat.Contains("desktopbsd")) return "desktopbsd"; - else return plat.Contains("darwin") ? "osx" : plat.Contains("unix") ? "unix" : "toaster (unknown)"; + else + return plat.Contains("darwin") + ? "osx" + : plat.Contains("unix") + ? "unix" + : "toaster (unknown)"; } } diff --git a/DisCatSharp/Net/Abstractions/Gateway/GatewayIdentifyResume.cs b/DisCatSharp/Net/Abstractions/Gateway/GatewayIdentifyResume.cs index 5e546a3a90..b9e3f7ca35 100644 --- a/DisCatSharp/Net/Abstractions/Gateway/GatewayIdentifyResume.cs +++ b/DisCatSharp/Net/Abstractions/Gateway/GatewayIdentifyResume.cs @@ -26,7 +26,10 @@ internal sealed class GatewayIdentify /// [JsonProperty("properties")] public ClientProperties ClientProperties => - new() { Discord = this.Discord }; + new() + { + Discord = this.Discord + }; /// /// Gets or sets whether to encrypt websocket traffic. diff --git a/DisCatSharp/Net/Abstractions/Gateway/GatewayOpCode.cs b/DisCatSharp/Net/Abstractions/Gateway/GatewayOpCode.cs index 6aa29d4649..49255e91c2 100644 --- a/DisCatSharp/Net/Abstractions/Gateway/GatewayOpCode.cs +++ b/DisCatSharp/Net/Abstractions/Gateway/GatewayOpCode.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Net.Abstractions; /// diff --git a/DisCatSharp/Net/Abstractions/IOAuth2Payload.cs b/DisCatSharp/Net/Abstractions/IOAuth2Payload.cs index d9832b5776..0b33f7c586 100644 --- a/DisCatSharp/Net/Abstractions/IOAuth2Payload.cs +++ b/DisCatSharp/Net/Abstractions/IOAuth2Payload.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Net.Abstractions; /// diff --git a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs index 686ae06ec1..932651bef3 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestApplicationCommandPayloads.cs @@ -83,7 +83,6 @@ internal sealed class RestApplicationCommandCreatePayload : ObservableApiObject /// [JsonProperty("integration_types", NullValueHandling = NullValueHandling.Ignore)] public List? IntegrationTypes { get; set; } - } /// diff --git a/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs index d3fc8769bb..3cab60bbd0 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs @@ -311,7 +311,6 @@ internal sealed class RestChannelMessageCreatePayload : RestChannelMessageEditPa /// [JsonProperty("message_reference", NullValueHandling = NullValueHandling.Ignore)] public InternalDiscordMessageReference? MessageReference { get; set; } - } /// diff --git a/DisCatSharp/Net/Abstractions/Rest/RestGcpAttachmentsPayload.cs b/DisCatSharp/Net/Abstractions/Rest/RestGcpAttachmentsPayload.cs index 3b21ef810e..212a2c2e73 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestGcpAttachmentsPayload.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestGcpAttachmentsPayload.cs @@ -1,4 +1,3 @@ - using System.Collections.Generic; using DisCatSharp.Entities; diff --git a/DisCatSharp/Net/Abstractions/Rest/RestGuildPayloads.cs b/DisCatSharp/Net/Abstractions/Rest/RestGuildPayloads.cs index cfb8a288d1..5ed0f55116 100644 --- a/DisCatSharp/Net/Abstractions/Rest/RestGuildPayloads.cs +++ b/DisCatSharp/Net/Abstractions/Rest/RestGuildPayloads.cs @@ -144,7 +144,6 @@ internal sealed class RestGuildModifyPayload : ObservableApiObject [JsonProperty("home_header")] public Optional HomeHeaderBase64 { get; set; } - /// /// Gets or sets the discovery splash base64. /// diff --git a/DisCatSharp/Net/Abstractions/ShardInfo.cs b/DisCatSharp/Net/Abstractions/ShardInfo.cs index 8aa3b698ac..30c3e6e7c8 100644 --- a/DisCatSharp/Net/Abstractions/ShardInfo.cs +++ b/DisCatSharp/Net/Abstractions/ShardInfo.cs @@ -36,7 +36,10 @@ internal sealed class ShardInfoConverter : JsonConverter public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var sinfo = value as ShardInfo; - var obj = new object[] { sinfo.ShardId, sinfo.ShardCount }; + var obj = new object[] + { + sinfo.ShardId, sinfo.ShardCount + }; serializer.Serialize(writer, obj); } @@ -52,8 +55,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var arr = this.ReadArrayObject(reader, serializer); return new ShardInfo { - ShardId = (int)arr[0], - ShardCount = (int)arr[1], + ShardId = (int)arr[0], ShardCount = (int)arr[1] }; } diff --git a/DisCatSharp/Net/Abstractions/StatusUpdate.cs b/DisCatSharp/Net/Abstractions/StatusUpdate.cs index 0266a0728e..1e8cc70648 100644 --- a/DisCatSharp/Net/Abstractions/StatusUpdate.cs +++ b/DisCatSharp/Net/Abstractions/StatusUpdate.cs @@ -39,7 +39,7 @@ internal sealed class StatusUpdate : ObservableApiObject UserStatus.DoNotDisturb => "dnd", UserStatus.Invisible or UserStatus.Offline => "invisible", UserStatus.Streaming => "streaming", - _ => "online", + _ => "online" }; /// diff --git a/DisCatSharp/Net/Abstractions/Transport/TransportActivity.cs b/DisCatSharp/Net/Abstractions/Transport/TransportActivity.cs index 4225718fd4..96b4fe0f06 100644 --- a/DisCatSharp/Net/Abstractions/Transport/TransportActivity.cs +++ b/DisCatSharp/Net/Abstractions/Transport/TransportActivity.cs @@ -314,7 +314,10 @@ internal sealed class GamePartySizeConverter : JsonConverter public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var obj = value is TransportActivity.GameParty.GamePartySize sinfo - ? new object[] { sinfo.Current, sinfo.Maximum } + ? new object[] + { + sinfo.Current, sinfo.Maximum + } : null; serializer.Serialize(writer, obj); } @@ -331,8 +334,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var arr = this.ReadArrayObject(reader, serializer); return new TransportActivity.GameParty.GamePartySize { - Current = (long)arr[0], - Maximum = (long)arr[1], + Current = (long)arr[0], Maximum = (long)arr[1] }; } diff --git a/DisCatSharp/Net/ConnectionEndpoint.cs b/DisCatSharp/Net/ConnectionEndpoint.cs index 9826315333..5723d6f8db 100644 --- a/DisCatSharp/Net/ConnectionEndpoint.cs +++ b/DisCatSharp/Net/ConnectionEndpoint.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Net; /// @@ -38,7 +37,7 @@ public ConnectionEndpoint(string hostname, int port, bool secured = false) /// Gets the hash code of this endpoint. /// /// Hash code of this endpoint. - public override readonly int GetHashCode() => 13 + (7 * this.Hostname.GetHashCode()) + (7 * this.Port); + public override readonly int GetHashCode() => 13 + 7 * this.Hostname.GetHashCode() + 7 * this.Port; /// /// Gets the string representation of this connection endpoint. diff --git a/DisCatSharp/Net/Models/ApplicationCommandEditModel.cs b/DisCatSharp/Net/Models/ApplicationCommandEditModel.cs index d1ef3d83a0..49b93b54aa 100644 --- a/DisCatSharp/Net/Models/ApplicationCommandEditModel.cs +++ b/DisCatSharp/Net/Models/ApplicationCommandEditModel.cs @@ -21,9 +21,11 @@ public Optional Name { if (value.Value.Length > 32) throw new ArgumentException("Application command name cannot exceed 32 characters.", nameof(value)); + this._name = value; } } + private Optional _name; /// @@ -36,9 +38,11 @@ public Optional Description { if (value.Value.Length > 100) throw new ArgumentException("Application command description cannot exceed 100 characters.", nameof(value)); + this._description = value; } } + private Optional _description; /// diff --git a/DisCatSharp/Net/Models/BaseEditModel.cs b/DisCatSharp/Net/Models/BaseEditModel.cs index f388d59e95..fe34be4d46 100644 --- a/DisCatSharp/Net/Models/BaseEditModel.cs +++ b/DisCatSharp/Net/Models/BaseEditModel.cs @@ -1,4 +1,3 @@ - namespace DisCatSharp.Net.Models; /// diff --git a/DisCatSharp/Net/Rest/BaseRestRequest.cs b/DisCatSharp/Net/Rest/BaseRestRequest.cs index 9356f83c61..3558c23564 100644 --- a/DisCatSharp/Net/Rest/BaseRestRequest.cs +++ b/DisCatSharp/Net/Rest/BaseRestRequest.cs @@ -138,5 +138,4 @@ protected internal void SetFaulted(Exception ex) /// The exception to set. protected internal bool TrySetFaulted(Exception ex) => this.RequestTaskSource.TrySetException(ex); - } diff --git a/DisCatSharp/Net/Rest/DiscordApiClient.cs b/DisCatSharp/Net/Rest/DiscordApiClient.cs index 6a4641d345..8f666649c3 100644 --- a/DisCatSharp/Net/Rest/DiscordApiClient.cs +++ b/DisCatSharp/Net/Rest/DiscordApiClient.cs @@ -131,15 +131,11 @@ private DiscordMessage PrepareMessage(JToken msgRaw) var channel = !ret.GuildId.HasValue ? new DiscordDmChannel { - Id = ret.ChannelId, - Discord = this.Discord, - Type = ChannelType.Private + Id = ret.ChannelId, Discord = this.Discord, Type = ChannelType.Private } : new DiscordChannel { - Id = ret.ChannelId, - GuildId = ret.GuildId, - Discord = this.Discord + Id = ret.ChannelId, GuildId = ret.GuildId, Discord = this.Discord }; ret.Channel = channel; @@ -158,26 +154,29 @@ private void PopulateMessage(TransportUser author, DiscordMessage ret) //If this is a webhook, it shouldn't be in the user cache. if (author.IsBot && int.Parse(author.Discriminator) == 0) - { - ret.Author = new(author) { Discord = this.Discord }; - } + ret.Author = new(author) + { + Discord = this.Discord + }; else { if (!this.Discord.UserCache.TryGetValue(author.Id, out var usr)) - { - this.Discord.UserCache[author.Id] = usr = new(author) { Discord = this.Discord }; - } + this.Discord.UserCache[author.Id] = usr = new(author) + { + Discord = this.Discord + }; if (guild != null) { if (!guild.Members.TryGetValue(author.Id, out var mbr)) - mbr = new(usr) { Discord = this.Discord, GuildId = guild.Id }; + mbr = new(usr) + { + Discord = this.Discord, GuildId = guild.Id + }; ret.Author = mbr; } else - { ret.Author = usr; - } } ret.PopulateMentions(); @@ -244,8 +243,19 @@ internal Task DoFormRequestAsync(DiscordOAuth2Client client, RateL /// 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) + 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); @@ -269,8 +279,17 @@ private Task DoStickerMultipartAsync(BaseDiscordClient client, Rat /// 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) + 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); @@ -284,7 +303,7 @@ private Task DoMultipartAsync(BaseDiscordClient client, RateLimitB // begin todo - #region Guild +#region Guild /// /// Gets the guild async. @@ -298,7 +317,10 @@ internal async Task GetGuildAsync(ulong guildId, bool? withCounts) urlParams["with_counts"] = withCounts?.ToString(); var route = $"{Endpoints.GUILDS}/:guild_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId }, out var path); + 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, urlParams).ConfigureAwait(false); @@ -330,11 +352,13 @@ internal async Task GetGuildAsync(ulong guildId, bool? withCounts) 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 bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId + }, out var path); var querydict = new Dictionary { - ["query"] = name, - ["limit"] = limit.ToString() + ["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); @@ -344,7 +368,10 @@ internal async Task> SearchMembersAsync(ulong guild var mbrs = new List(); foreach (var xtm in tms) { - var usr = new DiscordUser(xtm.User) { Discord = this.Discord }; + var usr = new DiscordUser(xtm.User) + { + Discord = this.Discord + }; this.Discord.UserCache.AddOrUpdate(xtm.User.Id, usr, (id, old) => { @@ -361,7 +388,10 @@ internal async Task> SearchMembersAsync(ulong guild return old; }); - mbrs.Add(new(xtm) { Discord = this.Discord, GuildId = guildId }); + mbrs.Add(new(xtm) + { + Discord = this.Discord, GuildId = guildId + }); } return mbrs; @@ -375,7 +405,10 @@ internal async Task> SearchMembersAsync(ulong guild 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 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); @@ -394,8 +427,14 @@ internal async Task GetGuildBanAsync(ulong guildId, ulong userId) /// 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) + internal async Task CreateGuildAsync( + string name, + string regionId, + Optional iconb64, + VerificationLevel? verificationLevel, + DefaultMessageNotifications? defaultMessageNotifications, + SystemChannelFlags? systemChannelFlags + ) { var pld = new RestGuildCreatePayload { @@ -408,7 +447,8 @@ internal async Task CreateGuildAsync(string name, string regionId, }; var route = $"{Endpoints.GUILDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + 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); @@ -432,12 +472,14 @@ internal async Task CreateGuildFromTemplateAsync(string templateCo { var pld = new RestGuildCreateFromTemplatePayload { - Name = name, - IconBase64 = iconb64 + 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 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); @@ -458,7 +500,10 @@ internal async Task CreateGuildFromTemplateAsync(string templateCo 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 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); @@ -495,13 +540,30 @@ internal async Task DeleteGuildAsync(ulong guildId) /// 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 homeHeaderb64, Optional preferredLocale, Optional premiumProgressBarEnabled, string? 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 homeHeaderb64, + Optional preferredLocale, + Optional premiumProgressBarEnabled, + string? reason + ) { var pld = new RestGuildModifyPayload { @@ -532,7 +594,10 @@ internal async Task ModifyGuildAsync(ulong guildId, Optional ModifyGuildAsync(ulong guildId, Optional /// Modifies the guild community settings. /// @@ -582,7 +645,10 @@ internal async Task ModifyGuildCommunitySettingsAsync(ulong guildI 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 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); @@ -616,12 +682,18 @@ internal async Task ModifyGuildInventorySettingsAsync(ulong guildI headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INVENTORY}{Endpoints.SETTINGS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { guild_id = guildId }, out var path); + 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, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); - this.Discord.Guilds[guildId].InventorySettings = new() { IsEmojiPackCollectible = isEmojiPackCollectible }; + this.Discord.Guilds[guildId].InventorySettings = new() + { + IsEmojiPackCollectible = isEmojiPackCollectible + }; return this.Discord.Guilds[guildId]; } @@ -635,12 +707,14 @@ internal async Task ModifyGuildIncidentActionsAsync(ulong guildId { var pld = new RestGuildIncidentActionsModifyPayload { - InvitesDisabledUntil = invitesDisabledUntil, - DmsDisabledUntil = dmsDisabledUntil, + InvitesDisabledUntil = invitesDisabledUntil, DmsDisabledUntil = dmsDisabledUntil }; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INCIDENT_ACTIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, 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.PUT, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -658,7 +732,10 @@ internal async Task ModifyGuildIncidentActionsAsync(ulong guildId internal async Task GetGuildOnboardingAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ONBOARDING}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId }, out var path); + 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); @@ -681,10 +758,7 @@ internal async Task ModifyGuildOnboardingAsync(ulong guildId, { var pld = new RestGuildOnboardingModifyPayload() { - Prompts = prompts, - DefaultChannelIds = defaultChannelIds, - Enabled = enabled, - Mode = mode + Prompts = prompts, DefaultChannelIds = defaultChannelIds, Enabled = enabled, Mode = mode }; var headers = Utilities.GetBaseHeaders(); @@ -692,7 +766,10 @@ internal async Task ModifyGuildOnboardingAsync(ulong guildId, headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ONBOARDING}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, 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.PUT, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -709,7 +786,10 @@ internal async Task ModifyGuildOnboardingAsync(ulong guildId, internal async Task GetGuildServerGuideAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.NEW_MEMBER_WELCOME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId }, out var path); + 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); @@ -732,10 +812,7 @@ internal async Task ModifyGuildServerGuideAsync(ulong guildI { var pld = new RestGuildServerGuideModifyPayload() { - Enabled = enabled, - WelcomeMessage = welcomeMessage, - NewMemberActions = newMemberActions, - ResourceChannels = resourceChannels + Enabled = enabled, WelcomeMessage = welcomeMessage, NewMemberActions = newMemberActions, ResourceChannels = resourceChannels }; var headers = Utilities.GetBaseHeaders(); @@ -743,7 +820,10 @@ internal async Task ModifyGuildServerGuideAsync(ulong guildI headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.NEW_MEMBER_WELCOME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, 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.PUT, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -764,8 +844,7 @@ internal async Task ModifyGuildSafetyAlertsSettingsAsync(ulong gui { var pld = new RestGuildSafetyModifyPayload { - SafetyAlertsChannelId = safetyAlertsChannelId, - Features = features + SafetyAlertsChannelId = safetyAlertsChannelId, Features = features }; var headers = Utilities.GetBaseHeaders(); @@ -773,7 +852,10 @@ internal async Task ModifyGuildSafetyAlertsSettingsAsync(ulong gui 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 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); @@ -808,7 +890,10 @@ internal async Task ModifyGuildFeaturesAsync(ulong guildId, List> 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 bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId + }, out var path); var urlParams = new Dictionary(); if (limit != null) @@ -893,7 +987,10 @@ internal async Task> GetGuildBansAsync(ulong guildId, { if (!this.Discord.TryGetCachedUserInternal(xb.RawUser.Id, out var usr)) { - usr = new(xb.RawUser) { Discord = this.Discord }; + usr = new(xb.RawUser) + { + Discord = this.Discord + }; usr = this.Discord.UserCache.AddOrUpdate(usr.Id, usr, (id, old) => { old.Username = usr.Username; @@ -934,7 +1031,10 @@ internal Task CreateGuildBanAsync(ulong guildId, ulong userId, int deleteMessage 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 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); @@ -953,7 +1053,10 @@ internal Task RemoveGuildBanAsync(ulong guildId, ulong userId, string? 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 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); @@ -966,7 +1069,10 @@ internal Task RemoveGuildBanAsync(ulong guildId, ulong userId, string? reason) 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 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); @@ -994,7 +1100,10 @@ internal async Task AddGuildMemberAsync(ulong guildId, ulong user }; 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 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); @@ -1020,7 +1129,10 @@ internal async Task> ListGuildMembersAsync(ulong 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 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); @@ -1036,7 +1148,6 @@ internal async Task> ListGuildMembersAsync(ulong /// The user_id. /// The role_id. /// The reason. - internal Task AddGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1044,7 +1155,10 @@ internal Task AddGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, 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 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); @@ -1057,7 +1171,6 @@ internal Task AddGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, /// The user_id. /// The role_id. /// The reason. - internal Task RemoveGuildMemberRoleAsync(ulong guildId, ulong userId, ulong roleId, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1065,7 +1178,10 @@ internal Task RemoveGuildMemberRoleAsync(ulong guildId, ulong userId, ulong role 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 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); @@ -1077,7 +1193,6 @@ internal Task RemoveGuildMemberRoleAsync(ulong guildId, ulong userId, ulong role /// The guild_id. /// The pld. /// The reason. - internal Task ModifyGuildChannelPositionAsync(ulong guildId, IEnumerable pld, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1085,7 +1200,10 @@ internal Task ModifyGuildChannelPositionAsync(ulong guildId, IEnumerableThe guild_id. /// The pld. /// The reason. - internal Task ModifyGuildChannelParentAsync(ulong guildId, IEnumerable pld, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1105,7 +1222,10 @@ internal Task ModifyGuildChannelParentAsync(ulong guildId, IEnumerableThe guild_id. /// The pld. /// The reason. - internal Task DetachGuildChannelParentAsync(ulong guildId, IEnumerable pld, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1125,7 +1244,10 @@ internal Task DetachGuildChannelParentAsync(ulong guildId, IEnumerableThe guild_id. /// The pld. /// The reason. - internal Task ModifyGuildRolePositionAsync(ulong guildId, IEnumerable pld, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -1145,7 +1266,10 @@ internal Task ModifyGuildRolePositionAsync(ulong guildId, IEnumerable /// Gets the audit logs async. /// - /// The guild_id. + /// 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) + /// The responsible user. + /// The action type. + internal async Task GetAuditLogsAsync(ulong guildId, int limit, ulong? after, ulong? before, ulong? responsible, int? actionType) { var urlParams = new Dictionary { @@ -1177,25 +1300,41 @@ internal async Task GetAuditLogsAsync(ulong guildId, int limit, ulong? 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 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 = DiscordJson.DeserializeObject(res.Response, this.Discord); + var auditLogData = DiscordJson.DeserializeObject(res.Response, this.Discord); + auditLogData.GuildId = guildId; + auditLogData.Entries.ForEach(x => + { + x.GuildId = auditLogData.GuildId; + x.Discord = (DiscordClient)this.Discord; + if (x.Options is null) + return; + + x.Options.Discord = this.Discord; + x.Options.GuildId = auditLogData.GuildId; + }); - return auditLogDataRaw; + return auditLogData; } /// /// 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 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); @@ -1209,11 +1348,13 @@ internal async Task GetGuildVanityUrlAsync(ulong guildId) /// 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 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); @@ -1228,9 +1369,7 @@ internal async Task GetGuildWidgetAsync(ulong guildId) ret.Channels = ret.Guild == null ? rawChannels.Select(r => new DiscordChannel { - Id = (ulong)r["id"], - Name = r["name"].ToString(), - Position = (int)r["position"] + Id = (ulong)r["id"], Name = r["name"].ToString(), Position = (int)r["position"] }).ToList() : rawChannels.Select(r => { @@ -1246,11 +1385,13 @@ internal async Task GetGuildWidgetAsync(ulong guildId) /// 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 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); @@ -1268,13 +1409,11 @@ internal async Task GetGuildWidgetSettingsAsync(ulong gui /// 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 + Enabled = isEnabled, ChannelId = channelId }; var headers = Utilities.GetBaseHeaders(); @@ -1282,7 +1421,10 @@ internal async Task ModifyGuildWidgetSettingsAsync(ulong 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 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); @@ -1297,11 +1439,13 @@ internal async Task ModifyGuildWidgetSettingsAsync(ulong /// 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 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); @@ -1317,17 +1461,18 @@ internal async Task> GetGuildTemplatesAsync( /// 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 + 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 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); @@ -1342,11 +1487,13 @@ internal async Task CreateGuildTemplateAsync(ulong guildId /// /// 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 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); @@ -1363,17 +1510,18 @@ internal async Task SyncGuildTemplateAsync(ulong guildId, /// 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 + 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 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); @@ -1388,11 +1536,13 @@ internal async Task ModifyGuildTemplateAsync(ulong guildId /// /// 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 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); @@ -1406,11 +1556,13 @@ internal async Task DeleteGuildTemplateAsync(ulong guildId /// 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 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); @@ -1427,18 +1579,18 @@ internal async Task GetGuildMembershipScreening /// 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 + 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 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); @@ -1452,11 +1604,13 @@ internal async Task ModifyGuildMembershipScreen /// 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 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); @@ -1472,18 +1626,18 @@ internal async Task GetGuildWelcomeScreenAsync(ulong /// 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 + 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 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); @@ -1499,18 +1653,18 @@ internal async Task ModifyGuildWelcomeScreenAsync(ulo /// 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 + 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 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)).ConfigureAwait(false); @@ -1523,17 +1677,18 @@ internal async Task UpdateCurrentUserVoiceStateAsync(ulong guildId, ulong channe /// 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 + 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 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)).ConfigureAwait(false); @@ -1547,7 +1702,10 @@ internal async Task UpdateUserVoiceStateAsync(ulong guildId, ulong userId, ulong 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 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); @@ -1567,7 +1725,10 @@ internal async Task> GetAutomodRulesAsync(ulong 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 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).ConfigureAwait(false); @@ -1591,11 +1752,24 @@ internal async Task GetAutomodRuleAsync(ulong guildId, ulong ruleId /// 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) + 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); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + guild_id = guildId + }, out var path); RestAutomodRuleModifyPayload pld = new() { @@ -1617,15 +1791,13 @@ internal async Task CreateAutomodRuleAsync(ulong guildId, string na 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 res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); var ret = DiscordJson.DeserializeObject(res.Response, this.Discord); ret.Discord = this.Discord; if (this.Discord is DiscordClient dc) - { await dc.OnAutomodRuleCreated(ret).ConfigureAwait(false); - } return ret; } @@ -1644,15 +1816,22 @@ internal async Task CreateAutomodRuleAsync(ulong guildId, string na /// 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) + 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 + Name = name, EventType = eventType, TriggerMetadata = metadata, Enabled = enabled }; if (actions.HasValue) @@ -1667,18 +1846,19 @@ internal async Task ModifyAutomodRuleAsync(ulong guildId, ulong rul 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 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)).ConfigureAwait(false); + var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); var ret = DiscordJson.DeserializeObject(res.Response, this.Discord); ret.Discord = this.Discord; if (this.Discord is DiscordClient dc) - { await dc.OnAutomodRuleUpdated(ret).ConfigureAwait(false); - } return ret; } @@ -1693,7 +1873,10 @@ internal async Task ModifyAutomodRuleAsync(ulong guildId, ulong rul 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 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)) @@ -1706,18 +1889,16 @@ internal async Task DeleteAutomodRuleAsync(ulong guildId, ulong rul ret.Discord = this.Discord; if (this.Discord is DiscordClient dc) - { await dc.OnAutomodRuleDeleted(ret).ConfigureAwait(false); - } return ret; } - #endregion +#endregion // End todo - #region Guild Scheduled Events +#region Guild Scheduled Events /// /// Creates a scheduled event. @@ -1741,7 +1922,10 @@ internal async Task CreateGuildScheduledEventAsync(ulong 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 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); @@ -1763,7 +1947,20 @@ internal async Task CreateGuildScheduledEventAsync(ulong /// /// 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) + 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 { @@ -1783,7 +1980,10 @@ internal async Task ModifyGuildScheduledEventAsync(ulong 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 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)).ConfigureAwait(false); @@ -1828,7 +2028,10 @@ internal async Task ModifyGuildScheduledEventStatusAsync( 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 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)).ConfigureAwait(false); @@ -1871,7 +2074,10 @@ internal async Task GetGuildScheduledEventAsync(ulong gui 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 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); @@ -1911,7 +2117,10 @@ internal async Task> ListGuild 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 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); @@ -1955,7 +2164,10 @@ internal Task DeleteGuildScheduledEventAsync(ulong guildId, ulong scheduledEvent 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 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); @@ -1985,7 +2197,10 @@ internal async Task> GetGu 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 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); @@ -1995,7 +2210,6 @@ internal async Task> GetGu foreach (var rspvUser in rspvUsers) { - rspvUser.Discord = this.Discord; rspvUser.GuildId = guildId; @@ -2020,11 +2234,13 @@ internal async Task> GetGu return new ReadOnlyDictionary(new Dictionary(rspv)); } - #endregion + +#endregion // begin todo - #region Channel +#region Channel + /// /// Creates a guild channel. /// @@ -2071,7 +2287,10 @@ internal async Task CreateGuildChannelAsync(ulong guildId, strin 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 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); @@ -2098,14 +2317,25 @@ internal async Task CreateGuildChannelAsync(ulong guildId, strin /// The default auto archive duration. /// The reason. [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] - internal async Task CreateForumChannelAsync(ulong guildId, string name, ulong? parent, - Optional topic, Optional template, - bool? nsfw, Optional defaultReactionEmoji, + internal async Task CreateForumChannelAsync( + ulong guildId, + string name, + ulong? parent, + Optional topic, + Optional template, + bool? nsfw, + Optional defaultReactionEmoji, #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) - Optional perUserRateLimit, Optional postCreateUserRateLimit, Optional defaultSortOrder, + Optional perUserRateLimit, + Optional postCreateUserRateLimit, + Optional defaultSortOrder, #pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) - ThreadAutoArchiveDuration? defaultAutoArchiveDuration, IEnumerable permissionOverwrites, Optional flags, string reason) + ThreadAutoArchiveDuration? defaultAutoArchiveDuration, + IEnumerable permissionOverwrites, + Optional flags, + string reason + ) #pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) { List restoverwrites = null; @@ -2138,7 +2368,10 @@ internal async Task CreateForumChannelAsync(ulong guildId, strin 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 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); @@ -2168,7 +2401,24 @@ internal async Task CreateForumChannelAsync(ulong guildId, strin /// The permission overwrites. /// The reason. #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) - internal Task ModifyChannelAsync(ulong channelId, string name, int? position, Optional topic, bool? nsfw, Optional parent, Optional bitrate, Optional userLimit, Optional perUserRateLimit, Optional rtcRegion, VideoQualityMode? qualityMode, ThreadAutoArchiveDuration? autoArchiveDuration, Optional type, IEnumerable permissionOverwrites, Optional flags, string reason) + internal Task ModifyChannelAsync( + ulong channelId, + string name, + int? position, + Optional topic, + bool? nsfw, + Optional parent, + Optional bitrate, + Optional userLimit, + Optional perUserRateLimit, + Optional rtcRegion, + VideoQualityMode? qualityMode, + ThreadAutoArchiveDuration? autoArchiveDuration, + Optional type, + IEnumerable permissionOverwrites, + Optional flags, + string reason + ) #pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) { List restoverwrites = null; @@ -2202,18 +2452,34 @@ internal Task ModifyChannelAsync(ulong channelId, string name, int? position, Op 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 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)); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] - 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) + 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) @@ -2246,7 +2512,10 @@ internal async Task ModifyForumChannelAsync(ulong channelId, str 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 bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); @@ -2261,11 +2530,13 @@ internal async Task ModifyForumChannelAsync(ulong channelId, str /// 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 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); @@ -2281,7 +2552,6 @@ internal async Task GetChannelAsync(ulong channelId) /// /// The channel_id. /// The reason. - internal Task DeleteChannelAsync(ulong channelId, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -2289,7 +2559,10 @@ internal Task DeleteChannelAsync(ulong channelId, string 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 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); @@ -2300,11 +2573,13 @@ internal Task DeleteChannelAsync(ulong channelId, string reason) /// /// 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 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); @@ -2347,7 +2622,12 @@ internal async Task CreateMessageAsync(ulong channelId, string c { HasContent = content != null, Content = content, - StickersIds = sticker is null ? Array.Empty() : new[] {sticker.Id}, + StickersIds = sticker is null + ? Array.Empty() + : new[] + { + sticker.Id + }, IsTts = false, HasEmbed = embeds?.Any() ?? false, Embeds = embeds, @@ -2355,13 +2635,19 @@ internal async Task CreateMessageAsync(ulong channelId, string c }; if (replyMessageId != null) - pld.MessageReference = new InternalDiscordMessageReference { MessageId = replyMessageId, FailIfNotExists = failOnInvalidReply }; + pld.MessageReference = new InternalDiscordMessageReference + { + MessageId = replyMessageId, FailIfNotExists = failOnInvalidReply + }; if (replyMessageId != null) pld.Mentions = new(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 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); @@ -2376,7 +2662,6 @@ internal async Task CreateMessageAsync(ulong channelId, string c /// /// The channel_id. /// The builder. - internal async Task CreateMessageAsync(ulong channelId, DiscordMessageBuilder builder) { builder.Validate(); @@ -2390,7 +2675,12 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM { HasContent = builder.Content != null, Content = builder.Content, - StickersIds = builder.Sticker is null ? Array.Empty() : new[] {builder.Sticker.Id}, + StickersIds = builder.Sticker is null + ? Array.Empty() + : new[] + { + builder.Sticker.Id + }, IsTts = builder.IsTts, HasEmbed = builder.Embeds != null, Embeds = builder.Embeds, @@ -2398,7 +2688,10 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM }; if (builder.ReplyId != null) - pld.MessageReference = new InternalDiscordMessageReference { MessageId = builder.ReplyId, FailIfNotExists = builder.FailOnInvalidReply }; + pld.MessageReference = new InternalDiscordMessageReference + { + MessageId = builder.ReplyId, FailIfNotExists = builder.FailOnInvalidReply + }; pld.Mentions = new(builder.Mentions ?? Mentions.All, builder.Mentions?.Any() ?? false, builder.MentionOnReply); @@ -2414,11 +2707,15 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM attachments.Add(att); fileId++; } + pld.Attachments = attachments; } var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + 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); @@ -2434,14 +2731,12 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM { DiscordAttachment att = new() { - Id = fileId, - Discord = this.Discord, - Description = file.Description, - Filename = file.Filename + Id = fileId, Discord = this.Discord, Description = file.Description, Filename = file.Filename }; attachments.Add(att); fileId++; } + pld.Attachments = attachments; var values = new Dictionary @@ -2450,7 +2745,10 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + 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); @@ -2458,9 +2756,7 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM 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; } @@ -2470,16 +2766,22 @@ internal async Task CreateMessageAsync(ulong channelId, DiscordM /// 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 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; }); + var channelsRaw = JsonConvert.DeserializeObject>(res.Response).Select(xc => + { + xc.Discord = this.Discord; + return xc; + }); foreach (var ret in channelsRaw) ret.Initialize(this.Discord); @@ -2500,7 +2802,10 @@ internal Task ModifyVoiceChannelStatusAsync(ulong channelId, string? status) }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.VOICE_STATUS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, payload: DiscordJson.SerializeObject(pld)); @@ -2518,14 +2823,12 @@ internal async Task CreateStageInstanceAsync(ulong channel { var pld = new RestStageInstanceCreatePayload { - ChannelId = channelId, - Topic = topic, - ScheduledEventId = scheduledEventId, - SendStartNotification = sendStartNotification + ChannelId = channelId, Topic = topic, ScheduledEventId = scheduledEventId, SendStartNotification = sendStartNotification }; var route = $"{Endpoints.STAGE_INSTANCES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + 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); @@ -2545,7 +2848,10 @@ internal async Task CreateStageInstanceAsync(ulong channel 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 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); @@ -2569,7 +2875,10 @@ internal Task ModifyStageInstanceAsync(ulong channelId, Optional topic, }; var route = $"{Endpoints.STAGE_INSTANCES}/:channel_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {channel_id = channelId }, out var path); + 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); @@ -2586,7 +2895,10 @@ internal Task ModifyStageInstanceAsync(ulong channelId, Optional topic, 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 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); @@ -2603,7 +2915,6 @@ internal Task DeleteStageInstanceAsync(ulong channelId, string reason) /// The before. /// The after. /// The around. - internal async Task> GetChannelMessagesAsync(ulong channelId, int limit, ulong? before, ulong? after, ulong? around) { var urlParams = new Dictionary(); @@ -2617,7 +2928,10 @@ internal async Task> GetChannelMessagesAsync(ulong 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 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); @@ -2635,11 +2949,13 @@ internal async Task> GetChannelMessagesAsync(ulong /// /// 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 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); @@ -2661,7 +2977,6 @@ internal async Task GetChannelMessageAsync(ulong channelId, ulon /// 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 files, Optional> attachments) { if (embeds.HasValue && embeds.Value != null) @@ -2678,8 +2993,8 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess Components = components, Flags = suppressEmbed.HasValue && (bool)suppressEmbed ? MessageFlags.SuppressedEmbeds : null, Mentions = mentions - .Map(m => new DiscordMentions(m ?? Mentions.None, false, mentions.Value?.OfType().Any() ?? false)) - .ValueOrDefault() + .Map(m => new DiscordMentions(m ?? Mentions.None, false, mentions.Value?.OfType().Any() ?? false)) + .ValueOrDefault() }; if (files?.Count > 0) @@ -2690,14 +3005,12 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess { DiscordAttachment att = new() { - Id = fileId, - Discord = this.Discord, - Description = file.Description, - Filename = file.Filename + Id = fileId, Discord = this.Discord, Description = file.Description, Filename = file.Filename }; attachmentsNew.Add(att); fileId++; } + if (attachments.HasValue && attachments.Value.Any()) attachmentsNew.AddRange(attachments.Value); @@ -2709,7 +3022,10 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoMultipartAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, values: values, files: files).ConfigureAwait(false); @@ -2717,9 +3033,7 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess var ret = this.PrepareMessage(JObject.Parse(res.Response)); foreach (var file in files.Where(x => x.ResetPositionTo.HasValue)) - { file.Stream.Position = file.ResetPositionTo.Value; - } return ret; } @@ -2728,7 +3042,10 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess pld.Attachments = attachments.ValueOrDefault(); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, 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.PATCH, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -2745,7 +3062,6 @@ internal async Task EditMessageAsync(ulong channelId, ulong mess /// The channel_id. /// The message_id. /// The reason. - internal Task DeleteMessageAsync(ulong channelId, ulong messageId, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -2753,7 +3069,10 @@ internal Task DeleteMessageAsync(ulong channelId, ulong messageId, string reason headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers); @@ -2765,7 +3084,6 @@ internal Task DeleteMessageAsync(ulong channelId, ulong messageId, string reason /// The channel_id. /// The message_ids. /// The reason. - internal Task DeleteMessagesAsync(ulong channelId, IEnumerable messageIds, string reason) { var pld = new RestChannelMessageBulkDeletePayload @@ -2778,7 +3096,10 @@ internal Task DeleteMessagesAsync(ulong channelId, IEnumerable messageIds headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}{Endpoints.BULK_DELETE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers, DiscordJson.SerializeObject(pld)); @@ -2788,16 +3109,22 @@ internal Task DeleteMessagesAsync(ulong channelId, IEnumerable messageIds /// Gets the channel invites async. /// /// The channel_id. - internal async Task> GetChannelInvitesAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.INVITES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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 invitesRaw = JsonConvert.DeserializeObject>(res.Response).Select(xi => { xi.Discord = this.Discord; return xi; }); + var invitesRaw = JsonConvert.DeserializeObject>(res.Response).Select(xi => + { + xi.Discord = this.Discord; + return xi; + }); return new ReadOnlyCollection(new List(invitesRaw)); } @@ -2814,7 +3141,6 @@ internal async Task> GetChannelInvitesAsync(ulong c /// If true, temporary. /// If true, unique. /// The reason. - internal async Task CreateChannelInviteAsync(ulong channelId, int maxAge, int maxUses, TargetType? targetType, ulong? targetApplicationId, ulong? targetUser, bool temporary, bool unique, string reason) { var pld = new RestChannelInviteCreatePayload @@ -2833,7 +3159,10 @@ internal async Task CreateChannelInviteAsync(ulong channelId, int headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.INVITES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + 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, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -2850,7 +3179,6 @@ internal async Task CreateChannelInviteAsync(ulong channelId, int /// The channel_id. /// The overwrite_id. /// The reason. - internal Task DeleteChannelPermissionAsync(ulong channelId, ulong overwriteId, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -2858,7 +3186,10 @@ internal Task DeleteChannelPermissionAsync(ulong channelId, ulong overwriteId, s headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.PERMISSIONS}/:overwrite_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, overwrite_id = overwriteId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, overwrite_id = overwriteId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers); @@ -2873,14 +3204,11 @@ internal Task DeleteChannelPermissionAsync(ulong channelId, ulong overwriteId, s /// The deny. /// The type. /// The reason. - internal Task EditChannelPermissionsAsync(ulong channelId, ulong overwriteId, Permissions allow, Permissions deny, string type, string reason) { var pld = new RestChannelPermissionEditPayload { - Type = type, - Allow = allow & PermissionMethods.FullPerms, - Deny = deny & PermissionMethods.FullPerms + Type = type, Allow = allow & PermissionMethods.FullPerms, Deny = deny & PermissionMethods.FullPerms }; var headers = Utilities.GetBaseHeaders(); @@ -2888,7 +3216,10 @@ internal Task EditChannelPermissionsAsync(ulong channelId, ulong overwriteId, Pe headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.PERMISSIONS}/:overwrite_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId, overwrite_id = overwriteId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId, overwrite_id = overwriteId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, headers, DiscordJson.SerializeObject(pld)); @@ -2898,11 +3229,13 @@ internal Task EditChannelPermissionsAsync(ulong channelId, ulong overwriteId, Pe /// Triggers the typing async. /// /// The channel_id. - internal Task TriggerTypingAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.TYPING}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route); @@ -2912,11 +3245,13 @@ internal Task TriggerTypingAsync(ulong channelId) /// Gets the pinned messages async. /// /// The channel_id. - internal async Task> GetPinnedMessagesAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.PINS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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); @@ -2934,11 +3269,13 @@ internal async Task> GetPinnedMessagesAsync(ulong /// /// The channel_id. /// The message_id. - internal Task PinMessageAsync(ulong channelId, ulong messageId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.PINS}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route); @@ -2949,11 +3286,13 @@ internal Task PinMessageAsync(ulong channelId, ulong messageId) /// /// The channel_id. /// The message_id. - internal Task UnpinMessageAsync(ulong channelId, ulong messageId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.PINS}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route); @@ -2966,17 +3305,18 @@ internal Task UnpinMessageAsync(ulong channelId, ulong messageId) /// The user_id. /// The access_token. /// The nickname. - internal Task AddGroupDmRecipientAsync(ulong channelId, ulong userId, string accessToken, string nickname) { var pld = new RestChannelGroupDmRecipientAddPayload { - AccessToken = accessToken, - Nickname = nickname + AccessToken = accessToken, Nickname = nickname }; var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.CHANNELS}/:channel_id{Endpoints.RECIPIENTS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId, user_id = userId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, payload: DiscordJson.SerializeObject(pld)); @@ -2987,11 +3327,13 @@ internal Task AddGroupDmRecipientAsync(ulong channelId, ulong userId, string acc /// /// The channel_id. /// The user_id. - internal Task RemoveGroupDmRecipientAsync(ulong channelId, ulong userId) { var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.CHANNELS}/:channel_id{Endpoints.RECIPIENTS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, user_id = userId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route); @@ -3002,17 +3344,16 @@ internal Task RemoveGroupDmRecipientAsync(ulong channelId, ulong userId) /// /// The access_tokens. /// The nicks. - internal async Task CreateGroupDmAsync(IEnumerable accessTokens, IDictionary nicks) { var pld = new RestUserGroupDmCreatePayload { - AccessTokens = accessTokens, - Nicknames = nicks + AccessTokens = accessTokens, Nicknames = nicks }; var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.CHANNELS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + 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); @@ -3026,7 +3367,6 @@ internal async Task CreateGroupDmAsync(IEnumerable acc /// Creates the dm async. /// /// The recipient_id. - internal async Task CreateDmAsync(ulong recipientId) { var pld = new RestUserDmCreatePayload @@ -3035,7 +3375,8 @@ internal async Task CreateDmAsync(ulong recipientId) }; var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.CHANNELS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + 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); @@ -3050,7 +3391,6 @@ internal async Task CreateDmAsync(ulong recipientId) /// /// The channel_id. /// The webhook_channel_id. - internal async Task FollowChannelAsync(ulong channelId, ulong webhookChannelId) { var pld = new FollowedChannelAddPayload @@ -3059,7 +3399,10 @@ internal async Task FollowChannelAsync(ulong channelId, }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.FOLLOWERS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var response = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -3072,22 +3415,25 @@ internal async Task FollowChannelAsync(ulong channelId, /// /// The channel_id. /// The message_id. - internal async Task CrosspostMessageAsync(ulong channelId, ulong messageId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.CROSSPOST}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var response = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route).ConfigureAwait(false); return DiscordJson.DeserializeObject(response.Response, this.Discord); } - #endregion +#endregion // End todo - #region Member +#region Member + /// /// Gets the current user async. /// @@ -3108,7 +3454,10 @@ internal Task GetUserAsync(ulong userId) internal async Task GetUserAsync(string userId) { var route = $"{Endpoints.USERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + user_id = userId + }, 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); @@ -3121,7 +3470,10 @@ internal async Task GetUserAsync(string userId) RawActivity = new(), Activity = new(), Status = UserStatus.Offline, - InternalUser = new() { Id = duser.Id } + InternalUser = new() + { + Id = duser.Id + } }; return duser; } @@ -3134,14 +3486,20 @@ internal async Task GetUserAsync(string userId) internal async Task GetGuildMemberAsync(ulong guildId, ulong userId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId, user_id = userId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); var tm = DiscordJson.DeserializeObject(res.Response, this.Discord); - var usr = new DiscordUser(tm.User) { Discord = this.Discord }; + var usr = new DiscordUser(tm.User) + { + Discord = this.Discord + }; usr = this.Discord.UserCache.AddOrUpdate(tm.User.Id, usr, (id, old) => { old.Username = usr.Username; @@ -3154,16 +3512,12 @@ internal async Task GetGuildMemberAsync(ulong guildId, ulong user if (this.Discord.Configuration.Intents.HasIntent(DiscordIntents.GuildPresences) && usr.Presence == null && this.Discord is DiscordClient dc) dc.PresencesInternal[usr.Id] = new() { - Discord = dc, - RawActivity = new(), - Activity = new(), - Status = UserStatus.Offline + Discord = dc, RawActivity = new(), Activity = new(), Status = UserStatus.Offline }; return new(tm) { - Discord = this.Discord, - GuildId = guildId + Discord = this.Discord, GuildId = guildId }; } @@ -3173,7 +3527,6 @@ internal async Task GetGuildMemberAsync(ulong guildId, ulong user /// The guild_id. /// The user_id. /// The reason. - internal Task RemoveGuildMemberAsync(ulong guildId, ulong userId, string reason) { var urlParams = new Dictionary(); @@ -3181,7 +3534,10 @@ internal Task RemoveGuildMemberAsync(ulong guildId, ulong userId, string reason) urlParams["reason"] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, 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.DELETE, route); @@ -3192,18 +3548,16 @@ internal Task RemoveGuildMemberAsync(ulong guildId, ulong userId, string reason) /// /// The username. /// The base64_avatar. - internal async Task ModifyCurrentUserAsync(string username, Optional base64Avatar) { var pld = new RestUserUpdateCurrentPayload { - Username = username, - AvatarBase64 = base64Avatar.ValueOrDefault(), - AvatarSet = base64Avatar.HasValue + Username = username, AvatarBase64 = base64Avatar.ValueOrDefault(), AvatarSet = base64Avatar.HasValue }; var route = $"{Endpoints.USERS}{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { }, 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); @@ -3218,12 +3572,12 @@ internal async Task ModifyCurrentUserAsync(string username, Optiona /// The limit. /// The before. /// The after. - internal async Task> GetCurrentUserGuildsAsync(int limit = 100, ulong? before = null, ulong? after = null) { var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.GUILDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, out var path); var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration) .AddParameter($"limit", limit.ToString(CultureInfo.InvariantCulture)); @@ -3242,9 +3596,7 @@ internal async Task> GetCurrentUserGuildsAsync(int l return new ReadOnlyCollection(new List(glds)); } else - { return DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); - } } /// @@ -3260,9 +3612,18 @@ internal async Task> GetCurrentUserGuildsAsync(int l /// Whether to verify the member. /// The member flags /// The reason. - internal Task ModifyGuildMemberAsync(ulong guildId, ulong userId, Optional nick, - Optional> roleIds, Optional mute, Optional deaf, - Optional voiceChannelId, Optional verify, MemberFlags flags, string reason) + internal Task ModifyGuildMemberAsync( + ulong guildId, + ulong userId, + Optional nick, + Optional> roleIds, + Optional mute, + Optional deaf, + Optional voiceChannelId, + Optional verify, + MemberFlags flags, + string reason + ) { var headers = Utilities.GetBaseHeaders(); if (!string.IsNullOrWhiteSpace(reason)) @@ -3276,17 +3637,20 @@ internal Task ModifyGuildMemberAsync(ulong guildId, ulong userId, Optional @@ -3308,10 +3672,13 @@ internal Task ModifyTimeoutAsync(ulong guildId, ulong userId, DateTimeOffset? un }; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, user_id = userId }, out var path); + 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); - return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, payload: DiscordJson.SerializeObject(pld)); + return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)); } /// @@ -3332,28 +3699,39 @@ internal Task ModifyCurrentMemberNicknameAsync(ulong guildId, string nick, strin }; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBERS}{Endpoints.ME}{Endpoints.NICK}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId }, out var path); + 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, payload: DiscordJson.SerializeObject(pld)); + return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PATCH, route, headers, DiscordJson.SerializeObject(pld)); } - #endregion - #region Roles +#endregion + +#region Roles + /// /// Gets the guild roles async. /// /// The guild_id. - internal async Task> GetGuildRolesAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ROLES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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 roles = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xr => { xr.GuildId = guildId; return xr; }).ToList(); + var roles = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xr => + { + xr.GuildId = guildId; + return xr; + }).ToList(); return roles; } @@ -3379,14 +3757,15 @@ internal async Task ModifyGuildRoleAsync(ulong guildId, ulong roleI Permissions = permissions & PermissionMethods.FullPerms, Color = color, Hoist = hoist, - Mentionable = mentionable, + Mentionable = mentionable }; if (emoji.HasValue && iconb64.HasValue) { pld.IconBase64 = null; pld.UnicodeEmoji = emoji; - } else if (emoji.HasValue && !iconb64.HasValue) + } + else if (emoji.HasValue && !iconb64.HasValue) pld.UnicodeEmoji = emoji; else if (iconb64.HasValue && !emoji.HasValue) pld.IconBase64 = iconb64; @@ -3396,7 +3775,10 @@ internal async Task ModifyGuildRoleAsync(ulong guildId, ulong roleI headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ROLES}/:role_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, role_id = roleId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + guild_id = guildId, role_id = roleId + }, 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); @@ -3420,7 +3802,10 @@ internal Task DeleteRoleAsync(ulong guildId, ulong roleId, string reason) headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ROLES}/:role_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, role_id = roleId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + guild_id = guildId, 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); @@ -3452,7 +3837,10 @@ internal async Task CreateGuildRoleAsync(ulong guildId, string name headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.ROLES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path); + 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); @@ -3462,16 +3850,17 @@ internal async Task CreateGuildRoleAsync(ulong guildId, string name return ret; } - #endregion - #region Prune +#endregion + +#region Prune + /// /// Gets the guild prune count async. /// /// The guild_id. /// The days. /// The include_roles. - internal async Task GetGuildPruneCountAsync(ulong guildId, int days, IEnumerable includeRoles) { if (days < 0 || days > 30) @@ -3483,11 +3872,14 @@ internal async Task GetGuildPruneCountAsync(ulong guildId, int days, IEnume }; var sb = includeRoles?.Aggregate(new StringBuilder(), - (sb, id) => sb.Append($"&include_roles={id}")) - ?? new StringBuilder(); + (sb, id) => sb.Append($"&include_roles={id}")) + ?? new StringBuilder(); var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.PRUNE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId + }, out var path); var url = Utilities.GetApiUriFor(path, $"{BuildQueryString(urlParams)}{sb}", this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); @@ -3504,7 +3896,6 @@ internal async Task GetGuildPruneCountAsync(ulong guildId, int days, IEnume /// If true, compute_prune_count. /// The include_roles. /// The reason. - internal async Task BeginGuildPruneAsync(ulong guildId, int days, bool computePruneCount, IEnumerable includeRoles, string reason) { if (days < 0 || days > 30) @@ -3512,20 +3903,22 @@ internal async Task GetGuildPruneCountAsync(ulong guildId, int days, IEnume var urlParams = new Dictionary { - ["days"] = days.ToString(CultureInfo.InvariantCulture), - ["compute_prune_count"] = computePruneCount.ToString() + ["days"] = days.ToString(CultureInfo.InvariantCulture), ["compute_prune_count"] = computePruneCount.ToString() }; var sb = includeRoles?.Aggregate(new StringBuilder(), - (sb, id) => sb.Append($"&include_roles={id}")) - ?? new StringBuilder(); + (sb, id) => sb.Append($"&include_roles={id}")) + ?? new StringBuilder(); var headers = Utilities.GetBaseHeaders(); if (!string.IsNullOrWhiteSpace(reason)) headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.PRUNE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + guild_id = guildId + }, out var path); var url = Utilities.GetApiUriFor(path, $"{BuildQueryString(urlParams)}{sb}", this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, headers).ConfigureAwait(false); @@ -3534,18 +3927,22 @@ internal async Task GetGuildPruneCountAsync(ulong guildId, int days, IEnume return pruned.Pruned; } - #endregion - #region GuildVarious +#endregion + +#region GuildVarious + /// /// Gets the template async. /// /// The code. - internal async Task GetTemplateAsync(string code) { var route = $"{Endpoints.GUILDS}{Endpoints.TEMPLATES}/:code"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { code }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + code + }, 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); @@ -3559,11 +3956,13 @@ internal async Task GetTemplateAsync(string code) /// Gets the guild integrations async. /// /// The guild_id. - internal async Task> GetGuildIntegrationsAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INTEGRATIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -3576,11 +3975,13 @@ internal async Task> GetGuildIntegrationsAsync /// Gets the guild preview async. /// /// The guild_id. - internal async Task GetGuildPreviewAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.PREVIEW}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -3595,17 +3996,18 @@ internal async Task GetGuildPreviewAsync(ulong guildId) /// The guild_id. /// The type. /// The id. - internal async Task CreateGuildIntegrationAsync(ulong guildId, string type, ulong id) { var pld = new RestGuildIntegrationAttachPayload { - Type = type, - Id = id + Type = type, Id = id }; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INTEGRATIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path); + 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); @@ -3622,18 +4024,18 @@ internal async Task CreateGuildIntegrationAsync(ulong guildI /// The expire_behaviour. /// The expire_grace_period. /// If true, enable_emoticons. - internal async Task ModifyGuildIntegrationAsync(ulong guildId, ulong integrationId, int expireBehaviour, int expireGracePeriod, bool enableEmoticons) { var pld = new RestGuildIntegrationModifyPayload { - ExpireBehavior = expireBehaviour, - ExpireGracePeriod = expireGracePeriod, - EnableEmoticons = enableEmoticons + ExpireBehavior = expireBehaviour, ExpireGracePeriod = expireGracePeriod, EnableEmoticons = enableEmoticons }; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INTEGRATIONS}/:integration_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, integration_id = integrationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + guild_id = guildId, integration_id = integrationId + }, 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); @@ -3647,11 +4049,13 @@ internal async Task ModifyGuildIntegrationAsync(ulong guildI /// /// The guild_id. /// The integration. - internal Task DeleteGuildIntegrationAsync(ulong guildId, DiscordIntegration integration) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INTEGRATIONS}/:integration_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, integration_id = integration.Id }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + guild_id = guildId, integration_id = integration.Id + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, payload: DiscordJson.SerializeObject(integration)); @@ -3662,11 +4066,13 @@ internal Task DeleteGuildIntegrationAsync(ulong guildId, DiscordIntegration inte /// /// The guild_id. /// The integration_id. - internal Task SyncGuildIntegrationAsync(ulong guildId, ulong integrationId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INTEGRATIONS}/:integration_id{Endpoints.SYNC}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId, integration_id = integrationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + guild_id = guildId, integration_id = integrationId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route); @@ -3676,11 +4082,13 @@ internal Task SyncGuildIntegrationAsync(ulong guildId, ulong integrationId) /// Gets the guild voice regions async. /// /// The guild_id. - internal async Task> GetGuildVoiceRegionsAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.REGIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -3694,11 +4102,13 @@ internal async Task> GetGuildVoiceRegionsAsync /// Gets the guild invites async. /// /// The guild_id. - internal async Task> GetGuildInvitesAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.INVITES}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -3707,9 +4117,11 @@ internal async Task> GetGuildInvitesAsync(ulong gui return invites; } - #endregion - #region Invite +#endregion + +#region Invite + /// /// Gets the invite async. /// @@ -3717,7 +4129,6 @@ internal async Task> GetGuildInvitesAsync(ulong gui /// If true, with_counts. /// If true, with_expiration. /// The scheduled event id to get. - internal async Task GetInviteAsync(string inviteCode, bool? withCounts, bool? withExpiration, ulong? guildScheduledEventId) { var urlParams = new Dictionary(); @@ -3729,7 +4140,10 @@ internal async Task GetInviteAsync(string inviteCode, bool? withC urlParams["guild_scheduled_event_id"] = guildScheduledEventId?.ToString(); var route = $"{Endpoints.INVITES}/:invite_code"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {invite_code = inviteCode }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + invite_code = inviteCode + }, 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); @@ -3743,7 +4157,6 @@ internal async Task GetInviteAsync(string inviteCode, bool? withC /// /// The invite_code. /// The reason. - internal async Task DeleteInviteAsync(string inviteCode, string reason) { var headers = Utilities.GetBaseHeaders(); @@ -3751,7 +4164,10 @@ internal async Task DeleteInviteAsync(string inviteCode, string r headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.INVITES}/:invite_code"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {invite_code = inviteCode }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + invite_code = inviteCode + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers).ConfigureAwait(false); @@ -3761,32 +4177,35 @@ internal async Task DeleteInviteAsync(string inviteCode, string r } /* - * Disabled due to API restrictions - * - * internal async Task InternalAcceptInvite(string invite_code) - * { - * this.Discord.DebugLogger.LogMessage(LogLevel.Warning, "REST API", "Invite accept endpoint was used; this account is now likely unverified", DateTime.Now); - * - * var url = new Uri($"{Utils.GetApiBaseUri(this.Configuration), Endpoints.INVITES}/{invite_code)); - * var bucket = this.Rest.GetBucket(0, MajorParameterType.Unbucketed, url, HttpRequestMethod.POST); - * var res = await this.DoRequestAsync(this.Discord, bucket, url, HttpRequestMethod.POST).ConfigureAwait(false); - * - * var ret = DiscordJson.DeserializeObject(res.Response, this.Discord); - * ret.Discord = this.Discord; - * - * return ret; - * } - */ - #endregion - - #region Connections + * Disabled due to API restrictions + * + * internal async Task InternalAcceptInvite(string invite_code) + * { + * this.Discord.DebugLogger.LogMessage(LogLevel.Warning, "REST API", "Invite accept endpoint was used; this account is now likely unverified", DateTime.Now); + * + * var url = new Uri($"{Utils.GetApiBaseUri(this.Configuration), Endpoints.INVITES}/{invite_code)); + * var bucket = this.Rest.GetBucket(0, MajorParameterType.Unbucketed, url, HttpRequestMethod.POST); + * var res = await this.DoRequestAsync(this.Discord, bucket, url, HttpRequestMethod.POST).ConfigureAwait(false); + * + * var ret = DiscordJson.DeserializeObject(res.Response, this.Discord); + * ret.Discord = this.Discord; + * + * return ret; + * } + */ + +#endregion + +#region Connections + /// /// Gets the users connections async. /// internal async Task> GetUserConnectionsAsync() { var route = $"{Endpoints.USERS}{Endpoints.ME}{Endpoints.CONNECTIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, 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); @@ -3803,7 +4222,10 @@ internal async Task> GetUserConnectionsAsync() internal async Task> GetRoleConnectionMetadataRecords(ulong id) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.ROLE_CONNECTIONS}{Endpoints.METADATA}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = id }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = id + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); @@ -3822,7 +4244,6 @@ internal async Task> Upd { var pld = new List(); foreach (var metadataObject in metadataObjects) - { pld.Add(new() { Type = metadataObject.Type, @@ -3832,27 +4253,31 @@ internal async Task> Upd NameLocalizations = metadataObject.NameLocalizations?.GetKeyValuePairs(), DescriptionLocalizations = metadataObject.DescriptionLocalizations?.GetKeyValuePairs() }); - } var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.ROLE_CONNECTIONS}{Endpoints.METADATA}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { application_id = id }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + application_id = id + }, 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 metadata = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); return metadata; } - #endregion - #region Voice +#endregion + +#region Voice + /// /// Lists the voice regions async. /// - internal async Task> ListVoiceRegionsAsync() { var route = $"{Endpoints.VOICE}{Endpoints.REGIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, 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); @@ -3861,9 +4286,11 @@ internal async Task> ListVoiceRegionsAsync() return regions; } - #endregion - #region Webhooks +#endregion + +#region Webhooks + /// /// Creates the webhook async. /// @@ -3875,9 +4302,7 @@ internal async Task CreateWebhookAsync(ulong channelId, string n { var pld = new RestWebhookPayload { - Name = name, - AvatarBase64 = base64Avatar.ValueOrDefault(), - AvatarSet = base64Avatar.HasValue + Name = name, AvatarBase64 = base64Avatar.ValueOrDefault(), AvatarSet = base64Avatar.HasValue }; var headers = new Dictionary(); @@ -3885,7 +4310,10 @@ internal async Task CreateWebhookAsync(ulong channelId, string n headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.WEBHOOKS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {channel_id = channelId }, out var path); + 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, headers, DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -3903,12 +4331,19 @@ internal async Task CreateWebhookAsync(ulong channelId, string n internal async Task> GetChannelWebhooksAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.WEBHOOKS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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 webhooksRaw = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xw => { xw.ApiClient = this; return xw; }); + var webhooksRaw = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xw => + { + xw.ApiClient = this; + return xw; + }); return webhooksRaw.ToList(); } @@ -3919,12 +4354,19 @@ internal async Task> GetChannelWebhooksAsync(ulong internal async Task> GetGuildWebhooksAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.WEBHOOKS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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 webhooksRaw = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xw => { xw.ApiClient = this; return xw; }); + var webhooksRaw = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord).Select(xw => + { + xw.ApiClient = this; + return xw; + }); return webhooksRaw.ToList(); } @@ -3935,7 +4377,10 @@ internal async Task> GetGuildWebhooksAsync(ulong g internal async Task GetWebhookAsync(ulong webhookId) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { webhook_id = webhookId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + webhook_id = webhookId + }, 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); @@ -3954,7 +4399,10 @@ internal async Task GetWebhookAsync(ulong webhookId) internal async Task GetWebhookWithTokenAsync(ulong webhookId, string webhookToken) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, 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); @@ -3979,10 +4427,7 @@ internal async Task ModifyWebhookAsync(ulong webhookId, ulong ch { var pld = new RestWebhookPayload { - Name = name, - AvatarBase64 = base64Avatar.ValueOrDefault(), - AvatarSet = base64Avatar.HasValue, - ChannelId = channelId + Name = name, AvatarBase64 = base64Avatar.ValueOrDefault(), AvatarSet = base64Avatar.HasValue, ChannelId = channelId }; var headers = new Dictionary(); @@ -3990,7 +4435,10 @@ internal async Task ModifyWebhookAsync(ulong webhookId, ulong ch headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.WEBHOOKS}/:webhook_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {webhook_id = webhookId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + webhook_id = webhookId + }, 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); @@ -4013,8 +4461,7 @@ internal async Task ModifyWebhookAsync(ulong webhookId, string n { var pld = new RestWebhookPayload { - Name = name, - AvatarBase64 = base64Avatar + Name = name, AvatarBase64 = base64Avatar }; var headers = new Dictionary(); @@ -4022,7 +4469,10 @@ internal async Task ModifyWebhookAsync(ulong webhookId, string n headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, 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); @@ -4045,7 +4495,10 @@ internal Task DeleteWebhookAsync(ulong webhookId, string reason) headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.WEBHOOKS}/:webhook_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {webhook_id = webhookId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + webhook_id = webhookId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers); @@ -4064,7 +4517,10 @@ internal Task DeleteWebhookAsync(ulong webhookId, string webhookToken, string re headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers); @@ -4126,6 +4582,7 @@ internal async Task ExecuteWebhookAsync(ulong webhookId, string attachments.Add(att); fileId++; } + pld.Attachments = attachments; } @@ -4133,7 +4590,10 @@ internal async Task ExecuteWebhookAsync(ulong webhookId, string values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord?.Configuration).AddParameter("wait", "true"); if (threadId != null) @@ -4163,7 +4623,10 @@ internal async Task ExecuteWebhookAsync(ulong webhookId, string internal async Task ExecuteWebhookSlackAsync(ulong webhookId, string webhookToken, string jsonPayload, string threadId) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.SLACK}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "true"); if (threadId != null) @@ -4184,7 +4647,10 @@ internal async Task ExecuteWebhookSlackAsync(ulong webhookId, st internal async Task ExecuteWebhookGithubAsync(ulong webhookId, string webhookToken, string jsonPayload, string threadId) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.GITHUB}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {webhook_id = webhookId, webhook_token = webhookToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + webhook_id = webhookId, webhook_token = webhookToken + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "true"); if (threadId != null) @@ -4239,6 +4705,7 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str attachments.Add(att); fileId++; } + if (builder.Attachments != null && builder.Attachments?.Count > 0) attachments.AddRange(builder.Attachments); @@ -4249,7 +4716,10 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str ["payload_json"] = DiscordJson.SerializeObject(pld) }; var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration); if (threadId != null) @@ -4273,7 +4743,10 @@ internal async Task EditWebhookMessageAsync(ulong webhookId, str pld.Attachments = builder.Attachments; var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration); if (threadId != null) @@ -4312,7 +4785,10 @@ internal Task EditWebhookMessageAsync(ulong webhookId, string we internal async Task GetWebhookMessageAsync(ulong webhookId, string webhookToken, string messageId, string threadId) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration); if (threadId != null) @@ -4353,7 +4829,10 @@ internal Task GetWebhookMessageAsync(ulong webhookId, string web internal async Task DeleteWebhookMessageAsync(ulong webhookId, string webhookToken, string messageId, string threadId) { var route = $"{Endpoints.WEBHOOKS}/:webhook_id/:webhook_token{Endpoints.MESSAGES}/:message_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + webhook_id = webhookId, webhook_token = webhookToken, message_id = messageId + }, out var path); var qub = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration); if (threadId != null) @@ -4380,20 +4859,24 @@ internal Task DeleteWebhookMessageAsync(ulong webhookId, string webhookToken, ul /// The thread_id. internal Task DeleteWebhookMessageAsync(ulong webhookId, string webhookToken, ulong messageId, ulong threadId) => this.DeleteWebhookMessageAsync(webhookId, webhookToken, messageId.ToString(), threadId.ToString()); - #endregion - #region Reactions +#endregion + +#region Reactions + /// /// Creates the reaction async. /// /// The channel_id. /// The message_id. /// The emoji. - internal Task CreateReactionAsync(ulong channelId, ulong messageId, string emoji) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}/:emoji{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId, message_id = messageId, emoji }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId, message_id = messageId, emoji + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route, ratelimitWaitOverride: this.Discord.Configuration.UseRelativeRatelimit ? null : 0.26); @@ -4405,11 +4888,13 @@ internal Task CreateReactionAsync(ulong channelId, ulong messageId, string emoji /// The channel_id. /// The message_id. /// The emoji. - internal Task DeleteOwnReactionAsync(ulong channelId, ulong messageId, string emoji) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}/:emoji{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId, emoji }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId, emoji + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, ratelimitWaitOverride: this.Discord.Configuration.UseRelativeRatelimit ? null : 0.26); @@ -4423,7 +4908,6 @@ internal Task DeleteOwnReactionAsync(ulong channelId, ulong messageId, string em /// The user_id. /// The emoji. /// The reason. - internal Task DeleteUserReactionAsync(ulong channelId, ulong messageId, ulong userId, string emoji, string reason) { var headers = new Dictionary(); @@ -4431,7 +4915,10 @@ internal Task DeleteUserReactionAsync(ulong channelId, ulong messageId, ulong us headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}/:emoji/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId, emoji, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId, emoji, 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, ratelimitWaitOverride: this.Discord.Configuration.UseRelativeRatelimit ? null : 0.26); @@ -4445,7 +4932,6 @@ internal Task DeleteUserReactionAsync(ulong channelId, ulong messageId, ulong us /// The emoji. /// The after_id. /// The limit. - internal async Task> GetReactionsAsync(ulong channelId, ulong messageId, string emoji, ulong? afterId = null, int limit = 25) { var urlParams = new Dictionary(); @@ -4455,7 +4941,10 @@ internal async Task> GetReactionsAsync(ulong channelI urlParams["limit"] = limit.ToString(CultureInfo.InvariantCulture); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}/:emoji"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId, message_id = messageId, emoji }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + channel_id = channelId, message_id = messageId, emoji + }, out var path); var url = Utilities.GetApiUriFor(path, BuildQueryString(urlParams), this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); @@ -4464,7 +4953,10 @@ internal async Task> GetReactionsAsync(ulong channelI var reacters = new List(); foreach (var xr in reactersRaw) { - var usr = new DiscordUser(xr) { Discord = this.Discord }; + var usr = new DiscordUser(xr) + { + Discord = this.Discord + }; usr = this.Discord.UserCache.AddOrUpdate(xr.Id, usr, (id, old) => { old.Username = usr.Username; @@ -4486,7 +4978,6 @@ internal async Task> GetReactionsAsync(ulong channelI /// The channel_id. /// The message_id. /// The reason. - internal Task DeleteAllReactionsAsync(ulong channelId, ulong messageId, string reason) { var headers = new Dictionary(); @@ -4494,7 +4985,10 @@ internal Task DeleteAllReactionsAsync(ulong channelId, ulong messageId, string r headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers, ratelimitWaitOverride: this.Discord.Configuration.UseRelativeRatelimit ? null : 0.26); @@ -4506,18 +5000,21 @@ internal Task DeleteAllReactionsAsync(ulong channelId, ulong messageId, string r /// The channel_id. /// The message_id. /// The emoji. - internal Task DeleteReactionsEmojiAsync(ulong channelId, ulong messageId, string emoji) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.MESSAGES}/:message_id{Endpoints.REACTIONS}/:emoji"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, message_id = messageId, emoji }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, message_id = messageId, emoji + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, ratelimitWaitOverride: this.Discord.Configuration.UseRelativeRatelimit ? null : 0.26); } - #endregion - #region Threads +#endregion + +#region Threads /// /// Creates the thread. @@ -4532,20 +5029,26 @@ internal Task DeleteReactionsEmojiAsync(ulong channelId, ulong messageId, string /// The message builder. /// Whether this thread is in a forum. /// The reason. - internal async Task CreateThreadAsync(ulong channelId, ulong? messageId, string name, - ThreadAutoArchiveDuration? autoArchiveDuration, ChannelType? type, int? rateLimitPerUser, IEnumerable? appliedTags = null, - DiscordMessageBuilder builder = null, bool isForum = false, string? reason = null) + internal async Task CreateThreadAsync( + ulong channelId, + ulong? messageId, + string name, + ThreadAutoArchiveDuration? autoArchiveDuration, + ChannelType? type, + int? rateLimitPerUser, + IEnumerable? appliedTags = null, + DiscordMessageBuilder builder = null, + bool isForum = false, + string? reason = null + ) { var pld = new RestThreadChannelCreatePayload { - Name = name, - AutoArchiveDuration = autoArchiveDuration, - PerUserRateLimit = rateLimitPerUser + Name = name, AutoArchiveDuration = autoArchiveDuration, PerUserRateLimit = rateLimitPerUser }; if (isForum) { - pld.Message = new() { Content = builder.Content, @@ -4555,10 +5058,12 @@ internal async Task CreateThreadAsync(ulong channelId, ulo Embeds = builder.Embeds, //Flags = builder.Flags, //Mentions = builder.Mentions, - StickersIds = builder.Sticker != null ? new List(1) - { - builder.Sticker.Id - } : null + StickersIds = builder.Sticker != null + ? new List(1) + { + builder.Sticker.Id + } + : null }; if (appliedTags != null && appliedTags.Any()) { @@ -4572,11 +5077,7 @@ internal async Task CreateThreadAsync(ulong channelId, ulo } } else - { pld.Type = type; - } - - var headers = Utilities.GetBaseHeaders(); if (!string.IsNullOrWhiteSpace(reason)) @@ -4588,8 +5089,14 @@ internal async Task CreateThreadAsync(ulong channelId, ulo route += Endpoints.THREADS; object param = messageId is null - ? new {channel_id = channelId} - : new {channel_id = channelId, message_id = messageId}; + ? new + { + channel_id = channelId + } + : new + { + channel_id = channelId, message_id = messageId + }; var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, param, out var path); @@ -4607,7 +5114,10 @@ internal async Task CreateThreadAsync(ulong channelId, ulo internal async Task GetThreadAsync(ulong threadId) { var route = $"{Endpoints.CHANNELS}/:thread_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {thread_id = threadId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + thread_id = threadId + }, 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); @@ -4623,7 +5133,10 @@ internal async Task GetThreadAsync(ulong threadId) internal async Task JoinThreadAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREAD_MEMBERS}{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route).ConfigureAwait(false); @@ -4636,7 +5149,10 @@ internal async Task JoinThreadAsync(ulong channelId) internal async Task LeaveThreadAsync(ulong channelId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREAD_MEMBERS}{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false); @@ -4650,7 +5166,10 @@ internal async Task LeaveThreadAsync(ulong channelId) internal async Task AddThreadMemberAsync(ulong channelId, ulong userId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREAD_MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {channel_id = channelId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + channel_id = channelId, user_id = userId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.PUT, route).ConfigureAwait(false); @@ -4670,7 +5189,10 @@ internal async Task GetThreadMemberAsync(ulong chann }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREAD_MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + channel_id = channelId, user_id = userId + }, 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); @@ -4688,7 +5210,10 @@ internal async Task GetThreadMemberAsync(ulong chann internal async Task RemoveThreadMemberAsync(ulong channelId, ulong userId) { var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREAD_MEMBERS}/:user_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {channel_id = channelId, user_id = userId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + channel_id = channelId, user_id = userId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false); @@ -4716,7 +5241,10 @@ internal async Task> GetThreadMembersA urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture); var route = $"{Endpoints.CHANNELS}/:thread_id{Endpoints.THREAD_MEMBERS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {thread_id = threadId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + thread_id = threadId + }, 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); @@ -4733,7 +5261,10 @@ internal async Task> GetThreadMembersA internal async Task GetActiveThreadsAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.THREADS}{Endpoints.THREAD_ACTIVE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -4759,7 +5290,10 @@ internal async Task GetJoinedPrivateArchivedThreadsAsync(ul urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.USERS}{Endpoints.ME}{Endpoints.THREADS}{Endpoints.THREAD_ARCHIVED}{Endpoints.THREAD_PRIVATE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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); @@ -4784,7 +5318,10 @@ internal async Task GetPublicArchivedThreadsAsync(ulong cha urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREADS}{Endpoints.THREAD_ARCHIVED}{Endpoints.THREAD_PUBLIC}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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); @@ -4809,7 +5346,10 @@ internal async Task GetPrivateArchivedThreadsAsync(ulong ch urlParams["limit"] = limit.Value.ToString(CultureInfo.InvariantCulture); var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.THREADS}{Endpoints.THREAD_ARCHIVED}{Endpoints.THREAD_PRIVATE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {channel_id = channelId }, out var path); + 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); @@ -4856,6 +5396,7 @@ internal Task ModifyThreadAsync(ulong threadId, ChannelType parentType, string n pld.AppliedTags = tags; } + if (pinned.HasValue && pinned.Value.HasValue) pld.Flags = pinned.Value.Value ? ChannelFlags.Pinned : Optional.None; } @@ -4865,24 +5406,30 @@ internal Task ModifyThreadAsync(ulong threadId, ChannelType parentType, string n headers.Add(REASON_HEADER_NAME, reason); var route = $"{Endpoints.CHANNELS}/:thread_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {thread_id = threadId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + thread_id = threadId + }, 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)); } - #endregion +#endregion + +#region Emoji - #region Emoji /// /// Gets the guild emojis async. /// /// The guild_id. - internal async Task> GetGuildEmojisAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.EMOJIS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId }, out var path); + 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); @@ -4920,11 +5467,13 @@ internal async Task> GetGuildEmojisAsync(ulong /// /// The guild_id. /// The emoji_id. - internal async Task GetGuildEmojiAsync(ulong guildId, ulong emojiId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.EMOJIS}/:emoji_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, emoji_id = emojiId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId, emoji_id = emojiId + }, 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); @@ -4950,14 +5499,11 @@ internal async Task GetGuildEmojiAsync(ulong guildId, ulong e /// The imageb64. /// The roles. /// The reason. - internal async Task CreateGuildEmojiAsync(ulong guildId, string name, string imageb64, IEnumerable roles, string reason) { var pld = new RestGuildEmojiCreatePayload { - Name = name, - ImageB64 = imageb64, - Roles = roles?.ToArray() + Name = name, ImageB64 = imageb64, Roles = roles?.ToArray() }; var headers = new Dictionary(); @@ -4965,7 +5511,10 @@ internal async Task CreateGuildEmojiAsync(ulong guildId, stri headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.EMOJIS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId }, out var path); + 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); @@ -4992,13 +5541,11 @@ internal async Task CreateGuildEmojiAsync(ulong guildId, stri /// The name. /// The roles. /// The reason. - internal async Task ModifyGuildEmojiAsync(ulong guildId, ulong emojiId, string name, IEnumerable roles, string reason) { var pld = new RestGuildEmojiModifyPayload { - Name = name, - Roles = roles?.ToArray() + Name = name, Roles = roles?.ToArray() }; var headers = new Dictionary(); @@ -5006,7 +5553,10 @@ internal async Task ModifyGuildEmojiAsync(ulong guildId, ulon headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.EMOJIS}/:emoji_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, emoji_id = emojiId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + guild_id = guildId, emoji_id = emojiId + }, 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); @@ -5030,7 +5580,6 @@ internal async Task ModifyGuildEmojiAsync(ulong guildId, ulon /// The guild_id. /// The emoji_id. /// The reason. - internal Task DeleteGuildEmojiAsync(ulong guildId, ulong emojiId, string reason) { var headers = new Dictionary(); @@ -5038,14 +5587,18 @@ internal Task DeleteGuildEmojiAsync(ulong guildId, ulong emojiId, string reason) headers[REASON_HEADER_NAME] = reason; var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.EMOJIS}/:emoji_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, emoji_id = emojiId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + guild_id = guildId, emoji_id = emojiId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); return this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers); } - #endregion - #region Stickers +#endregion + +#region Stickers /// /// Gets a sticker. @@ -5054,7 +5607,10 @@ internal Task DeleteGuildEmojiAsync(ulong guildId, ulong emojiId, string reason) internal async Task GetStickerAsync(ulong stickerId) { var route = $"{Endpoints.STICKERS}/:sticker_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {sticker_id = stickerId}, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + sticker_id = stickerId + }, 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); @@ -5068,7 +5624,8 @@ internal async Task GetStickerAsync(ulong stickerId) internal async Task> GetStickerPacksAsync() { var route = $"{Endpoints.STICKERPACKS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, 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); @@ -5086,7 +5643,10 @@ internal async Task> GetStickerPacksAsync() internal async Task> GetGuildStickersAsync(ulong guildId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.STICKERS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId}, out var path); + 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); @@ -5103,7 +5663,10 @@ internal async Task> GetGuildStickersAsync(ulong g internal async Task GetGuildStickerAsync(ulong guildId, ulong stickerId) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.STICKERS}/:sticker_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {guild_id = guildId, sticker_id = stickerId}, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId, sticker_id = stickerId + }, 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); @@ -5124,7 +5687,10 @@ internal async Task GetGuildStickerAsync(ulong guildId, ulong st internal async Task CreateGuildStickerAsync(ulong guildId, string name, string description, string tags, DiscordMessageFile file, string reason) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.STICKERS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {guild_id = guildId}, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + guild_id = guildId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var headers = Utilities.GetBaseHeaders(); @@ -5149,7 +5715,10 @@ internal async Task CreateGuildStickerAsync(ulong guildId, strin internal async Task ModifyGuildStickerAsync(ulong guildId, ulong stickerId, Optional name, Optional description, Optional tags, string reason) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.STICKERS}/:sticker_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {guild_id = guildId, sticker_id = stickerId}, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + guild_id = guildId, sticker_id = stickerId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var headers = Utilities.GetBaseHeaders(); if (!string.IsNullOrWhiteSpace(reason)) @@ -5157,9 +5726,7 @@ internal async Task ModifyGuildStickerAsync(ulong guildId, ulong var pld = new RestStickerModifyPayload() { - Name = name, - Description = description, - Tags = tags + Name = name, Description = description, Tags = tags }; var values = new Dictionary @@ -5181,7 +5748,10 @@ internal async Task ModifyGuildStickerAsync(ulong guildId, ulong internal async Task DeleteGuildStickerAsync(ulong guildId, ulong stickerId, string reason) { var route = $"{Endpoints.GUILDS}/:guild_id{Endpoints.STICKERS}/:sticker_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {guild_id = guildId, sticker_id = stickerId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + guild_id = guildId, sticker_id = stickerId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var headers = Utilities.GetBaseHeaders(); if (!string.IsNullOrWhiteSpace(reason)) @@ -5189,9 +5759,10 @@ internal async Task DeleteGuildStickerAsync(ulong guildId, ulong stickerId, stri await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route, headers).ConfigureAwait(false); } - #endregion - #region Application Commands +#endregion + +#region Application Commands /// /// Gets the global application commands. @@ -5201,7 +5772,10 @@ internal async Task DeleteGuildStickerAsync(ulong guildId, ulong stickerId, stri internal async Task> GetGlobalApplicationCommandsAsync(ulong applicationId, bool withLocalizations = false) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId + }, out var path); var querydict = new Dictionary { @@ -5224,7 +5798,6 @@ internal async Task> BulkOverwriteGloba var pld = new List(); if (commands.Any()) foreach (var command in commands) - { pld.Add(new() { Type = command.Type, @@ -5239,10 +5812,12 @@ internal async Task> BulkOverwriteGloba AllowedContexts = command.AllowedContexts, IntegrationTypes = command.IntegrationTypes }); - } var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + application_id = applicationId + }, 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); @@ -5274,7 +5849,10 @@ internal async Task CreateGlobalApplicationCommandAsy }; var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + application_id = applicationId + }, 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); @@ -5293,7 +5871,10 @@ internal async Task CreateGlobalApplicationCommandAsy internal async Task GetGlobalApplicationCommandAsync(ulong applicationId, ulong commandId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {application_id = applicationId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId, command_id = commandId + }, 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); @@ -5319,13 +5900,20 @@ internal async Task GetGlobalApplicationCommandAsync( /// Whether this command is marked as NSFW. /// The allowed contexts. /// The allowed integration types. - internal async Task EditGlobalApplicationCommandAsync(ulong applicationId, + internal async Task EditGlobalApplicationCommandAsync( + ulong applicationId, ulong commandId, - Optional name, Optional description, Optional?> options, + Optional name, + Optional description, + Optional?> options, Optional nameLocalization, Optional descriptionLocalization, - Optional defaultMemberPermission, Optional dmPermission, Optional isNsfw, - Optional?> allowedContexts, Optional?> integrationTypes) + Optional defaultMemberPermission, + Optional dmPermission, + Optional isNsfw, + Optional?> allowedContexts, + Optional?> integrationTypes + ) { var pld = new RestApplicationCommandEditPayload { @@ -5342,7 +5930,10 @@ internal async Task EditGlobalApplicationCommandAsync }; var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {application_id = applicationId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + application_id = applicationId, command_id = commandId + }, 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); @@ -5358,11 +5949,13 @@ internal async Task EditGlobalApplicationCommandAsync /// /// The application_id. /// The command_id. - internal async Task DeleteGlobalApplicationCommandAsync(ulong applicationId, ulong commandId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {application_id = applicationId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + application_id = applicationId, command_id = commandId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false); @@ -5377,7 +5970,10 @@ internal async Task DeleteGlobalApplicationCommandAsync(ulong applicationId, ulo internal async Task> GetGuildApplicationCommandsAsync(ulong applicationId, ulong guildId, bool withLocalizations = false) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {application_id = applicationId, guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId, guild_id = guildId + }, out var path); var querydict = new Dictionary { @@ -5401,7 +5997,6 @@ internal async Task> BulkOverwriteGuild var pld = new List(); if (commands.Any()) foreach (var command in commands) - { pld.Add(new() { Type = command.Type, @@ -5415,10 +6010,12 @@ internal async Task> BulkOverwriteGuild Nsfw = command.IsNsfw, AllowedContexts = command.AllowedContexts }); - } var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new {application_id = applicationId, guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + application_id = applicationId, guild_id = guildId + }, 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); @@ -5450,7 +6047,10 @@ internal async Task CreateGuildApplicationCommandAsyn }; var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {application_id = applicationId, guild_id = guildId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + application_id = applicationId, 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); @@ -5470,7 +6070,10 @@ internal async Task CreateGuildApplicationCommandAsyn internal async Task GetGuildApplicationCommandAsync(ulong applicationId, ulong guildId, ulong commandId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new {application_id = applicationId, guild_id = guildId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId, guild_id = guildId, command_id = commandId + }, 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); @@ -5497,13 +6100,21 @@ internal async Task GetGuildApplicationCommandAsync(u /// Whether this command is marked as NSFW. /// The allowed contexts. /// The allowed integration types. - internal async Task EditGuildApplicationCommandAsync(ulong applicationId, ulong guildId, + internal async Task EditGuildApplicationCommandAsync( + ulong applicationId, + ulong guildId, ulong commandId, - Optional name, Optional description, Optional?> options, + Optional name, + Optional description, + Optional?> options, Optional nameLocalization, Optional descriptionLocalization, - Optional defaultMemberPermission, Optional dmPermission, Optional isNsfw, - Optional?> allowedContexts, Optional?> integrationTypes) + Optional defaultMemberPermission, + Optional dmPermission, + Optional isNsfw, + Optional?> allowedContexts, + Optional?> integrationTypes + ) { var pld = new RestApplicationCommandEditPayload { @@ -5519,7 +6130,10 @@ internal async Task EditGuildApplicationCommandAsync( }; var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new {application_id = applicationId, guild_id = guildId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { + application_id = applicationId, guild_id = guildId, command_id = commandId + }, 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); @@ -5539,7 +6153,10 @@ internal async Task EditGuildApplicationCommandAsync( internal async Task DeleteGuildApplicationCommandAsync(ulong applicationId, ulong guildId, ulong commandId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.GUILDS}/:guild_id{Endpoints.COMMANDS}/:command_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new {application_id = applicationId, guild_id = guildId, command_id = commandId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + application_id = applicationId, guild_id = guildId, command_id = commandId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false); @@ -5574,25 +6191,24 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i flags |= MessageFlags.SuppressNotifications; } - var data = builder != null ? new DiscordInteractionApplicationCommandCallbackData - { - Content = builder?.Content ?? null, - Embeds = builder?.Embeds ?? null, - IsTts = builder?.IsTts, - Mentions = builder?.Mentions ?? null, - Flags = flags, - Components = builder?.Components ?? null, - Choices = null - } : null; - + var data = builder != null + ? new DiscordInteractionApplicationCommandCallbackData + { + Content = builder?.Content ?? null, + Embeds = builder?.Embeds ?? null, + IsTts = builder?.IsTts, + Mentions = builder?.Mentions ?? null, + Flags = flags, + Components = builder?.Components ?? null, + Choices = null + } + : null; pld = new() { - Type = type, - Data = data + Type = type, Data = data }; - if (builder != null && builder.Files != null && builder.Files.Count > 0) { ulong fileId = 0; @@ -5610,12 +6226,12 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i attachments.Add(att); fileId++; } + pld.Attachments = attachments; pld.Data.Attachments = attachments; } } else - { pld = new() { Type = type, @@ -5632,7 +6248,6 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i }, Attachments = null }; - } var values = new Dictionary(); @@ -5641,7 +6256,10 @@ internal async Task CreateInteractionResponseAsync(ulong interactionId, string i values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.INTERACTIONS}/:interaction_id/:interaction_token{Endpoints.CALLBACK}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {interaction_id = interactionId, interaction_token = interactionToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + interaction_id = interactionId, interaction_token = interactionToken + }, out var path); var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "false").Build(); if (builder != null) @@ -5672,16 +6290,17 @@ internal async Task CreateInteractionModalResponseAsync(ulong interactionId, str Type = type, Data = new() { - Title = builder.Title, - CustomId = builder.CustomId, - ModalComponents = builder.ModalComponents + Title = builder.Title, CustomId = builder.CustomId, ModalComponents = builder.ModalComponents } }; var values = new Dictionary(); var route = $"{Endpoints.INTERACTIONS}/:interaction_id/:interaction_token{Endpoints.CALLBACK}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {interaction_id = interactionId, interaction_token = interactionToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + interaction_id = interactionId, interaction_token = interactionToken + }, out var path); var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "true").Build(); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -5704,17 +6323,17 @@ internal async Task CreateInteractionIframeResponseAsync(ulong interactionId, st Type = type, Data = new() { - Title = title, - CustomId = customId, - ModalSize = modalSize, - IframePath = iFramePath + Title = title, CustomId = customId, ModalSize = modalSize, IframePath = iFramePath } }; var values = new Dictionary(); var route = $"{Endpoints.INTERACTIONS}/:interaction_id/:interaction_token{Endpoints.CALLBACK}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {interaction_id = interactionId, interaction_token = interactionToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + interaction_id = interactionId, interaction_token = interactionToken + }, out var path); var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "true").Build(); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, payload: DiscordJson.SerializeObject(pld)).ConfigureAwait(false); @@ -5760,7 +6379,6 @@ internal async Task CreateFollowupMessageAsync(ulong application if (embed.Timestamp != null) embed.Timestamp = embed.Timestamp.Value.ToUniversalTime(); - MessageFlags? flags = builder != null && builder.FlagsChanged ? MessageFlags.None : null; if (builder != null) { @@ -5782,7 +6400,6 @@ internal async Task CreateFollowupMessageAsync(ulong application Components = builder.Components }; - if (builder.Files != null && builder.Files.Count > 0) { ulong fileId = 0; @@ -5800,6 +6417,7 @@ internal async Task CreateFollowupMessageAsync(ulong application attachments.Add(att); fileId++; } + pld.Attachments = attachments; } @@ -5810,21 +6428,20 @@ internal async Task CreateFollowupMessageAsync(ulong application values["payload_json"] = DiscordJson.SerializeObject(pld); var route = $"{Endpoints.WEBHOOKS}/:application_id/:interaction_token"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new {application_id = applicationId, interaction_token = interactionToken }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + application_id = applicationId, interaction_token = interactionToken + }, out var path); var url = Utilities.GetApiUriBuilderFor(path, this.Discord.Configuration).AddParameter("wait", "true").Build(); var res = await this.DoMultipartAsync(this.Discord, bucket, url, RestRequestMethod.POST, route, values: values, files: builder.Files).ConfigureAwait(false); var ret = DiscordJson.DeserializeObject(res.Response, this.Discord); foreach (var att in ret.AttachmentsInternal) - { att.Discord = this.Discord; - } foreach (var file in builder.Files.Where(x => x.ResetPositionTo.HasValue)) - { file.Stream.Position = file.ResetPositionTo.Value; - } ret.Discord = this.Discord; return ret; @@ -5857,9 +6474,10 @@ internal Task EditFollowupMessageAsync(ulong applicationId, stri /// The message id. internal Task DeleteFollowupMessageAsync(ulong applicationId, string interactionToken, ulong messageId) => this.DeleteWebhookMessageAsync(applicationId, interactionToken, messageId); - #endregion - #region Misc +#endregion + +#region Misc /// /// Gets the published store sku listings (premium application subscription). @@ -5874,12 +6492,13 @@ internal async Task> GetPublishedListingsAsync(ul }; var route = $"{Endpoints.STORE}{Endpoints.PUBLISHED_LISTINGS}{Endpoints.SKUS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, 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 storeSkus = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); + var storeSkus = DiscordJson.DeserializeIEnumerableObject>(res.Response, this.Discord); foreach (var storeSku in storeSkus) storeSku.Sku.Discord = this.Discord; @@ -5894,7 +6513,10 @@ internal async Task> GetPublishedListingsAsync(ul internal async Task> GetSkusAsync(ulong applicationId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.SKUS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId + }, 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); @@ -5918,7 +6540,10 @@ internal async Task> GetEntitlementsAsync(ulon urlParams["user_id"] = userId.Value.ToString(); var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.ENTITLEMENTS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId + }, 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); @@ -5938,13 +6563,14 @@ internal async Task CreateTestEntitlementsAsync(ulong applic { TestEntitlementCreatePayload pld = new() { - SkuId = skuId, - OwnerId = ownerId, - OwnerType = ownerType + SkuId = skuId, OwnerId = ownerId, OwnerType = ownerType }; var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.ENTITLEMENTS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { + application_id = applicationId + }, 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); @@ -5960,7 +6586,10 @@ internal async Task CreateTestEntitlementsAsync(ulong applic internal async Task DeleteTestEntitlementsAsync(ulong applicationId, ulong entitlementId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.ENTITLEMENTS}/:entitlement_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new { application_id = applicationId, entitlement_id = entitlementId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.DELETE, route, new + { + application_id = applicationId, entitlement_id = entitlementId + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.DELETE, route).ConfigureAwait(false); @@ -5986,7 +6615,10 @@ internal Task GetApplicationRpcInfoAsync(ulong applicatio private async Task GetApplicationOauth2InfoAsync(string applicationId) { var route = $"{Endpoints.OAUTH2}{Endpoints.APPLICATIONS}/:application_id"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId + }, 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); @@ -6002,7 +6634,8 @@ private async Task GetApplicationOauth2InfoAsync(string ap internal async Task GetCurrentApplicationInfoAsync() { var route = $"{Endpoints.APPLICATIONS}{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, 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); @@ -6019,9 +6652,15 @@ internal async Task GetCurrentApplicationInfoAsync() /// internal async Task ModifyCurrentApplicationInfoAsync( Optional description, - Optional interactionsEndpointUrl, Optional roleConnectionsVerificationUrl, Optional customInstallUrl, - Optional?> tags, Optional iconb64, Optional coverImageb64, - Optional flags, Optional installParams) + Optional interactionsEndpointUrl, + Optional roleConnectionsVerificationUrl, + Optional customInstallUrl, + Optional?> tags, + Optional iconb64, + Optional coverImageb64, + Optional flags, + Optional installParams + ) { var pld = new RestApplicationModifyPayload() { @@ -6034,11 +6673,11 @@ internal async Task ModifyCurrentApplicationInfoAsync( ConverImageBase64 = coverImageb64, Flags = flags, InstallParams = installParams - }; var route = $"{Endpoints.APPLICATIONS}{Endpoints.ME}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PATCH, route, new + { }, 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); @@ -6056,7 +6695,10 @@ internal async Task ModifyCurrentApplicationInfoAsync( private async Task GetApplicationRpcInfoAsync(string applicationId) { var route = $"{Endpoints.APPLICATIONS}/:application_id{Endpoints.RPC}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = applicationId }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = applicationId + }, 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); @@ -6071,7 +6713,10 @@ private async Task GetApplicationRpcInfoAsync(string appl internal async Task> GetApplicationAssetsAsync(DiscordApplication application) { var route = $"{Endpoints.OAUTH2}{Endpoints.APPLICATIONS}/:application_id{Endpoints.ASSETS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { application_id = application.Id }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + application_id = application.Id + }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route).ConfigureAwait(false); @@ -6095,7 +6740,8 @@ internal async Task GetGatewayInfoAsync() var route = Endpoints.GATEWAY; if (this.Discord.Configuration.TokenType == TokenType.Bot) route += Endpoints.BOT; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, out var path); var url = Utilities.GetApiUriFor(path, this.Discord.Configuration); var res = await this.DoRequestAsync(this.Discord, bucket, url, RestRequestMethod.GET, route, headers).ConfigureAwait(false); @@ -6116,7 +6762,10 @@ internal async Task RequestFileUploadAsync(ulong channel }; var route = $"{Endpoints.CHANNELS}/:channel_id{Endpoints.ATTACHMENTS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { channel_id = channelId }, out var path); + 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); @@ -6133,9 +6782,9 @@ internal void UploadGcpFile(GcpAttachmentUploadInformation target, Stream file) this.Rest.HttpClient.Send(request); } - #endregion +#endregion - #region OAuth2 +#region OAuth2 /// /// Gets the current oauth2 authorization information. @@ -6148,7 +6797,8 @@ internal async Task GetCurrentOAuth2Authorizati // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.OAUTH2}/@me"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6172,7 +6822,10 @@ internal async Task GetCurrentUserAsync(string accessToken) // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me"; var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, - new { application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) }, out var path); + new + { + application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) + }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6195,7 +6848,8 @@ internal async Task> GetCurrentUserConnectionsA // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me{Endpoints.CONNECTIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6217,7 +6871,8 @@ internal async Task> GetCurrentUserGuildsAsync(strin // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me{Endpoints.GUILDS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6240,7 +6895,10 @@ internal async Task GetCurrentUserGuildMemberAsync(string accessT // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me{Endpoints.GUILDS}/:guild_id{Endpoints.MEMBER}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new { guild_id = guildId.ToString(CultureInfo.InvariantCulture) }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, new + { + guild_id = guildId.ToString(CultureInfo.InvariantCulture) + }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6264,7 +6922,10 @@ internal async Task GetCurrentUserApplicationR // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me{Endpoints.APPLICATIONS}/:application_id/{Endpoints.ROLE_CONNECTIONS}"; var bucket = this.Rest.GetBucket(RestRequestMethod.GET, route, - new { application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) }, out var path); + new + { + application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) + }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6289,14 +6950,15 @@ internal Task ModifyCurrentUserApplicationRoleConnectionAsync(string accessToken RestOAuth2ApplicationRoleConnectionPayload pld = new() { - PlatformName = platformName, - PlatformUsername = platformUsername, - Metadata = metadata.HasValue ? metadata.Value.GetKeyValuePairs() : Optional>.None + PlatformName = platformName, PlatformUsername = platformUsername, Metadata = metadata.HasValue ? metadata.Value.GetKeyValuePairs() : Optional>.None }; // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.USERS}/@me{Endpoints.APPLICATIONS}/:application_id/{Endpoints.ROLE_CONNECTIONS}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new { application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.PUT, route, new + { + application_id = this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) + }, out var path); var headers = Utilities.GetBaseHeaders(); headers.Add("Bearer", accessToken); @@ -6317,15 +6979,26 @@ internal async Task ExchangeOAuth2AccessTokenAsync(string co // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.OAUTH2}{Endpoints.TOKEN}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { }, out var path); var formData = new Dictionary { - { "client_id", this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) }, - { "client_secret", this.OAuth2Client.ClientSecret }, - { "grant_type", "authorization_code" }, - { "code", code }, - { "redirect_uri", this.OAuth2Client.RedirectUri.AbsoluteUri } + { + "client_id", this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) + }, + { + "client_secret", this.OAuth2Client.ClientSecret + }, + { + "grant_type", "authorization_code" + }, + { + "code", code + }, + { + "redirect_uri", this.OAuth2Client.RedirectUri.AbsoluteUri + } }; var url = Utilities.GetApiUriFor(path); @@ -6346,15 +7019,26 @@ internal async Task RefreshOAuth2AccessTokenAsync(string ref // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.OAUTH2}{Endpoints.TOKEN}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { }, out var path); var formData = new Dictionary { - { "client_id", this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) }, - { "client_secret", this.OAuth2Client.ClientSecret }, - { "grant_type", "refresh_token" }, - { "refresh_token", refreshToken }, - { "redirect_uri", this.OAuth2Client.RedirectUri.AbsoluteUri } + { + "client_id", this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture) + }, + { + "client_secret", this.OAuth2Client.ClientSecret + }, + { + "grant_type", "refresh_token" + }, + { + "refresh_token", refreshToken + }, + { + "redirect_uri", this.OAuth2Client.RedirectUri.AbsoluteUri + } }; var url = Utilities.GetApiUriFor(path); @@ -6376,7 +7060,8 @@ internal Task RevokeOAuth2TokenAsync(string token, string type) // ReSharper disable once HeuristicUnreachableCode var route = $"{Endpoints.OAUTH2}{Endpoints.TOKEN}{Endpoints.REVOKE}"; - var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); + var bucket = this.Rest.GetBucket(RestRequestMethod.POST, route, new + { }, out var path); var authorizationString = Encoding.UTF8.GetBytes($"{this.OAuth2Client.ClientId.ToString(CultureInfo.InvariantCulture)}:{this.OAuth2Client.ClientSecret}"); var base64EncodedAuthorizationString = Convert.ToBase64String(authorizationString); @@ -6386,8 +7071,12 @@ internal Task RevokeOAuth2TokenAsync(string token, string type) var formData = new Dictionary { - { "token", token }, - { "token_type_hint", type } + { + "token", token + }, + { + "token_type_hint", type + } }; var url = Utilities.GetApiUriFor(path); @@ -6395,5 +7084,5 @@ internal Task RevokeOAuth2TokenAsync(string token, string type) return Task.CompletedTask; } - #endregion +#endregion } diff --git a/DisCatSharp/Net/Rest/MultipartWebRequest.cs b/DisCatSharp/Net/Rest/MultipartWebRequest.cs index 8e7036eb50..81dbd35d78 100644 --- a/DisCatSharp/Net/Rest/MultipartWebRequest.cs +++ b/DisCatSharp/Net/Rest/MultipartWebRequest.cs @@ -40,8 +40,18 @@ internal sealed class MultipartWebRequest : BaseRestRequest /// The files. /// The ratelimit_wait_override. /// The file id start. - internal MultipartWebRequest(BaseDiscordClient client, RateLimitBucket bucket, Uri url, RestRequestMethod method, string route, IReadOnlyDictionary headers = null, IReadOnlyDictionary values = null, - IReadOnlyCollection files = null, double? ratelimitWaitOverride = null, int? overwriteFileIdStart = null) + internal MultipartWebRequest( + BaseDiscordClient client, + RateLimitBucket bucket, + Uri url, + RestRequestMethod method, + string route, + IReadOnlyDictionary headers = null, + IReadOnlyDictionary values = null, + IReadOnlyCollection files = null, + double? ratelimitWaitOverride = null, + int? overwriteFileIdStart = null + ) : base(client, bucket, url, method, route, headers, ratelimitWaitOverride) { this.Values = values; @@ -50,7 +60,6 @@ internal MultipartWebRequest(BaseDiscordClient client, RateLimitBucket bucket, U } } - /// /// Represents a multipart HTTP request for stickers. /// @@ -90,8 +99,19 @@ internal sealed class MultipartStickerWebRequest : BaseRestRequest /// The sticker tag. /// The sticker description. /// The ratelimit_wait_override. - internal MultipartStickerWebRequest(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) + internal MultipartStickerWebRequest( + 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 + ) : base(client, bucket, url, method, route, headers, ratelimitWaitOverride) { this.File = file; diff --git a/DisCatSharp/Net/Rest/RestClient.cs b/DisCatSharp/Net/Rest/RestClient.cs index fd085b7872..79972d619a 100644 --- a/DisCatSharp/Net/Rest/RestClient.cs +++ b/DisCatSharp/Net/Rest/RestClient.cs @@ -106,23 +106,23 @@ internal RestClient(BaseDiscordClient client) /// The timeout. /// Whether to use relative ratelimit. /// The logger. - internal RestClient(IWebProxy proxy, TimeSpan timeout, bool useRelativeRatelimit, - ILogger logger) + internal RestClient( + IWebProxy proxy, + TimeSpan timeout, + bool useRelativeRatelimit, + ILogger logger + ) { this._logger = logger; var httphandler = new HttpClientHandler { - UseCookies = false, - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - UseProxy = proxy != null, - Proxy = proxy + UseCookies = false, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, UseProxy = proxy != null, Proxy = proxy }; this.HttpClient = new(httphandler) { - BaseAddress = new(Utilities.GetApiBaseUri(this._discord?.Configuration)), - Timeout = timeout + BaseAddress = new(Utilities.GetApiBaseUri(this._discord?.Configuration)), Timeout = timeout }; this.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", Utilities.GetUserAgent()); @@ -163,10 +163,12 @@ public RateLimitBucket GetBucket(RestRequestMethod method, string route, object rparams[xp.Name] = val is string xs ? xs : val is DateTime dt - ? dt.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) - : val is DateTimeOffset dto - ? dto.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) - : val is IFormattable xf ? xf.ToString(null, CultureInfo.InvariantCulture) : val.ToString(); + ? dt.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) + : val is DateTimeOffset dto + ? dto.ToString("yyyy-MM-ddTHH:mm:sszzz", CultureInfo.InvariantCulture) + : val is IFormattable xf + ? xf.ToString(null, CultureInfo.InvariantCulture) + : val.ToString(); } var guildId = rparams.TryGetValue("guild_id", out var rparam) ? rparam : ""; @@ -225,7 +227,6 @@ public RateLimitBucket GetBucket(RestRequestMethod method, string route, object public Task ExecuteRequestAsync(BaseRestRequest request) => request == null ? throw new ArgumentNullException(nameof(request)) : this.ExecuteRequestAsync(request, null, null); - /// /// Executes the form data request. /// @@ -423,19 +424,12 @@ private async Task ExecuteFormRequestAsync(BaseRestRequest request, RateLimitBuc // If it's 0 or less, we can remove the bucket from the active request queue, // along with any of its past routes. if (count <= 0) - { foreach (var r in bucket.RouteHashes) - { if (this._requestQueue.ContainsKey(r)) - { _ = this._requestQueue.TryRemove(r, out _); - } - } - } } } - /// /// Executes the request. /// This is to allow proper rescheduling of the first request from a bucket. @@ -493,6 +487,7 @@ private async Task ExecuteRequestAsync(BaseRestRequest request, RateLimitBucket return; } + this._logger.LogDebug(LoggerEvents.RatelimitDiag, "Request for {bucket} is allowed. Url: {url}", bucket.ToString(), request.Url.AbsoluteUri); } else @@ -574,19 +569,17 @@ private async Task ExecuteRequestAsync(BaseRestRequest request, RateLimitBucket // we don't want to wait here until all the blocked requests have been run, additionally Set can never throw an exception that could be suppressed here _ = this._globalRateLimitEvent.SetAsync(); } + this.ExecuteRequestAsync(request, bucket, ratelimitTcs) .LogTaskFault(this._logger, LogLevel.Error, LoggerEvents.RestError, "Error while retrying request"); } else { if (this._discord is not null && this._discord is DiscordClient) - { await (this._discord as DiscordClient).RateLimitHitInternal.InvokeAsync(this._discord as DiscordClient, new(this._discord.ServiceProvider) { - Exception = ex as RateLimitException, - ApiEndpoint = request.Url.AbsoluteUri + Exception = ex as RateLimitException, ApiEndpoint = request.Url.AbsoluteUri }); - } this._logger.LogError(LoggerEvents.RatelimitHit, "Ratelimit hit, requeuing request to {url}", request.Url.AbsoluteUri); await wait.ConfigureAwait(false); this.ExecuteRequestAsync(request, bucket, ratelimitTcs) @@ -595,6 +588,7 @@ private async Task ExecuteRequestAsync(BaseRestRequest request, RateLimitBucket return; } + break; case 500: @@ -609,18 +603,21 @@ private async Task ExecuteRequestAsync(BaseRestRequest request, RateLimitBucket if (ex != null) { if (this._discord?.Configuration.EnableSentry ?? false) - { if (senex != null) { Dictionary debugInfo = new() { - { "route", request.Route }, - { "time", DateTimeOffset.UtcNow } + { + "route", request.Route + }, + { + "time", DateTimeOffset.UtcNow + } }; senex.AddSentryContext("Request", debugInfo); this._discord.Sentry.CaptureException(senex); } - } + request.SetFaulted(ex); } else @@ -648,15 +645,9 @@ private async Task ExecuteRequestAsync(BaseRestRequest request, RateLimitBucket // If it's 0 or less, we can remove the bucket from the active request queue, // along with any of its past routes. if (count <= 0) - { foreach (var r in bucket.RouteHashes) - { if (this._requestQueue.ContainsKey(r)) - { _ = this._requestQueue.TryRemove(r, out _); - } - } - } } } @@ -699,7 +690,6 @@ private async Task> WaitForInitialRateLimit(RateLimit while (!bucket.LimitValid) { if (bucket.LimitTesting == 0) - { if (Interlocked.CompareExchange(ref bucket.LimitTesting, 1, 0) == 0) { // if we got here when the first request was just finishing, we must not create the waiter task as it would signal ExecuteRequestAsync to bypass rate limiting @@ -711,7 +701,7 @@ private async Task> WaitForInitialRateLimit(RateLimit bucket.LimitTestFinished = ratelimitsTcs.Task; return ratelimitsTcs; } - } + // it can take a couple of cycles for the task to be allocated, so wait until it happens or we are no longer probing for the limits Task waitTask = null; while (bucket.LimitTesting != 0 && (waitTask = bucket.LimitTestFinished) == null) @@ -793,14 +783,12 @@ private HttpRequestMessage BuildRequest(BaseRestRequest request) var fileId = mprequest.OverwriteFileIdStart ?? 0; if (mprequest.Files != null && mprequest.Files.Any()) - { foreach (var f in mprequest.Files) { var name = $"files[{fileId.ToString(CultureInfo.InvariantCulture)}]"; content.Add(new StreamContent(f.Value), name, f.Key); fileId++; } - } req.Content = content; } @@ -826,10 +814,18 @@ private HttpRequestMessage BuildRequest(BaseRestRequest request) var content = new MultipartFormDataContent(boundary) { - { new StringContent(mpsrequest.Name), "name" }, - { new StringContent(mpsrequest.Tags), "tags" }, - { new StringContent(mpsrequest.Description), "description" }, - { sc, "file", fileName } + { + new StringContent(mpsrequest.Name), "name" + }, + { + new StringContent(mpsrequest.Tags), "tags" + }, + { + new StringContent(mpsrequest.Description), "description" + }, + { + sc, "file", fileName + } }; req.Content = content; @@ -851,6 +847,7 @@ private void Handle429(RestResponse response, out Task waitTask, out bool global if (response.Headers == null) return; + var hs = response.Headers; // handle the wait @@ -862,10 +859,8 @@ private void Handle429(RestResponse response, out Task waitTask, out bool global // check if global b1nzy if (hs.TryGetValue("X-RateLimit-Global", out var isGlobal) && isGlobal.ToLowerInvariant() == "true") - { // global global = true; - } } /// @@ -888,10 +883,7 @@ private void UpdateBucket(BaseRestRequest request, RestResponse response, TaskCo var hs = response.Headers; if (hs.TryGetValue("X-RateLimit-Scope", out var scope)) - { bucket.Scope = scope; - } - if (hs.TryGetValue("X-RateLimit-Global", out var isGlobal) && isGlobal.ToLowerInvariant() == "true") { @@ -1036,7 +1028,7 @@ private async Task CleanupBucketsAsync() { var bucket = this._hashesToBuckets.Values.FirstOrDefault(x => x.RouteHashes.Contains(key)); - if (bucket == null || (bucket != null && bucket.LastAttemptAt.AddSeconds(5) < DateTimeOffset.UtcNow)) + if (bucket == null || bucket != null && bucket.LastAttemptAt.AddSeconds(5) < DateTimeOffset.UtcNow) _ = this._requestQueue.TryRemove(key, out _); } diff --git a/DisCatSharp/Net/Rest/RestRequestMethod.cs b/DisCatSharp/Net/Rest/RestRequestMethod.cs index aa1613e0b3..329ebaa803 100644 --- a/DisCatSharp/Net/Rest/RestRequestMethod.cs +++ b/DisCatSharp/Net/Rest/RestRequestMethod.cs @@ -1,4 +1,3 @@ - // ReSharper disable InconsistentNaming namespace DisCatSharp.Net; diff --git a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs index 77a3d5f114..a0b13ecc50 100644 --- a/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/DiscordComponentJsonConverter.cs @@ -39,7 +39,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return null; var job = JObject.Load(reader); - var type = (job["type"]?.ToObject()) ?? throw new ArgumentException($"Value {reader} does not have a component type specifier"); + var type = job["type"]?.ToObject() ?? throw new ArgumentException($"Value {reader} does not have a component type specifier"); DiscordComponent cmp; cmp = type switch { @@ -52,7 +52,10 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist ComponentType.RoleSelect => new DiscordRoleSelectComponent(), ComponentType.MentionableSelect => new DiscordMentionableSelectComponent(), ComponentType.ChannelSelect => new DiscordChannelSelectComponent(), - _ => new() { Type = type } + _ => new() + { + Type = type + } }; // Populate the existing component with the values in the JObject. This avoids a recursive JsonConverter loop diff --git a/DisCatSharp/Net/Serialization/DiscordJson.cs b/DisCatSharp/Net/Serialization/DiscordJson.cs index 50f8b0892c..efbb7957cd 100644 --- a/DisCatSharp/Net/Serialization/DiscordJson.cs +++ b/DisCatSharp/Net/Serialization/DiscordJson.cs @@ -70,6 +70,7 @@ private static string SerializeObjectInternal(object value, Type type, JsonSeria jsonTextWriter.Formatting = jsonSerializer.Formatting; jsonSerializer.Serialize(jsonTextWriter, value, type); } + return stringWriter.ToString(); } @@ -81,25 +82,26 @@ private static T DeserializeObjectInternal(string json, BaseDiscordClient? di })!; if (discord == null) return obj; + obj.Discord = discord; if (!discord.Configuration.ReportMissingFields || !obj.AdditionalProperties.Any()) return obj; + var sentryMessage = "Found missing properties in api response for " + obj.GetType().Name; List sentryFields = new(); var vals = 0; foreach (var ap in obj.AdditionalProperties) { vals++; - if (obj.IgnoredJsonKeys.Count == 0 || !obj.IgnoredJsonKeys.Any(x => x == ap.Key)) + if (obj.IgnoredJsonKeys.Count == 0 || obj.IgnoredJsonKeys.All(x => x != ap.Key)) { if (vals == 1) - { if (discord.Configuration.EnableLibraryDeveloperMode) { discord.Logger.LogInformation("{sentry}", sentryMessage); discord.Logger.LogDebug("{json}", json); } - } + sentryFields.Add(ap.Key); if (discord.Configuration.EnableLibraryDeveloperMode) discord.Logger.LogInformation("Found field {field} on {object}", ap.Key, obj.GetType().Name); @@ -107,13 +109,12 @@ private static T DeserializeObjectInternal(string json, BaseDiscordClient? di } if (!discord.Configuration.EnableSentry || sentryFields.Count == 0) return obj; + var sentryJson = JsonConvert.SerializeObject(sentryFields); sentryMessage += "\n\nNew fields: " + sentryJson; SentryEvent sentryEvent = new() { - Level = SentryLevel.Warning, - Logger = nameof(DiscordJson), - Message = sentryMessage + Level = SentryLevel.Warning, Logger = nameof(DiscordJson), Message = sentryMessage }; sentryEvent.SetFingerprint(BaseDiscordClient.GenerateSentryFingerPrint(sentryEvent)); sentryEvent.SetExtra("Found Fields", sentryJson); @@ -124,8 +125,12 @@ private static T DeserializeObjectInternal(string json, BaseDiscordClient? di Username = discord.CurrentUser.UsernameWithDiscriminator, Other = new Dictionary() { - { "developer", discord.Configuration.DeveloperUserId?.ToString() ?? "not_given" }, - { "email", discord.Configuration.FeedbackEmail ?? "not_given" } + { + "developer", discord.Configuration.DeveloperUserId?.ToString() ?? "not_given" + }, + { + "email", discord.Configuration.FeedbackEmail ?? "not_given" + } } }; var sid = discord.Sentry.CaptureEvent(sentryEvent); @@ -144,10 +149,12 @@ private static T DeserializeIEnumerableObjectInternal(string json, BaseDiscor })!; if (discord == null) return obj; + foreach (var ob in obj) ob.Discord = discord; if (!discord.Configuration.ReportMissingFields || !obj.Any(x => x.AdditionalProperties.Any())) return obj; + var first = obj.First(); var sentryMessage = "Found missing properties in api response for " + first.GetType().Name; List sentryFields = new(); @@ -158,13 +165,12 @@ private static T DeserializeIEnumerableObjectInternal(string json, BaseDiscor if (first.IgnoredJsonKeys.Count == 0 || !first.IgnoredJsonKeys.Any(x => x == ap.Key)) { if (vals == 1) - { if (discord.Configuration.EnableLibraryDeveloperMode) { discord.Logger.LogInformation("{sentry}", sentryMessage); discord.Logger.LogDebug("{json}", json); } - } + sentryFields.Add(ap.Key); if (discord.Configuration.EnableLibraryDeveloperMode) discord.Logger.LogInformation("Found field {field} on {object}", ap.Key, first.GetType().Name); @@ -172,13 +178,12 @@ private static T DeserializeIEnumerableObjectInternal(string json, BaseDiscor } if (!discord.Configuration.EnableSentry || sentryFields.Count == 0) return obj; + var sentryJson = JsonConvert.SerializeObject(sentryFields); sentryMessage += "\n\nNew fields: " + sentryJson; SentryEvent sentryEvent = new() { - Level = SentryLevel.Warning, - Logger = nameof(DiscordJson), - Message = sentryMessage + Level = SentryLevel.Warning, Logger = nameof(DiscordJson), Message = sentryMessage }; sentryEvent.SetFingerprint(BaseDiscordClient.GenerateSentryFingerPrint(sentryEvent)); sentryEvent.SetExtra("Found Fields", sentryJson); @@ -189,8 +194,12 @@ private static T DeserializeIEnumerableObjectInternal(string json, BaseDiscor Username = discord.CurrentUser.UsernameWithDiscriminator, Other = new Dictionary() { - { "developer", discord.Configuration.DeveloperUserId?.ToString() ?? "not_given" }, - { "email", discord.Configuration.FeedbackEmail ?? "not_given" } + { + "developer", discord.Configuration.DeveloperUserId?.ToString() ?? "not_given" + }, + { + "email", discord.Configuration.FeedbackEmail ?? "not_given" + } } }; var sid = discord.Sentry.CaptureEvent(sentryEvent); diff --git a/DisCatSharp/Net/Serialization/SnowflakeArrayAsDictionaryJsonConverter.cs b/DisCatSharp/Net/Serialization/SnowflakeArrayAsDictionaryJsonConverter.cs index 11eca77177..d6fc01d754 100644 --- a/DisCatSharp/Net/Serialization/SnowflakeArrayAsDictionaryJsonConverter.cs +++ b/DisCatSharp/Net/Serialization/SnowflakeArrayAsDictionaryJsonConverter.cs @@ -30,9 +30,7 @@ internal class SnowflakeArrayAsDictionaryJsonConverter : JsonConverter public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) - { writer.WriteNull(); - } else { var type = value.GetType().GetTypeInfo(); @@ -57,16 +55,14 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // the default name of an indexer is "Item" var properties = objectType.GetTypeInfo().GetDeclaredProperty("Item"); - var entries = (IEnumerable) serializer.Deserialize(reader, objectType.GenericTypeArguments[1].MakeArrayType()); + var entries = (IEnumerable)serializer.Deserialize(reader, objectType.GenericTypeArguments[1].MakeArrayType()); foreach (var entry in entries) - { properties.SetValue(dict, entry, new object[] { (entry as SnowflakeObject)?.Id ?? (entry as DiscordVoiceState)?.UserId ?? throw new InvalidOperationException($"Type {entry?.GetType()} is not deserializable") }); - } return dict; } @@ -83,6 +79,6 @@ public override bool CanConvert(Type objectType) var valueParam = objectType.GenericTypeArguments[1]; return typeof(SnowflakeObject).GetTypeInfo().IsAssignableFrom(valueParam.GetTypeInfo()) || - valueParam == typeof(DiscordVoiceState); + valueParam == typeof(DiscordVoiceState); } } diff --git a/DisCatSharp/Net/Udp/DCSUdpClient.cs b/DisCatSharp/Net/Udp/DCSUdpClient.cs index 2833e84ce2..f4be062f2d 100644 --- a/DisCatSharp/Net/Udp/DCSUdpClient.cs +++ b/DisCatSharp/Net/Udp/DCSUdpClient.cs @@ -26,7 +26,6 @@ internal class DcsUdpClient : BaseUdpClient /// private readonly BlockingCollection _packetQueue; - /// /// Gets the receiver task. /// @@ -104,14 +103,12 @@ public override void Close() private async Task ReceiverLoopAsync() { while (!this.TOKEN.IsCancellationRequested) - { try { var packet = await this._client.ReceiveAsync().ConfigureAwait(false); this._packetQueue.Add(packet.Buffer); } catch (Exception) { } - } } /// diff --git a/DisCatSharp/Net/WebSocket/SocketLock.cs b/DisCatSharp/Net/WebSocket/SocketLock.cs index e8b3ef923c..0a6bed2148 100644 --- a/DisCatSharp/Net/WebSocket/SocketLock.cs +++ b/DisCatSharp/Net/WebSocket/SocketLock.cs @@ -81,6 +81,7 @@ public void UnlockAfter(TimeSpan unlockDelay) this._timeoutCancelSource.Dispose(); } catch { } + this._timeoutCancelSource = null; this._unlockTask = Task.Delay(unlockDelay, CancellationToken.None); diff --git a/DisCatSharp/Net/WebSocket/WebSocketClient.cs b/DisCatSharp/Net/WebSocket/WebSocketClient.cs index 49b0ca63f2..ded4877a0b 100644 --- a/DisCatSharp/Net/WebSocket/WebSocketClient.cs +++ b/DisCatSharp/Net/WebSocket/WebSocketClient.cs @@ -96,7 +96,8 @@ private WebSocketClient(IWebProxy proxy, IServiceProvider provider) public async Task ConnectAsync(Uri uri) { // Disconnect first - try { await this.DisconnectAsync().ConfigureAwait(false); } catch { } + try { await this.DisconnectAsync().ConfigureAwait(false); } + catch { } // Disallow sending messages await this._senderLock.WaitAsync().ConfigureAwait(false); @@ -275,8 +276,7 @@ internal async Task ReceiverLoopAsync() break; bs.Write(buffer.Array, 0, result.Count); - } - while (!result.EndOfMessage); + } while (!result.EndOfMessage); resultBytes = new byte[bs.Length]; bs.Position = 0; @@ -291,13 +291,9 @@ internal async Task ReceiverLoopAsync() } if (result.MessageType == WebSocketMessageType.Binary) - { await this._messageReceived.InvokeAsync(this, new SocketBinaryMessageEventArgs(resultBytes)).ConfigureAwait(false); - } else if (result.MessageType == WebSocketMessageType.Text) - { await this._messageReceived.InvokeAsync(this, new SocketTextMessageEventArgs(Utilities.UTF8.GetString(resultBytes))).ConfigureAwait(false); - } else // close { if (!this._isClientClose) @@ -310,15 +306,24 @@ internal async Task ReceiverLoopAsync() await this._ws.CloseOutputAsync(code, result.CloseStatusDescription, CancellationToken.None).ConfigureAwait(false); } - await this._disconnected.InvokeAsync(this, new(this._serviceProvider) { CloseCode = (int)result.CloseStatus, CloseMessage = result.CloseStatusDescription }).ConfigureAwait(false); + await this._disconnected.InvokeAsync(this, new(this._serviceProvider) + { + CloseCode = (int)result.CloseStatus, CloseMessage = result.CloseStatusDescription + }).ConfigureAwait(false); break; } } } catch (Exception ex) { - await this._exceptionThrown.InvokeAsync(this, new(this._serviceProvider) { Exception = ex }).ConfigureAwait(false); - await this._disconnected.InvokeAsync(this, new(this._serviceProvider) { CloseCode = -1, CloseMessage = "" }).ConfigureAwait(false); + await this._exceptionThrown.InvokeAsync(this, new(this._serviceProvider) + { + Exception = ex + }).ConfigureAwait(false); + await this._disconnected.InvokeAsync(this, new(this._serviceProvider) + { + CloseCode = -1, CloseMessage = "" + }).ConfigureAwait(false); } // Don't await or you deadlock @@ -335,7 +340,8 @@ internal async Task ReceiverLoopAsync() public static IWebSocketClient CreateNew(IWebProxy proxy, IServiceProvider provider) => new WebSocketClient(proxy, provider); - #region Events +#region Events + /// /// Triggered when the client connects successfully. /// @@ -344,6 +350,7 @@ public event AsyncEventHandler Connected add => this._connected.Register(value); remove => this._connected.Unregister(value); } + private readonly AsyncEvent _connected; /// @@ -354,6 +361,7 @@ public event AsyncEventHandler Disconnec add => this._disconnected.Register(value); remove => this._disconnected.Unregister(value); } + private readonly AsyncEvent _disconnected; /// @@ -364,6 +372,7 @@ public event AsyncEventHandler Message add => this._messageReceived.Register(value); remove => this._messageReceived.Unregister(value); } + private readonly AsyncEvent _messageReceived; /// @@ -374,6 +383,7 @@ public event AsyncEventHandler Exception add => this._exceptionThrown.Register(value); remove => this._exceptionThrown.Unregister(value); } + private readonly AsyncEvent _exceptionThrown; private IServiceProvider _serviceProvider; @@ -387,6 +397,10 @@ public event AsyncEventHandler Exception /// The event args. private void EventErrorHandler(AsyncEvent asyncEvent, Exception ex, AsyncEventHandler handler, WebSocketClient sender, TArgs eventArgs) where TArgs : AsyncEventArgs - => this._exceptionThrown.InvokeAsync(this, new(this._serviceProvider) { Exception = ex }).ConfigureAwait(false).GetAwaiter().GetResult(); - #endregion + => this._exceptionThrown.InvokeAsync(this, new(this._serviceProvider) + { + Exception = ex + }).ConfigureAwait(false).GetAwaiter().GetResult(); + +#endregion } diff --git a/DisCatSharp/QueryUriBuilder.cs b/DisCatSharp/QueryUriBuilder.cs index 1d9e681cd1..14c0976480 100644 --- a/DisCatSharp/QueryUriBuilder.cs +++ b/DisCatSharp/QueryUriBuilder.cs @@ -18,6 +18,7 @@ internal class QueryUriBuilder /// Gets the query parameters. /// public IReadOnlyList> QueryParameters => this._queryParams; + private readonly List> _queryParams = new(); /// diff --git a/DisCatSharp/RingBuffer.cs b/DisCatSharp/RingBuffer.cs index af9c729941..d26d751024 100644 --- a/DisCatSharp/RingBuffer.cs +++ b/DisCatSharp/RingBuffer.cs @@ -39,6 +39,7 @@ public bool IsReadOnly /// Gets or sets the internal collection of items. /// protected T[] InternalBuffer { get; set; } + private bool _reachedEnd; /// @@ -110,21 +111,18 @@ public void Add(T item) public bool TryGet(Func predicate, out T item) { for (var i = this.CurrentIndex; i < this.InternalBuffer.Length; i++) - { if (this.InternalBuffer[i] != null && predicate(this.InternalBuffer[i])) { item = this.InternalBuffer[i]; return true; } - } + for (var i = 0; i < this.CurrentIndex; i++) - { if (this.InternalBuffer[i] != null && predicate(this.InternalBuffer[i])) { item = this.InternalBuffer[i]; return true; } - } item = default; return false; @@ -186,13 +184,11 @@ public void CopyTo(T[] array, int index) public bool Remove(Func predicate) { for (var i = 0; i < this.InternalBuffer.Length; i++) - { if (this.InternalBuffer[i] != null && predicate(this.InternalBuffer[i])) { this.InternalBuffer[i] = default; return true; } - } return false; } diff --git a/DisCatSharp/Utilities.cs b/DisCatSharp/Utilities.cs index 20ee7a7e20..3b4fcd1557 100644 --- a/DisCatSharp/Utilities.cs +++ b/DisCatSharp/Utilities.cs @@ -133,7 +133,7 @@ internal static string GetFormattedToken(DiscordConfiguration config) { TokenType.Bearer => $"Bearer {config.Token}", TokenType.Bot => $"Bot {config.Token}", - _ => throw new ArgumentException("Invalid token type specified.", nameof(config)), + _ => throw new ArgumentException("Invalid token type specified.", nameof(config)) }; /// @@ -220,7 +220,7 @@ internal static IEnumerable GetUserMentions(DiscordMessage message) var regex = new Regex(@"<@!?(\d+)>", RegexOptions.ECMAScript | RegexOptions.Compiled); var matches = regex.Matches(message.Content); return from Match match in matches - select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); + select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); } /// @@ -233,7 +233,7 @@ internal static IEnumerable GetRoleMentions(DiscordMessage message) var regex = new Regex(@"<@&(\d+)>", RegexOptions.ECMAScript); var matches = regex.Matches(message.Content); return from Match match in matches - select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); + select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); } /// @@ -246,7 +246,7 @@ internal static IEnumerable GetChannelMentions(DiscordMessage message) var regex = new Regex(@"<#(\d+)>", RegexOptions.ECMAScript); var matches = regex.Matches(message.Content); return from Match match in matches - select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); + select ulong.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); } /// @@ -259,7 +259,7 @@ internal static IEnumerable GetEmojis(DiscordMessage message) var regex = new Regex(@"", RegexOptions.ECMAScript); var matches = regex.Matches(message.Content); return from Match match in matches - select ulong.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture); + select ulong.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture); } /// @@ -279,8 +279,7 @@ internal static bool IsValidSlashCommandName(string name) /// The guild. /// The taad. /// A bool. - [DiscordDeprecated, Deprecated] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] + [DiscordDeprecated, Deprecated, System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] internal static bool CheckThreadAutoArchiveDurationFeature(DiscordGuild guild, ThreadAutoArchiveDuration taad) => true; @@ -289,8 +288,7 @@ internal static bool CheckThreadAutoArchiveDurationFeature(DiscordGuild guild, T /// /// The guild. /// A bool. - [DiscordDeprecated, Deprecated] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] + [DiscordDeprecated, Deprecated, System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "")] internal static bool CheckThreadPrivateFeature(DiscordGuild guild) => true; @@ -404,7 +402,6 @@ public static DateTimeOffset GetSnowflakeTime(this ulong snowflake) public static DateTimeOffset? GetSnowflakeTime(this ulong? snowflake) => snowflake is not null ? DiscordClient.DiscordEpoch.AddMilliseconds(snowflake.Value >> 22) : null; - /// /// Converts this into human-readable format. ///