From 954b9136167bcf6529ce1b4dcb3a29c6e1538f2a Mon Sep 17 00:00:00 2001 From: Still Hsu <341464@gmail.com> Date: Mon, 21 May 2018 11:51:08 +0800 Subject: [PATCH] Squashed commit of the following: commit dece19d89505342e5f8c51317b54be8ce69336c9 Merge: fdaa689a e764dafe Author: Still Hsu <341464@gmail.com> Date: Mon May 21 11:47:47 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commit e764dafe083bf5db62091ac1f6b3d438eee38882 Author: Quahu Date: Sun May 13 15:34:40 2018 +0200 Add ViewChannel to Voice channel permissions (#1059) Previously, Voice channels did not have ViewChannel in their "all" permissions commit 32fc2df21b1840fd913ccce80c0686e8e853b43d Author: Alex Gravely Date: Sat May 12 20:47:44 2018 -0400 Remove unused field in EmbedFieldBuilder. (#1018) commit 39dffe858584d0e9eed750bff6426e9562db4262 Author: Finite Reality Date: Sun May 13 01:46:07 2018 +0100 Audit Logs implementation (#1055) * Copy audit logs impl from old branch and clean up I suck at using git, so I'm gonna use brute force. * Remove unnecessary TODOs Category channels do not provide any new information, and the other I forgot to remove beforehand * Add invite update data, clean up after feedback * Remove TODOs, add WebhookType enum for future use WebhookType is a future-use type, as currently audit logs are the only thing which may return it. commit fdaa689ae8be8e9d2ff5190b6cfed5af244b805b Author: Still Hsu <341464@gmail.com> Date: Wed May 9 06:04:59 2018 +0800 Add explanation for RunMode commit ea82c2537e64d4b75f85d9369e90cb55cfcadcc7 Author: Still Hsu <341464@gmail.com> Date: Tue May 8 16:30:48 2018 +0800 Initial proofread of the articles commit 124f1a267c663fbbb0f2dc23367dd910ae3ba4cc Merge: 25557218 97c89310 Author: Still Hsu <341464@gmail.com> Date: Tue May 8 05:02:01 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commit 97c893107b51de24a38ea03c2f8260030c8fc7f5 Author: Still Hsu <341464@gmail.com> Date: Mon May 7 06:22:49 2018 +0800 Implement GetBanAsync (#1056) commit 25557218dbc9390dbeac108afc153776f52dc26f Author: Still Hsu <341464@gmail.com> Date: Sun May 6 16:11:19 2018 +0800 Add details to SpotifyGame commit c7b236ddf5d7324dd8c1513ccd528a7a45d0031f Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:58:23 2018 +0800 Add more IGuild docs commit 1bb06cc37b7c2312b0ab111da63026a01da01e42 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:40:31 2018 +0800 Replace all langword placements with code block commit ac47d84ea74c81e136434dcc33967fe4cd95c1e6 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:22:17 2018 +0800 Replace langword null to code block null instead - Because DocFX sucks at rendering langword commit 0b15bbc54d15c036f770bab818712956c527b4ee Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:20:34 2018 +0800 Add XML docs commit 65d4e4360eb88e3bc5cc8f0da6135e5ee997af6c Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:57:53 2018 +0800 Add BaseSocketClient docs commit 8f64c045999c1bb0440bdc818f082e7459756b36 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:37:55 2018 +0800 Replace note block commit d8bb9e7aaa1e908ceb9227285c0cebec9add5280 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:31:50 2018 +0800 Add warning for bulk-delete endpoint commit adae5ffc9e42343f170d6c869644637587330b59 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:07:28 2018 +0800 Fix missing Username prop commit 3e591972cafdffb6692a1b94cf9a63251188df8b Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:01:34 2018 +0800 Add properties examples to overwrite commit 0ad66f6765addf6d4d25dfbddadeaa542d461403 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 04:55:15 2018 +0800 Fix minor consistencies & redundant impl commit 124efdf7e66ee070fbcdde07ed4f20c717c9c1c0 Author: Still Hsu <341464@gmail.com> Date: Sun May 6 04:40:14 2018 +0800 XML Docs commit 3aa5d363de335444558fdb4bf1bf48a5743bc917 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 18:22:46 2018 +0800 Add 'last modified' plugin Source: https://github.com/Still34/DocFx.Plugin.LastModified Licensed under MIT License commit 2014870dc05dedb6171338d8ae4329eaa4c73f90 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:57:40 2018 +0800 Fix letter-casing for files commit f27d659ebeb88348e24e759308933e3983831ad7 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:50:00 2018 +0800 Document exposed TypeReaders commit 5a824a5695d72a62e28e0a307a5be446557291be Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:44:15 2018 +0800 Add missing exceptions commit c2de0c055f3894c795ea7d7da774fb006c752898 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:40:16 2018 +0800 Fix seealso for preconditions and add missing descriptions commit 3a7d7ee9552a2c6fea1c32b6f3cd91f6efdd29f5 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:36:22 2018 +0800 Minor fixes in documentations + Fix unescaped '<' + Fix typo commit 45839bd982a822dd9da10ceb48989fdb2cd8cd85 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:29:47 2018 +0800 Add XML Docs commit 9e6254600cd7bb5b7626025492223717f92501f9 Merge: aea06788 bb4bb138 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 14:48:13 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commit aea067884c81832ad6cd910ff56c550cf3ecad75 Merge: 27dc4831 9ddd7090 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:51:07 2018 +0800 Merge branch 'docs/faq-n-patches-offline' of https://github.com/Still34/Discord.Net into docs/faq-n-patches-offline commit 27dc4831e88c952f3ea1f68b18434e16197fdfa9 Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:50:27 2018 +0800 Add XML Docs commit baa8beb3824ed59fb50d269b9e13721fa9f5a04e Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:49:42 2018 +0800 Add XML Docs commit 089f97a0101a4ef9194f65b2d4435c0c69dfa87c Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:43:04 2018 +0800 Add details regarding userbot support commit bb4bb138460cc1e6bac53b4e838893dcfd812ce7 Author: Finite Reality Date: Fri May 4 11:42:54 2018 +0100 Fix issues with #984, remove extraneous whitespace (#1051) - Removed unnecessary parameter in SocketVoiceServer - Moved SocketVoiceServer into Entities/Voice - Fixed a bug where trying to download the cached guild would throw - Fixed a potential bug where Discord might not give us a port when connecting to voice commit 9ddd70906aa01015fc76bc2401868e044c4c7cc1 Merge: f197174f 7cfed7ff Author: Still Hsu <341464@gmail.com> Date: Fri May 4 09:37:04 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commit f197174fcc2df1e092b26cd2c8087b602ffb1960 Author: Still Hsu <341464@gmail.com> Date: Fri May 4 09:36:53 2018 +0800 Fix embed docs consistency commit 7cfed7ff67ac9aee517de4130d9ccf504791ed61 Author: Alex Gravely Date: Thu May 3 21:30:13 2018 -0400 Fix nullref when passing null to GetShardIdFor. (#1049) commit e775853b1b26eaf80e6e76c295b44ca6241eaee7 Author: Luke Date: Fri May 4 02:29:51 2018 +0100 Expose VoiceServerUpdate events (#984) * Expose VoiceServerUpdate events * Amend based on feedback * Move this out of guild entity * Fix namespace issue * Adjust based on feedback #2 * Use cacheable instead * Change based on feedback commit 157acc46955d52809b959b52fb1a04404a6df3a5 Author: Still Hsu <341464@gmail.com> Date: Thu May 3 23:03:35 2018 +0800 Add tag examples commit 57ea571a8115f4b768c2dbbe1f2ef807b0cfd647 Author: Still Hsu <341464@gmail.com> Date: Thu May 3 22:48:33 2018 +0800 Fix sample link & add missing pictures commit 6769c37ad7e664845948c50ce403217a9951ef07 Author: Still Hsu <341464@gmail.com> Date: Thu May 3 22:39:26 2018 +0800 Compress some assets & add OAuth2 URL generator --- .../PreconditionAttribute.Overwrites.md | 8 +- .../Common/ObjectProperties.Overwrites.md | 174 ++++++++++++++++++ .../plugins/LastModifiedPostProcessor.dll | Bin 0 -> 7168 bytes docs/docfx.json | 5 +- docs/faq/basics/basic-operations.md | 8 +- docs/faq/basics/client-basics.md | 20 +- docs/faq/basics/getting-started.md | 28 +-- .../faq/commands/{Commands.md => commands.md} | 109 ++++++----- docs/faq/commands/samples/Remainder.cs | 2 +- docs/faq/misc/{Glossary.md => glossary.md} | 0 docs/faq/misc/{Legacy.md => legacy.md} | 4 +- docs/guides/commands/intro.md | 2 +- docs/guides/commands/post-execution.md | 36 ++-- docs/guides/concepts/connections.md | 14 +- docs/guides/concepts/deployment.md | 4 +- docs/guides/concepts/entities.md | 2 +- docs/guides/concepts/events.md | 2 +- docs/guides/concepts/logging.md | 2 +- docs/guides/getting_started/first-bot.md | 17 +- .../images/install-vs-nuget.png | Bin 119670 -> 49542 bytes .../images/intro-client-id.png | Bin 5109 -> 0 bytes .../images/intro-copy-oauth.png | Bin 0 -> 20319 bytes .../images/intro-create-app.png | Bin 52035 -> 23986 bytes .../images/intro-create-bot.png | Bin 45743 -> 20044 bytes .../images/intro-generate-oauth.png | Bin 0 -> 9008 bytes docs/guides/getting_started/installing.md | 2 +- docs/guides/getting_started/terminology.md | 6 +- docs/guides/introduction/intro.md | 4 +- .../ParameterPreconditionAttribute.cs | 1 + .../Attributes/PreconditionAttribute.cs | 15 +- .../RequireUserPermissionAttribute.cs | 6 +- src/Discord.Net.Commands/CommandService.cs | 6 +- .../Readers/ChannelTypeReader.cs | 8 +- .../Readers/MessageTypeReader.cs | 9 +- .../Readers/RoleTypeReader.cs | 5 + .../Readers/TypeReader.cs | 14 +- .../Readers/UserTypeReader.cs | 9 +- .../Results/RuntimeResult.cs | 2 +- src/Discord.Net.Core/CDN.cs | 70 ++++++- src/Discord.Net.Core/DiscordConfig.cs | 54 +++++- .../Entities/Activities/GameAsset.cs | 2 +- .../Entities/Activities/SpotifyGame.cs | 33 ++++ .../Entities/AuditLogs/ActionType.cs | 50 +++++ .../Entities/AuditLogs/IAuditLogData.cs | 14 ++ .../Entities/AuditLogs/IAuditLogEntry.cs | 34 ++++ .../Channels/GuildChannelProperties.cs | 9 +- .../Entities/Channels/IGuildChannel.cs | 14 +- .../Entities/Channels/IMessageChannel.cs | 19 +- .../Entities/Channels/ITextChannel.cs | 16 +- .../Entities/Channels/IVoiceChannel.cs | 2 +- .../Channels/TextChannelProperties.cs | 3 + .../Channels/VoiceChannelProperties.cs | 2 +- .../Entities/Emotes/EmoteProperties.cs | 1 + .../Entities/Guilds/GuildEmbedProperties.cs | 4 +- .../Entities/Guilds/GuildProperties.cs | 17 +- .../Entities/Guilds/IGuild.cs | 160 +++++++++++----- .../Entities/Guilds/IUserGuild.cs | 4 +- .../Entities/Guilds/IVoiceRegion.cs | 8 +- src/Discord.Net.Core/Entities/Image.cs | 2 +- .../Entities/Invites/IInviteMetadata.cs | 8 +- .../Entities/Messages/EmbedAuthor.cs | 2 +- .../Entities/Messages/EmbedBuilder.cs | 17 +- .../Entities/Messages/EmbedField.cs | 2 +- .../Entities/Messages/EmbedVideo.cs | 4 +- .../Entities/Messages/IAttachment.cs | 35 +++- .../Entities/Messages/IEmbed.cs | 64 +++++-- .../Entities/Messages/IMessage.cs | 29 ++- .../Entities/Messages/ISystemMessage.cs | 2 +- .../Entities/Messages/IUserMessage.cs | 2 +- .../Entities/Messages/MessageProperties.cs | 18 +- .../Entities/Messages/ReactionMetadata.cs | 2 +- .../Entities/Messages/TagHandling.cs | 48 +++-- .../Permissions/ChannelPermissions.cs | 44 ++--- .../Entities/Permissions/GuildPermissions.cs | 56 +++--- src/Discord.Net.Core/Entities/Roles/Color.cs | 15 +- src/Discord.Net.Core/Entities/Roles/IRole.cs | 12 +- .../Entities/Roles/RoleProperties.cs | 11 +- .../Entities/Users/GuildUserProperties.cs | 16 +- .../Entities/Users/ISelfUser.cs | 4 +- src/Discord.Net.Core/Entities/Users/IUser.cs | 21 ++- .../Entities/Users/IVoiceState.cs | 12 +- .../Entities/Users/SelfUserProperties.cs | 10 +- .../Entities/Webhooks/WebhookProperties.cs | 11 +- .../Entities/Webhooks/WebhookType.cs | 14 ++ .../Extensions/UserExtensions.cs | 60 +++++- src/Discord.Net.Core/IDiscordClient.cs | 31 +++- src/Discord.Net.Core/Net/HttpException.cs | 2 +- src/Discord.Net.Core/RequestOptions.cs | 2 +- src/Discord.Net.Core/Utils/Cacheable.cs | 2 +- .../Utils/ConcurrentHashSet.cs | 10 +- src/Discord.Net.Core/Utils/MentionUtils.cs | 9 + src/Discord.Net.Rest/API/Common/AuditLog.cs | 16 ++ .../API/Common/AuditLogChange.cs | 17 ++ .../API/Common/AuditLogEntry.cs | 26 +++ .../API/Common/AuditLogOptions.cs | 27 +++ .../API/Rest/GetAuditLogsParams.cs | 8 + src/Discord.Net.Rest/DiscordRestApiClient.cs | 29 +++ .../Entities/AuditLogs/AuditLogHelper.cs | 58 ++++++ .../AuditLogs/DataTypes/BanAuditLogData.cs | 23 +++ .../DataTypes/ChannelCreateAuditLogData.cs | 52 ++++++ .../DataTypes/ChannelDeleteAuditLogData.cs | 45 +++++ .../AuditLogs/DataTypes/ChannelInfo.cs | 18 ++ .../DataTypes/ChannelUpdateAuditLogData.cs | 45 +++++ .../DataTypes/EmoteCreateAuditLogData.cs | 31 ++++ .../DataTypes/EmoteDeleteAuditLogData.cs | 28 +++ .../DataTypes/EmoteUpdateAuditLogData.cs | 31 ++++ .../Entities/AuditLogs/DataTypes/GuildInfo.cs | 32 ++++ .../DataTypes/GuildUpdateAuditLogData.cs | 79 ++++++++ .../DataTypes/InviteCreateAuditLogData.cs | 55 ++++++ .../DataTypes/InviteDeleteAuditLogData.cs | 55 ++++++ .../AuditLogs/DataTypes/InviteInfo.cs | 20 ++ .../DataTypes/InviteUpdateAuditLogData.cs | 46 +++++ .../AuditLogs/DataTypes/KickAuditLogData.cs | 23 +++ .../DataTypes/MemberRoleAuditLogData.cs | 50 +++++ .../DataTypes/MemberUpdateAuditLogData.cs | 35 ++++ .../DataTypes/MessageDeleteAuditLogData.cs | 22 +++ .../DataTypes/OverwriteCreateAuditLogData.cs | 37 ++++ .../DataTypes/OverwriteDeleteAuditLogData.cs | 42 +++++ .../DataTypes/OverwriteUpdateAuditLogData.cs | 44 +++++ .../AuditLogs/DataTypes/PruneAuditLogData.cs | 22 +++ .../DataTypes/RoleCreateAuditLogData.cs | 47 +++++ .../DataTypes/RoleDeleteAuditLogData.cs | 47 +++++ .../Entities/AuditLogs/DataTypes/RoleInfo.cs | 21 +++ .../DataTypes/RoleUpdateAuditLogData.cs | 62 +++++++ .../AuditLogs/DataTypes/UnbanAuditLogData.cs | 23 +++ .../DataTypes/WebhookCreateAuditLogData.cs | 44 +++++ .../DataTypes/WebhookDeleteAuditLogData.cs | 46 +++++ .../AuditLogs/DataTypes/WebhookInfo.cs | 16 ++ .../DataTypes/WebhookUpdateAuditLogData.cs | 52 ++++++ .../Entities/AuditLogs/RestAuditLogEntry.cs | 38 ++++ .../Entities/Channels/ChannelHelper.cs | 2 +- .../Entities/Channels/IRestMessageChannel.cs | 67 ++++++- .../Entities/Channels/RestGroupChannel.cs | 26 +++ .../Entities/Guilds/GuildHelper.cs | 49 ++++- .../Entities/Guilds/RestGuild.cs | 30 ++- .../Entities/Messages/Attachment.cs | 11 +- .../Entities/RestApplication.cs | 2 +- .../Entities/Users/RestGuildUser.cs | 2 +- .../Audio/AudioClient.cs | 2 +- .../BaseSocketClient.Events.cs | 7 + src/Discord.Net.WebSocket/BaseSocketClient.cs | 72 ++++++-- .../DiscordShardedClient.cs | 2 +- .../DiscordSocketClient.cs | 67 ++++--- .../DiscordSocketConfig.cs | 2 +- .../Channels/ISocketMessageChannel.cs | 52 +++++- .../Channels/SocketCategoryChannel.cs | 1 + .../Entities/Channels/SocketDMChannel.cs | 4 +- .../Entities/Channels/SocketGroupChannel.cs | 3 +- .../Entities/Channels/SocketGuildChannel.cs | 6 +- .../Entities/Channels/SocketTextChannel.cs | 4 +- .../Entities/Guilds/SocketGuild.cs | 83 ++++++--- .../Entities/Messages/MessageCache.cs | 8 +- .../Entities/Messages/SocketMessage.cs | 50 ++++- .../Entities/Messages/SocketReaction.cs | 33 ++++ .../Entities/Messages/SocketSystemMessage.cs | 3 + .../Entities/Messages/SocketUserMessage.cs | 3 + .../Entities/Users/SocketGlobalUser.cs | 5 +- .../Entities/Users/SocketGroupUser.cs | 1 + .../Entities/Users/SocketGuildUser.cs | 3 +- .../Entities/Users/SocketSelfUser.cs | 1 + .../Entities/Users/SocketUnknownUser.cs | 1 + .../Entities/Users/SocketVoiceState.cs | 2 +- .../Entities/Users/SocketWebhookUser.cs | 1 + .../Entities/Voice/SocketVoiceServer.cs | 42 +++++ 164 files changed, 3109 insertions(+), 567 deletions(-) create mode 100644 docs/_overwrites/Common/ObjectProperties.Overwrites.md create mode 100644 docs/_template/lastmodified/plugins/LastModifiedPostProcessor.dll rename docs/faq/commands/{Commands.md => commands.md} (55%) rename docs/faq/misc/{Glossary.md => glossary.md} (100%) rename docs/faq/misc/{Legacy.md => legacy.md} (83%) delete mode 100644 docs/guides/getting_started/images/intro-client-id.png create mode 100644 docs/guides/getting_started/images/intro-copy-oauth.png create mode 100644 docs/guides/getting_started/images/intro-generate-oauth.png create mode 100644 src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs create mode 100644 src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs create mode 100644 src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs create mode 100644 src/Discord.Net.Core/Entities/Webhooks/WebhookType.cs create mode 100644 src/Discord.Net.Rest/API/Common/AuditLog.cs create mode 100644 src/Discord.Net.Rest/API/Common/AuditLogChange.cs create mode 100644 src/Discord.Net.Rest/API/Common/AuditLogEntry.cs create mode 100644 src/Discord.Net.Rest/API/Common/AuditLogOptions.cs create mode 100644 src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/UnbanAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Voice/SocketVoiceServer.cs diff --git a/docs/_overwrites/Commands/PreconditionAttribute.Overwrites.md b/docs/_overwrites/Commands/PreconditionAttribute.Overwrites.md index 8117b2c3f..75b9f93a5 100644 --- a/docs/_overwrites/Commands/PreconditionAttribute.Overwrites.md +++ b/docs/_overwrites/Commands/PreconditionAttribute.Overwrites.md @@ -1,7 +1,5 @@ --- uid: Discord.Commands.PreconditionAttribute -seealso: - - linkId: Discord.Commands.ParameterPreconditionAttribute remarks: *content --- @@ -12,8 +10,6 @@ method-level for a command. --- uid: Discord.Commands.ParameterPreconditionAttribute -seealso: - - linkId: Discord.Commands.PreconditionAttribute remarks: *content --- @@ -31,11 +27,11 @@ The following example creates a precondition to see if the user has sufficient role required to access the command. ```cs -public class RequireRoleAtribute : PreconditionAttribute +public class RequireRoleAttribute : PreconditionAttribute { private readonly ulong _roleId; - public RequireRoleAtribute(ulong roleId) + public RequireRoleAttribute(ulong roleId) { _roleId = roleId; } diff --git a/docs/_overwrites/Common/ObjectProperties.Overwrites.md b/docs/_overwrites/Common/ObjectProperties.Overwrites.md new file mode 100644 index 000000000..e9c365d39 --- /dev/null +++ b/docs/_overwrites/Common/ObjectProperties.Overwrites.md @@ -0,0 +1,174 @@ +--- +uid: Discord.GuildChannelProperties +example: [*content] +--- + +The following example uses @Discord.IGuildChannel.ModifyAsync* to +apply changes specified in the properties, + +```cs +var channel = _client.GetChannel(id) as IGuildChannel; +if (channel == null) return; + +await channel.ModifyAsync(x => +{ + x.Name = "new-name"; + x.Position = channel.Position - 1; +}); +``` + +--- +uid: Discord.TextChannelProperties +example: [*content] +--- + +The following example uses @Discord.ITextChannel.ModifyAsync* to +apply changes specified in the properties, + +```cs +var channel = _client.GetChannel(id) as ITextChannel; +if (channel == null) return; + +await channel.ModifyAsync(x => +{ + x.Name = "cool-guys-only"; + x.Topic = "This channel is only for cool guys and adults!!!"; + x.Position = channel.Position - 1; + x.IsNsfw = true; +}); +``` + +--- +uid: Discord.VoiceChannelProperties +example: [*content] +--- + +The following example uses @Discord.IVoiceChannel.ModifyAsync* to +apply changes specified in the properties, + +```cs +var channel = _client.GetChannel(id) as IVoiceChannel; +if (channel == null) return; + +await channel.ModifyAsync(x => +{ + x.UserLimit = 5; +}); +``` + +--- +uid: Discord.EmoteProperties +example: [*content] +--- + +The following example uses @Discord.IGuild.ModifyEmoteAsync* to +apply changes specified in the properties, + +```cs +await guild.ModifyEmoteAsync(x => +{ + x.Name = "blobo"; +}); +``` + +--- +uid: Discord.MessageProperties +example: [*content] +--- + +The following example uses @Discord.IUserMessage.ModifyAsync* to +apply changes specified in the properties, + +```cs +var message = await channel.SendMessageAsync("boo"); +await Task.Delay(TimeSpan.FromSeconds(1)); +await message.ModifyAsync(x => x.Content = "boi"); +``` + +--- +uid: Discord.GuildProperties +example: [*content] +--- + +The following example uses @Discord.IGuild.ModifyAsync* to +apply changes specified in the properties, + +```cs +var guild = _client.GetGuild(id); +if (guild == null) return; + +await guild.ModifyAsync(x => +{ + x.Name = "VERY Fast Discord Running at Incredible Hihg Speed"; +}); +``` + +--- +uid: Discord.RoleProperties +example: [*content] +--- + +The following example uses @Discord.IRole.ModifyAsync* to +apply changes specified in the properties, + +```cs +var role = guild.GetRole(id); +if (role == null) return; + +await role.ModifyAsync(x => +{ + x.Name = "cool boi"; + x.Color = Color.Gold; + x.Hoist = true; + x.Mentionable = true; +}); +``` + +--- +uid: Discord.GuildUserProperties +example: [*content] +--- + +The following example uses @Discord.IGuildUser.ModifyAsync* to +apply changes specified in the properties, + +```cs +var user = guild.GetUser(id); +if (user == null) return; + +await user.ModifyAsync(x => +{ + x.Nickname = "I need healing"; +}); +``` + +--- +uid: Discord.SelfUserProperties +example: [*content] +--- + +The following example uses @Discord.ISelfUser.ModifyAsync* to +apply changes specified in the properties, + +```cs +await selfUser.ModifyAsync(x => +{ + x.Username = "Mercy"; +}); +``` + +--- +uid: Discord.WebhookProperties +example: [*content] +--- + +The following example uses @Discord.IWebhook.ModifyAsync* to +apply changes specified in the properties, + +```cs +await webhook.ModifyAsync(x => +{ + x.Name = "very fast fox"; + x.ChannelId = newChannelId; +}); +``` \ No newline at end of file diff --git a/docs/_template/lastmodified/plugins/LastModifiedPostProcessor.dll b/docs/_template/lastmodified/plugins/LastModifiedPostProcessor.dll new file mode 100644 index 0000000000000000000000000000000000000000..c527ec698d2621ceccdec139a60ba2e4e9114250 GIT binary patch literal 7168 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 literal 0 HcmV?d00001 diff --git a/docs/docfx.json b/docs/docfx.json index ccd271999..cb6a36360 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -35,9 +35,10 @@ "dest": "_site", "template": [ "default", - "_template/light-dark-theme" + "_template/light-dark-theme", + "_template/lastmodified" ], - "postProcessors": [ "ExtractSearchIndex" ], + "postProcessors": [ "ExtractSearchIndex", "LastModifiedPostProcessor" ], "overwrite": "_overwrites/**/**.md", "globalMetadata": { "_appTitle": "Discord.Net Documentation", diff --git a/docs/faq/basics/basic-operations.md b/docs/faq/basics/basic-operations.md index 518a7426d..aef28a683 100644 --- a/docs/faq/basics/basic-operations.md +++ b/docs/faq/basics/basic-operations.md @@ -8,7 +8,7 @@ title: Questions about Basic Operations ## How should I safely check a type? > [!WARNING] -> Direct casting (e.g. `(Type)type`) is **the least recommended** +> Direct casting (e.g., `(Type)type`) is **the least recommended** > way of casting, as it *can* throw an [InvalidCastException] > when the object isn't the desired type. > @@ -28,9 +28,9 @@ A good and safe casting example: ## How do I send a message? > [!TIP] -> The [GetChannel] method by default returns an [IChannel]. -> This means channels such as [IVoiceChannel], [ICategoryChannel] -> can be returned. This is why that you cannot send message +> The [GetChannel] method by default returns an [IChannel], allowing +> channel types such as [IVoiceChannel], [ICategoryChannel] +> to be returned; consequently, you cannot send a message > to channels like those. Any implementation of [IMessageChannel] has a [SendMessageAsync] diff --git a/docs/faq/basics/client-basics.md b/docs/faq/basics/client-basics.md index 376667ca0..48386206c 100644 --- a/docs/faq/basics/client-basics.md +++ b/docs/faq/basics/client-basics.md @@ -8,11 +8,12 @@ title: Basic Questions about Client ## My client keeps returning 401 upon logging in! > [!WARNING] -> Userbot/selfbot (logging in with a user token) is not -> officially supported with this library. +> Userbot/selfbot (logging in with a user token) is no +> longer supported with this library starting from 2.0, as +> logging in under a user account may result in account termination. > -> Logging in under a user account may result in account -> termination! +> For more information, see issue [827] & [958], as well as the official +> [Discord API Terms of Service]. There are few possible reasons why this may occur. @@ -20,20 +21,23 @@ There are few possible reasons why this may occur. bot account created from the Discord Developer portal, you should be using `TokenType.Bot`. 2. You are not using the correct login credentials. Please keep in - mind that tokens is different from a *client secret*. + mind that a token is **different** from a *client secret*. [TokenType]: xref:Discord.TokenType +[827]: https://github.com/RogueException/Discord.Net/issues/827 +[958]: https://github.com/RogueException/Discord.Net/issues/958 +[Discord API Terms of Service]: https://discordapp.com/developers/docs/legal ## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect? Your bot should **not** attempt to interact in any way with guilds/servers until the [Ready] event fires. When the bot connects, it first has to download guild information from -Discord in order for you to get access to any server +Discord for you to get access to any server information; the client is not ready at this point. Technically, the [GuildAvailable] event fires once the data for a -particular guild has downloaded; however, it's best to wait for all +particular guild has downloaded; however, it is best to wait for all guilds to be downloaded. Once all downloads are complete, the [Ready] event is triggered, then you can proceed to do whatever you like. @@ -42,7 +46,7 @@ event is triggered, then you can proceed to do whatever you like. ## How do I get a message's previous content when that message is edited? -If you need to do anything with messages (e.g. checking Reactions, +If you need to do anything with messages (e.g., checking Reactions, checking the content of edited/deleted messages), you must set the [MessageCacheSize] in your [DiscordSocketConfig] settings in order to use the cached message entity. Read more about it [here](xref:Guides.Concepts.Events#cacheable). diff --git a/docs/faq/basics/getting-started.md b/docs/faq/basics/getting-started.md index 08972ba2e..6e39aeed0 100644 --- a/docs/faq/basics/getting-started.md +++ b/docs/faq/basics/getting-started.md @@ -8,25 +8,27 @@ title: Beginner Questions / How to Get Started ## How do I add my bot to my server/guild? You can do so by using the [permission calculator] provided -by FiniteReality. -This tool allows you to set the permissions that the bot will be -added with, and invite the bot into your guild. With this method, -bots will also be assigned their own special roles that normal users -cannot use; this is what we call a `Managed` role, and this is a much -safer method of permission management than to create a role that any -users can be assigned to. - +by [FiniteReality]. +This tool allows you to set permissions that the bot will be assigned +with, and invite the bot into your guild. With this method, bots will +also be assigned a unique role that a regular user cannot use; this +is what we call a `Managed` role. Because you cannot assign this +role to any other users, it is much safer than creating a single +role which, intentionally or not, can be applied to other users +to escalate their privilege. + +[FiniteReality]: https://github.com/FiniteReality/permissions-calculator [permission calculator]: https://finitereality.github.io/permissions-calculator ## What is a token? A token is a credential used to log into an account. This information should be kept **private** and for your eyes only. Anyone with your -token can log into your account. This applies to both user and bot -accounts. That also means that you should never ever hardcode your -token or add it into source control, as your identity may be stolen -by scrape bots on the internet that scours through constantly to -obtain a token. +token can log into your account. This risk applies to both user +and bot accounts. That also means that you should **never** hardcode +your token or add it into source control, as your identity may be +stolen by scrape bots on the internet that scours through +constantly to obtain a token. ## What is a client/user/object ID? diff --git a/docs/faq/commands/Commands.md b/docs/faq/commands/commands.md similarity index 55% rename from docs/faq/commands/Commands.md rename to docs/faq/commands/commands.md index 4811b02be..2c905eaad 100644 --- a/docs/faq/commands/Commands.md +++ b/docs/faq/commands/commands.md @@ -5,37 +5,35 @@ title: Questions about Commands # Command-related Questions -## How can I restrict some of my commands so only certain users can execute them? +## How can I restrict some of my commands so only specific users can execute them? Based on how you want to implement the restrictions, you can use the built-in [RequireUserPermission] precondition, which allows you to restrict the command based on the user's current permissions in the -guild or channel (*e.g. `GuildPermission.Administrator`, -`ChannelPermission.ManageMessages` etc.*). +guild or channel (*e.g., `GuildPermission.Administrator`, +`ChannelPermission.ManageMessages`*). If, however, you wish to restrict the commands based on the user's -role, you can either create your own custom precondition or use +role, you can either create your custom precondition or use Joe4evr's [Preconditions Addons] that provides a few custom preconditions that aren't provided in the stock library. -Its source can also be used as an example for creating your own +Its source can also be used as an example for creating your custom preconditions. [RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute [Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions -## I'm getting an error about `Assembly#GetEntryAssembly`. +## Why am I getting an error about `Assembly.GetEntryAssembly`? -You may be confusing [CommandService#AddModulesAsync] with -[CommandService#AddModuleAsync]. The former is used to add modules -via the assembly, while the latter is used to add a single module. - -[CommandService#AddModulesAsync]: xref:Discord.Commands.CommandService.AddModulesAsync* -[CommandService#AddModuleAsync]: xref:Discord.Commands.CommandService.AddModuleAsync* +You may be confusing @Discord.Commands.CommandService.AddModulesAsync* +with @Discord.Commands.CommandService.AddModuleAsync*. The former +is used to add modules via the assembly, while the latter is used to +add a single module. ## What does [Remainder] do in the command signature? The [RemainderAttribute] leaves the string unparsed, meaning you -don't have to add quotes around the text for the text to be +do not have to add quotes around the text for the text to be recognized as a single object. Please note that if your method has multiple parameters, the remainder attribute can only be applied to the last parameter. @@ -47,13 +45,14 @@ the last parameter. ## What is a service? Why does my module not hold any data after execution? In Discord.Net, modules are created similarly to ASP.NET, meaning -that they have a transient nature. This means that they are spawned -every time when a request is received, and are killed from memory -when the execution finishes. This is why you cannot store persistent -data inside a module. To workaround this, consider using a service. - -Service is often used to hold data externally, so that they will -persist throughout execution. Think of it like a chest that holds +that they have a transient nature; modules are spawned whenever a +request is received, and are killed from memory when the execution +finishes. In other words, you cannot store persistent +data inside a module. Consider using a service if you wish to +workaround this. + +Service is often used to hold data externally so that they persist +throughout execution. Think of it like a chest that holds whatever you throw at it that won't be affected by anything unless you want it to. Note that you should also learn Microsoft's implementation of [Dependency Injection] \([video]) before proceeding, @@ -66,25 +65,47 @@ A brief example of service and dependency injection can be seen below. [Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection [video]: https://www.youtube.com/watch?v=QtDTfn8YxXg -## I have a long-running Task in my command, and Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway. What gives? +## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do? + +By default, the library warns the user about any long-running event +handler that persists for **more than 3 seconds**. Any event +handlers that are run on the same thread as the gateway task, the task +in charge of keeping the connection alive, may block the processing of +heartbeat, and thus terminating the connection. + +In this case, the library detects that a `MessageReceived` +event handler is blocking the gateway thread. This warning is +typically associated with the command handler as it listens for that +particular event. If the command handler is blocking the thread, then +this **might** mean that you have a long-running command. -By default, all commands are executed on the same thread as the -gateway task, which is responsible for keeping the connection from -your client to Discord alive. When you execute a command, -this blocks the gateway from communicating for as long as the command -task is being executed. The library will warn you about any long -running event handler (in this case, the command handler) that -persists for **more than 3 seconds**. +> [!NOTE] +> In rare cases, runtime errors can also cause blockage, usually +> associated with Mono, which is not supported by this library. -To resolve this, the library has designed a flag called [RunMode]. +To prevent a long-running command from blocking the gateway +thread, a flag called [RunMode] is explicitly designed to resolve +this issue. There are 2 main `RunMode`s. -1. `RunMode.Sync` (default) +1. `RunMode.Sync` 2. `RunMode.Async` +`Sync` is the default behavior and makes the command to be run on the +same thread as the gateway one. `Async` will spin the task off to a +different thread from the gateway one. + +> [!IMPORTANT] +> While specifying `RunMode.Async` allows the command to be spun off +> to a different thread, keep in mind that by doing so, there will be +> **potentially unwanted consequences**. Before applying this flag, +> please consider whether it is necessary to do so. +> +> Further details regarding `RunMode.Async` can be found below. + You can set the `RunMode` either by specifying it individually via -the `CommandAttribute`, or by setting the global default with +the `CommandAttribute` or by setting the global default with the [DefaultRunMode] flag under `CommandServiceConfig`. # [CommandAttribute](#tab/cmdattrib) @@ -99,15 +120,6 @@ the [DefaultRunMode] flag under `CommandServiceConfig`. *** -> [!IMPORTANT] -> While specifying `RunMode.Async` allows the command to be spun off -> to a different thread instead of the gateway thread, -> keep in mind that there will be **potential consequences** -> by doing so. Before applying this flag, please -> consider whether it is necessary to do so. -> -> Further details regarding `RunMode.Async` can be found below. - [RunMode]: xref:Discord.Commands.RunMode [CommandAttribute]: xref:Discord.Commands.CommandAttribute [DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode @@ -115,16 +127,15 @@ the [DefaultRunMode] flag under `CommandServiceConfig`. ## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default? `RunMode.Async` works by spawning a new `Task` with an unawaited -[Task.Run], essentially making `ExecuteAsyncInternalAsync`, the task -that is used to invoke the command task, to be finished on a -different thread. This means that [ExecuteAsync] will be forced to -return a successful [ExecuteResult] regardless of the actual -execution result. +[Task.Run], essentially making the task that is used to invoke the +command task to be finished on a different thread. This design means +that [ExecuteAsync] will be forced to return a successful +[ExecuteResult] regardless of the actual execution result. The following are the known caveats with `RunMode.Async`, -1. You can potentially introduce race condition. -2. Unnecessary overhead caused by [async state machine]. +1. You can potentially introduce a race condition. +2. Unnecessary overhead caused by the [async state machine]. 3. [ExecuteAsync] will immediately return [ExecuteResult] instead of other result types (this is particularly important for those who wish to utilize [RuntimeResult] in 2.0). @@ -137,7 +148,7 @@ For #3, in Discord.Net 2.0, the library introduces a new event called **successfully executed**. This event will be raised regardless of the `RunMode` type and will return the appropriate execution result. -For #4, exceptions are caught in [CommandService#Log] event under +For #4, exceptions are caught in [CommandService.Log] event under [LogMessage.Exception] as [CommandException]. [Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run @@ -146,6 +157,6 @@ For #4, exceptions are caught in [CommandService#Log] event under [ExecuteResult]: xref:Discord.Commands.ExecuteResult [RuntimeResult]: xref:Discord.Commands.RuntimeResult [CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted -[CommandService#Log]: xref:Discord.Commands.CommandService.Log +[CommandService.Log]: xref:Discord.Commands.CommandService.Log [LogMessage.Exception]: xref:Discord.LogMessage.Exception* [CommandException]: xref:Discord.Commands.CommandException \ No newline at end of file diff --git a/docs/faq/commands/samples/Remainder.cs b/docs/faq/commands/samples/Remainder.cs index a28c782e0..337fb6e45 100644 --- a/docs/faq/commands/samples/Remainder.cs +++ b/docs/faq/commands/samples/Remainder.cs @@ -16,5 +16,5 @@ public Task EchoAsync(string text) => ReplyAsync(text); // Wrapping the message in quotes solves this. // This way, the system knows the entire message is to be parsed as a // single String. -// e.g. +// e.g., // !echo "Coffee Cake" \ No newline at end of file diff --git a/docs/faq/misc/Glossary.md b/docs/faq/misc/glossary.md similarity index 100% rename from docs/faq/misc/Glossary.md rename to docs/faq/misc/glossary.md diff --git a/docs/faq/misc/Legacy.md b/docs/faq/misc/legacy.md similarity index 83% rename from docs/faq/misc/Legacy.md rename to docs/faq/misc/legacy.md index ef4caa1cd..fec6ba24d 100644 --- a/docs/faq/misc/Legacy.md +++ b/docs/faq/misc/legacy.md @@ -7,8 +7,8 @@ title: Questions about Legacy Versions ## X, Y, Z does not work! It doesn't return a valid value anymore -If you're currently using an older version in stable branch, please -upgrade to the latest pre-release version to ensure maximum +If you are currently using an older version of the stable branch, +please upgrade to the latest pre-release version to ensure maximum compatibility. Several features may be broken in older versions and will likely not be fixed in the version branch due to their breaking nature. diff --git a/docs/guides/commands/intro.md b/docs/guides/commands/intro.md index 8036ed09e..e2fad73e8 100644 --- a/docs/guides/commands/intro.md +++ b/docs/guides/commands/intro.md @@ -107,7 +107,7 @@ be found in @Guides.Commands.TypeReaders. #### Optional Parameters Parameters, by default, are always required. To make a parameter -optional, give it a default value (i.e. `int num = 0`). +optional, give it a default value (i.e., `int num = 0`). #### Parameters with Spaces diff --git a/docs/guides/commands/post-execution.md b/docs/guides/commands/post-execution.md index 5f19147cb..267f84b8f 100644 --- a/docs/guides/commands/post-execution.md +++ b/docs/guides/commands/post-execution.md @@ -6,18 +6,18 @@ title: Post-command Execution Handling # Preface When developing commands, you may want to consider building a -post-execution handling system so you can have a finer control +post-execution handling system so you can have finer control over commands. Discord.Net offers several post-execution workflows for you to work with. -If you recall, in the [Command Guide], we've shown the following +If you recall, in the [Command Guide], we have shown the following example for executing and handling commands, [!code[Command Handler](samples/command_handler.cs)] You may notice that after we perform [ExecuteAsync], we store the -result and print it to the chat. This is essentially the most -basic post-execution handling. +result and print it to the chat, essentially creating the most +fundamental form of a post-execution handler. With this in mind, we could start doing things like the following, @@ -25,8 +25,8 @@ With this in mind, we could start doing things like the following, However, this may not always be preferred, because you are creating your post-execution logic *with* the essential command -handler. This could lead to messy code and could potentially be a -violation of the SRP (Single Responsibility Principle). +handler. This design could lead to messy code and could potentially +be a violation of the SRP (Single Responsibility Principle). Another major issue is if your command is marked with `RunMode.Async`, [ExecuteAsync] will **always** return a successful @@ -37,8 +37,8 @@ about the impact in the [FAQ](xref:FAQ.Commands). Enter [CommandExecuted], an event that was introduced in Discord.Net 2.0. This event is raised whenever a command is -successfully executed **without any run-time exceptions** or **without -any parsing or precondition failure**. This means this event can be +successfully executed **without any run-time exceptions** or **any +parsing or precondition failure**. This means this event can be used to streamline your post-execution design, and the best thing about this event is that it is not prone to `RunMode.Async`'s [ExecuteAsync] drawbacks. @@ -52,7 +52,7 @@ next? We can take this further by using [RuntimeResult]. ### RuntimeResult -`RuntimeResult` was originally introduced in 1.0 to allow +`RuntimeResult` was initially introduced in 1.0 to allow developers to centralize their command result logic. In other words, it is a result type that is designed to be returned when the command has finished its execution. @@ -62,7 +62,7 @@ However, it wasn't widely adopted due to the aforementioned result-handler via the [CommandExecuted] event, we can start making use of this class. -The best way to make use of it is to create your own version of +The best way to make use of it is to create your version of `RuntimeResult`. You can achieve this by inheriting the `RuntimeResult` class. @@ -71,16 +71,16 @@ of `RuntimeResult`, [!code[Base Use](samples/customresult_base.cs)] -The sky's the limit from here. You can add any additional information -you'd like regarding the execution result. +The sky is the limit from here. You can add any additional information +you would like regarding the execution result. -For example, you may want to add your own result type or other +For example, you may want to add your result type or other helpful information regarding the execution, or something simple like static methods to help you create return types easily. [!code[Extended Use](samples/customresult_extended.cs)] -After you're done creating your own [RuntimeResult], you can +After you're done creating your [RuntimeResult], you can implement it in your command by marking the command return type to `Task`. @@ -100,12 +100,12 @@ And now we can check for it in our [CommandExecuted] handler: ## CommandService.Log Event We have so far covered the handling of various result types, but we -haven't talked about what to do if the command enters a catastrophic -failure (i.e. exceptions). To resolve this, we can make use of the +have not talked about what to do if the command enters a catastrophic +failure (i.e., exceptions). To resolve this, we can make use of the [CommandService.Log] event. -All exceptions thrown during a command execution will be caught and -be sent to the Log event under the [LogMessage.Exception] property +All exceptions thrown during a command execution are caught and sent +to the Log event under the [LogMessage.Exception] property as a [CommandException] type. The [CommandException] class allows us to access the exception thrown, as well as the context of the command. diff --git a/docs/guides/concepts/connections.md b/docs/guides/concepts/connections.md index 324b67566..99ea45756 100644 --- a/docs/guides/concepts/connections.md +++ b/docs/guides/concepts/connections.md @@ -11,14 +11,14 @@ stopped. To start a connection, invoke the `StartAsync` method on a client that supports a WebSocket connection; to end a connection, invoke the -`StopAsync` method. This will gracefully close any open WebSocket or +`StopAsync` method, which gracefully closes any open WebSocket or UdpSocket connections. Since the Start/Stop methods only signal to an underlying connection manager that a connection needs to be started, **they return before a -connection is actually made.** +connection is made.** -As a result, you will need to hook into one of the connection-state +As a result, you need to hook into one of the connection-state based events to have an accurate representation of when a client is ready for use. @@ -29,7 +29,7 @@ ready to be used. A separate event, `Ready`, is provided on [DiscordSocketClient], which is raised only when the client has finished guild stream or guild -sync, and has a complete guild cache. +sync and has a completed guild cache. [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient @@ -41,8 +41,8 @@ sync, and has a complete guild cache. > [!TIP] > Avoid running long-running code on the gateway! If you deadlock the -> gateway (as explained in [events]), the connection manager will be -> unable to recover and reconnect. +> gateway (as explained in [events]), the connection manager will +> **NOT** be able to recover and reconnect. Assuming the client disconnected because of a fault on Discord's end, and not a deadlock on your end, we will always attempt to reconnect @@ -50,6 +50,6 @@ and resume a connection. Don't worry about trying to maintain your own connections, the connection manager is designed to be bulletproof and never fail - if -your client doesn't manage to reconnect, you've found a bug! +your client does not manage to reconnect, you have found a bug! [events]: xref:Guides.Concepts.Events diff --git a/docs/guides/concepts/deployment.md b/docs/guides/concepts/deployment.md index d26abee34..eea747817 100644 --- a/docs/guides/concepts/deployment.md +++ b/docs/guides/concepts/deployment.md @@ -68,7 +68,7 @@ for use on another machine without installing the dependencies first. This can be achieved by using the dotnet CLI too on the development machine: - `dotnet publish -c Release` +* `dotnet publish -c Release` Additionally, you may want to target a specific platform when publishing the application so you may use the application without @@ -80,7 +80,7 @@ For example, when targeting a Windows 10 machine, you may want to use the following to create the application in Windows executable format (.exe): - `dotnet publish -c Release -r win10-x64` +* `dotnet publish -c Release -r win10-x64` [.NET Core application deployment]: https://docs.microsoft.com/en-us/dotnet/core/deploying/ [Runtime ID]: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog \ No newline at end of file diff --git a/docs/guides/concepts/entities.md b/docs/guides/concepts/entities.md index 7c66c7a57..7415f043a 100644 --- a/docs/guides/concepts/entities.md +++ b/docs/guides/concepts/entities.md @@ -56,7 +56,7 @@ DiscordSocketClient. > [FAQ](xref:FAQ.Basics.GetStarted) page. More detailed versions of entities can be pulled from the basic -entities, e.g. `SocketGuild.GetUser`, which returns a +entities, e.g., `SocketGuild.GetUser`, which returns a `SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a `SocketGuildChannel`. Again, you may need to cast these objects to get a variant of the type that you need. diff --git a/docs/guides/concepts/events.md b/docs/guides/concepts/events.md index d8e586681..293b5dc72 100644 --- a/docs/guides/concepts/events.md +++ b/docs/guides/concepts/events.md @@ -74,7 +74,7 @@ object. [Cacheable]: xref:Discord.Cacheable`2 > [!NOTE] -> Many events relating to a Message entity (i.e. `MessageUpdated` and +> Many events relating to a Message entity (i.e., `MessageUpdated` and > `ReactionAdded`) rely on the client's message cache, which is > **not** enabled by default. Set the `MessageCacheSize` flag in > @Discord.WebSocket.DiscordSocketConfig to enable it. diff --git a/docs/guides/concepts/logging.md b/docs/guides/concepts/logging.md index dba78006f..b92d2bd53 100644 --- a/docs/guides/concepts/logging.md +++ b/docs/guides/concepts/logging.md @@ -16,7 +16,7 @@ section. > [!WARNING] > Due to the nature of Discord.Net's event system, all log event > handlers will be executed synchronously on the gateway thread. If your -> log output will be dumped to a Web API (e.g. Sentry), you are advised +> log output will be dumped to a Web API (e.g., Sentry), you are advised > to wrap your output in a `Task.Run` so the gateway thread does not > become blocked while waiting for logging data to be written. diff --git a/docs/guides/getting_started/first-bot.md b/docs/guides/getting_started/first-bot.md index 622709eca..a5a83aa16 100644 --- a/docs/guides/getting_started/first-bot.md +++ b/docs/guides/getting_started/first-bot.md @@ -27,8 +27,8 @@ Discord Applications Portal first. ![Step 5](images/intro-create-bot.png) 6. Confirm the popup. -7. If this bot will be public, check "Public Bot." **Do not tick any - other options!** +7. (Optional) If this bot will be public, check "Public Bot." + * **Do not tick any other options!** [Discord Applications Portal]: https://discordapp.com/developers/applications/me @@ -38,15 +38,18 @@ Bots **cannot** use invite links; they must be explicitly invited through the OAuth2 flow. 1. Open your bot's application on the [Discord Applications Portal]. -2. Retrieve the application's **Client ID**. +2. Navigate to `OAuth2 URL Generator` and click on `Generate OAuth2 URL`. - ![Step 2](images/intro-client-id.png) + ![Step 2](images/intro-generate-oauth.png) -3. Create an OAuth2 authorization URL +3. Select the permissions that you wish to assign your bot with. - - `https://discordapp.com/oauth2/authorize?client_id=&scope=bot` + > [!NOTE] + > This will assign the bot with a special "managed" role that no + > one else can use. The permissions can be changed later in the + > roles settings if you ever change your mind! -4. Open the authorization URL in your browser. +4. Open the generated authorization URL in your browser. 5. Select a server. 6. Click on authorize. diff --git a/docs/guides/getting_started/images/install-vs-nuget.png b/docs/guides/getting_started/images/install-vs-nuget.png index 64da79a9ff2c16ded006fb55e2cd89151b9a2340..ecf627d11ee9a3eeffecb25d4bdb4988a687dbc4 100644 GIT binary patch literal 49542 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
~p2)L2YXmDS>jXzj;9(rS^ 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 diff --git a/docs/guides/getting_started/images/intro-client-id.png b/docs/guides/getting_started/images/intro-client-id.png deleted file mode 100644 index e370aa2ecbb1c2e9b98b7f7cd35fa664e1e3bc28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5109 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 RUQVJ2(AP21F4ue#^It;zlF|SG diff --git a/docs/guides/getting_started/images/intro-copy-oauth.png b/docs/guides/getting_started/images/intro-copy-oauth.png new file mode 100644 index 0000000000000000000000000000000000000000..31dc6f74320a628ed367803b1b44738fcb2bfebd GIT binary patch literal 20319 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 literal 52035 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 G(EkD3K*%=$ diff --git a/docs/guides/getting_started/images/intro-create-bot.png b/docs/guides/getting_started/images/intro-create-bot.png index 0522358cfcb35a17632b03394333891988fc0c0e..cc4e55ec39cdd8618832e5c639959f958dd5f727 100644 GIT binary patch literal 20044 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�za0T3WZx8>F( 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 literal 0 HcmV?d00001 diff --git a/docs/guides/getting_started/installing.md b/docs/guides/getting_started/installing.md index c0980101e..b174a3829 100644 --- a/docs/guides/getting_started/installing.md +++ b/docs/guides/getting_started/installing.md @@ -40,7 +40,7 @@ Release builds of Discord.Net will be published to the Development builds of Discord.Net, as well as add-ons, will be published to our [MyGet feed]. -Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` +* Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` Not sure how to add a direct feed? See how [with Visual Studio] or [without Visual Studio]. diff --git a/docs/guides/getting_started/terminology.md b/docs/guides/getting_started/terminology.md index a03dc8fbf..61a226dcf 100644 --- a/docs/guides/getting_started/terminology.md +++ b/docs/guides/getting_started/terminology.md @@ -28,13 +28,13 @@ addon will run on all platforms. `Discord.Net.Rest` provides a set of concrete classes to be used **strictly** with the REST portion of Discord's API. Entities in this -implementation are prefixed with `Rest` (e.g. `RestChannel`). +implementation are prefixed with `Rest` (e.g., `RestChannel`). `Discord.Net.Rpc` provides a set of concrete classes that are used with Discord's RPC API. Entities in this implementation are prefixed -with `Rpc` (e.g. `RpcChannel`). +with `Rpc` (e.g., `RpcChannel`). `Discord.Net.WebSocket` provides a set of concrete classes that are used primarily with Discord's WebSocket API or entities that are kept in cache. When developing bots, you will be using this implementation. -All entities are prefixed with `Socket` (e.g. `SocketChannel`). \ No newline at end of file +All entities are prefixed with `Socket` (e.g., `SocketChannel`). \ No newline at end of file diff --git a/docs/guides/introduction/intro.md b/docs/guides/introduction/intro.md index 165a7949a..c22edd1f7 100644 --- a/docs/guides/introduction/intro.md +++ b/docs/guides/introduction/intro.md @@ -17,7 +17,7 @@ understand these topics to some extent before proceeding. Here are some examples: -1. [Official quick start guide] +1. [Official samples] 2. [Official template] > [!NOTE] @@ -26,7 +26,7 @@ Here are some examples: > It is not meant to be something that will work out of the box. [Official template]: https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot -[Official quick start guide]: https://github.com/RogueException/Discord.Net/blob/dev/docs/guides/getting_started/samples/first-bot/structure.cs +[Official samples]: https://github.com/RogueException/Discord.Net/tree/dev/samples [Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap [polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism [interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ diff --git a/src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs b/src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs index efdb2c5b2..9b750809b 100644 --- a/src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/ParameterPreconditionAttribute.cs @@ -6,6 +6,7 @@ namespace Discord.Commands /// /// Requires the parameter to pass the specified precondition before execution can begin. /// + /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] public abstract class ParameterPreconditionAttribute : Attribute { diff --git a/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs b/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs index 58d9c8ba4..316b2729e 100644 --- a/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs @@ -3,20 +3,29 @@ using System.Threading.Tasks; namespace Discord.Commands { - /// Requires the module or class to pass the specified precondition before execution can begin. + /// + /// Requires the module or class to pass the specified precondition before execution can begin. + /// + /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public abstract class PreconditionAttribute : Attribute { /// - /// Specify a group that this precondition belongs to. + /// Specifies a group that this precondition belongs to. /// /// /// of the same group require only one of the preconditions to pass in order to - /// be successful (A || B). Specifying = or not at all will + /// be successful (A || B). Specifying = null or not at all will /// require *all* preconditions to pass, just like normal (A && B). /// public string Group { get; set; } = null; + /// + /// Checks if the has the sufficient permission to be executed. + /// + /// The context of the command. + /// The command being executed. + /// The service collection used for dependency injection. public abstract Task CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services); } } diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs index 072f10e0f..f2bd717e4 100644 --- a/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs @@ -54,9 +54,9 @@ namespace Discord.Commands if (GuildPermission.HasValue) { if (guildUser == null) - return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel")); + return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel.")); if (!guildUser.GuildPermissions.Has(GuildPermission.Value)) - return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}")); + return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}.")); } if (ChannelPermission.HasValue) @@ -68,7 +68,7 @@ namespace Discord.Commands perms = ChannelPermissions.All(context.Channel); if (!perms.Has(ChannelPermission.Value)) - return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}")); + return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}.")); } return Task.FromResult(PreconditionResult.FromSuccess()); diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 39cae845e..24db6e9b5 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -129,7 +129,7 @@ namespace Discord.Commands /// The type of module. /// /// The for your dependency injection solution, if using one - otherwise, pass - /// . + /// null. /// /// /// A built module. @@ -144,7 +144,7 @@ namespace Discord.Commands /// The type of module. /// /// The for your dependency injection solution, if using one - otherwise, pass - /// . + /// null. /// /// /// A built module. @@ -183,7 +183,7 @@ namespace Discord.Commands /// The containing command modules. /// /// An for your dependency injection solution, if using one - otherwise, pass - /// . + /// null. /// /// /// A collection of built modules. diff --git a/src/Discord.Net.Commands/Readers/ChannelTypeReader.cs b/src/Discord.Net.Commands/Readers/ChannelTypeReader.cs index cd7a9d744..6cb9ca6e6 100644 --- a/src/Discord.Net.Commands/Readers/ChannelTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/ChannelTypeReader.cs @@ -6,19 +6,23 @@ using System.Threading.Tasks; namespace Discord.Commands { + /// + /// A for parsing objects implementing . + /// + /// The type to be checked; must implement . public class ChannelTypeReader : TypeReader where T : class, IChannel { + /// public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { if (context.Guild != null) { var results = new Dictionary(); var channels = await context.Guild.GetChannelsAsync(CacheMode.CacheOnly).ConfigureAwait(false); - ulong id; //By Mention (1.0) - if (MentionUtils.TryParseChannel(input, out id)) + if (MentionUtils.TryParseChannel(input, out ulong id)) AddResult(results, await context.Guild.GetChannelAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f); //By Id (0.9) diff --git a/src/Discord.Net.Commands/Readers/MessageTypeReader.cs b/src/Discord.Net.Commands/Readers/MessageTypeReader.cs index a87cfbe43..acec2f12d 100644 --- a/src/Discord.Net.Commands/Readers/MessageTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/MessageTypeReader.cs @@ -4,15 +4,18 @@ using System.Threading.Tasks; namespace Discord.Commands { + /// + /// A for parsing objects implementing . + /// + /// The type to be checked; must implement . public class MessageTypeReader : TypeReader where T : class, IMessage { + /// public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { - ulong id; - //By Id (1.0) - if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out ulong id)) { if (await context.Channel.GetMessageAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) is T msg) return TypeReaderResult.FromSuccess(msg); diff --git a/src/Discord.Net.Commands/Readers/RoleTypeReader.cs b/src/Discord.Net.Commands/Readers/RoleTypeReader.cs index c199033fa..4c9aaf4d8 100644 --- a/src/Discord.Net.Commands/Readers/RoleTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/RoleTypeReader.cs @@ -6,9 +6,14 @@ using System.Threading.Tasks; namespace Discord.Commands { + /// + /// A for parsing objects implementing . + /// + /// The type to be checked; must implement . public class RoleTypeReader : TypeReader where T : class, IRole { + /// public override Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { if (context.Guild != null) diff --git a/src/Discord.Net.Commands/Readers/TypeReader.cs b/src/Discord.Net.Commands/Readers/TypeReader.cs index af45a0aac..037213ae9 100644 --- a/src/Discord.Net.Commands/Readers/TypeReader.cs +++ b/src/Discord.Net.Commands/Readers/TypeReader.cs @@ -1,10 +1,22 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord.Commands { + /// + /// Defines a reader class that parses user input into a specified type. + /// public abstract class TypeReader { + /// + /// Attempts to parse the into the desired type. + /// + /// The context of the command. + /// The raw input of the command. + /// The service collection used for dependency injection. + /// + /// An awaitable Task containing the result of the type reading process. + /// public abstract Task ReadAsync(ICommandContext context, string input, IServiceProvider services); } } diff --git a/src/Discord.Net.Commands/Readers/UserTypeReader.cs b/src/Discord.Net.Commands/Readers/UserTypeReader.cs index 7feab50ad..6d9f1dd8c 100644 --- a/src/Discord.Net.Commands/Readers/UserTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/UserTypeReader.cs @@ -7,9 +7,14 @@ using System.Threading.Tasks; namespace Discord.Commands { + /// + /// A for parsing objects implementing . + /// + /// The type to be checked; must implement . public class UserTypeReader : TypeReader where T : class, IUser { + /// public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { var results = new Dictionary(); @@ -72,8 +77,8 @@ namespace Discord.Commands .ForEachAsync(channelUser => AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f)) .ConfigureAwait(false); - foreach (var guildUser in guildUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase))) - AddResult(results, guildUser as T, (guildUser as IGuildUser).Nickname == input ? 0.60f : 0.50f); + foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Nickname, StringComparison.OrdinalIgnoreCase))) + AddResult(results, guildUser as T, guildUser.Nickname == input ? 0.60f : 0.50f); } if (results.Count > 0) diff --git a/src/Discord.Net.Commands/Results/RuntimeResult.cs b/src/Discord.Net.Commands/Results/RuntimeResult.cs index a7febd68e..e4c86fc23 100644 --- a/src/Discord.Net.Commands/Results/RuntimeResult.cs +++ b/src/Discord.Net.Commands/Results/RuntimeResult.cs @@ -8,7 +8,7 @@ namespace Discord.Commands /// /// Initializes a new class with the type of error and reason. /// - /// The type of failure, or if none. + /// The type of failure, or null if none. /// The reason of failure. protected RuntimeResult(CommandError? error, string reason) { diff --git a/src/Discord.Net.Core/CDN.cs b/src/Discord.Net.Core/CDN.cs index 1b75d0633..0fefc9a0d 100644 --- a/src/Discord.Net.Core/CDN.cs +++ b/src/Discord.Net.Core/CDN.cs @@ -8,13 +8,26 @@ namespace Discord public static class CDN { /// - /// Returns the Discord developer application icon. + /// Returns an application icon URL. /// + /// The application identifier. + /// The icon identifier. + /// + /// A URL pointing to the application's icon. + /// public static string GetApplicationIconUrl(ulong appId, string iconId) => iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null; + /// - /// Returns the user avatar URL based on the and . + /// Returns a user avatar URL. /// + /// The user snowflake identifier. + /// The avatar identifier. + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// The format to return. + /// + /// A URL pointing to the user's avatar in the specified size. + /// public static string GetUserAvatarUrl(ulong userId, string avatarId, ushort size, ImageFormat format) { if (avatarId == null) @@ -26,34 +39,64 @@ namespace Discord /// Returns the default user avatar URL. /// /// The discriminator value of a user. + /// + /// A URL pointing to the user's default avatar when one isn't set. + /// public static string GetDefaultUserAvatarUrl(ushort discriminator) { return $"{DiscordConfig.CDNUrl}embed/avatars/{discriminator % 5}.png"; } /// - /// Returns the icon URL associated with the given guild ID. + /// Returns an icon URL. /// + /// The guild snowflake identifier. + /// The icon identifier. + /// + /// A URL pointing to the guild's icon. + /// public static string GetGuildIconUrl(ulong guildId, string iconId) => iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null; /// - /// Returns the guild splash URL associated with the given guild and splash ID. + /// Returns a guild splash URL. /// + /// The guild snowflake identifier. + /// The splash icon identifier. + /// + /// A URL pointing to the guild's icon. + /// public static string GetGuildSplashUrl(ulong guildId, string splashId) => splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null; /// - /// Returns the channel icon URL associated with the given guild and icon ID. + /// Returns a channel icon URL. /// + /// The channel snowflake identifier. + /// The icon identifier. + /// + /// A URL pointing to the channel's icon. + /// public static string GetChannelIconUrl(ulong channelId, string iconId) => iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; /// - /// Returns the emoji URL based on the emoji ID. + /// Returns an emoji URL. /// + /// The emoji snowflake identifier. + /// Whether this emoji is animated. + /// + /// A URL pointing to the custom emote. + /// public static string GetEmojiUrl(ulong emojiId, bool animated) => $"{DiscordConfig.CDNUrl}emojis/{emojiId}.{(animated ? "gif" : "png")}"; /// - /// Returns the rich presence asset URL based on the asset ID and . + /// Returns a Rich Presence asset URL. /// + /// The application identifier. + /// The asset identifier. + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// The format to return. + /// + /// A URL pointing to the asset image in the specified size. + /// public static string GetRichAssetUrl(ulong appId, string assetId, ushort size, ImageFormat format) { string extension = FormatToExtension(format, ""); @@ -61,10 +104,21 @@ namespace Discord } /// - /// Returns the Spotify album URL based on the album art ID. + /// Returns a Spotify album URL. /// + /// The identifier for the album art (e.g. 6be8f4c8614ecf4f1dd3ebba8d8692d8ce4951ac). + /// + /// A URL pointing to the Spotify album art. + /// public static string GetSpotifyAlbumArtUrl(string albumArtId) => $"https://i.scdn.co/image/{albumArtId}"; + /// + /// Returns a Spotify direct URL for a track. + /// + /// The identifier for the track (e.g. 4uLU6hMCjMI75M1A2tKUQC). + /// + /// A URL pointing to the Spotify track. + /// public static string GetSpotifyDirectUrl(string trackId) => $"https://open.spotify.com/track/{trackId}"; diff --git a/src/Discord.Net.Core/DiscordConfig.cs b/src/Discord.Net.Core/DiscordConfig.cs index b3cdddfa5..0e46f2960 100644 --- a/src/Discord.Net.Core/DiscordConfig.cs +++ b/src/Discord.Net.Core/DiscordConfig.cs @@ -8,68 +8,116 @@ namespace Discord public class DiscordConfig { /// - /// Returns the gateway version Discord.Net uses. + /// Returns the API version Discord.Net uses. /// + /// + /// A 32-bit integer representing the API version that Discord.Net uses to communicate with Discord. + /// A list of available API version can be seen on the official + /// Discord API documentation + /// . + /// public const int APIVersion = 6; /// /// Gets the Discord.Net version, including the build number. /// + /// + /// A string containing the detailed version information, including its build number; Unknown when + /// the version fails to be fetched. + /// public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute()?.InformationalVersion ?? - typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ?? + typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ?? "Unknown"; /// /// Gets the user agent that Discord.Net uses in its clients. /// + /// + /// The user agent used in each Discord.Net request. + /// public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; /// /// Returns the base Discord API URL. /// + /// + /// The Discord API URL using . + /// public static readonly string APIUrl = $"https://discordapp.com/api/v{APIVersion}/"; /// /// Returns the base Discord CDN URL. /// + /// + /// The base Discord Content Delivery Network (CDN) URL. + /// public const string CDNUrl = "https://cdn.discordapp.com/"; /// - /// Returns the base Discord invite URL. + /// Returns the base Discord invite URL. /// + /// + /// The base Discord invite URL. + /// public const string InviteUrl = "https://discord.gg/"; /// /// Returns the default timeout for requests. /// + /// + /// The amount of time it takes in milliseconds before a request is timed out. + /// public const int DefaultRequestTimeout = 15000; /// /// Returns the max length for a Discord message. /// + /// + /// The maximum length of a message allowed by Discord. + /// public const int MaxMessageSize = 2000; /// /// Returns the max messages allowed to be in a request. /// + /// + /// The maximum number of messages that can be gotten per-batch. + /// public const int MaxMessagesPerBatch = 100; /// /// Returns the max users allowed to be in a request. /// + /// + /// The maximum number of users that can be gotten per-batch. + /// public const int MaxUsersPerBatch = 1000; /// /// Returns the max guilds allowed to be in a request. /// + /// + /// The maximum number of guilds that can be gotten per-batch. + /// public const int MaxGuildsPerBatch = 100; + public const int MaxAuditLogEntriesPerBatch = 100; /// /// Gets or sets how a request should act in the case of an error, by default. /// + /// + /// The currently set . + /// public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry; /// /// Gets or sets the minimum log level severity that will be sent to the Log event. /// + /// + /// The currently set for logging level. + /// public LogSeverity LogLevel { get; set; } = LogSeverity.Info; /// /// Gets or sets whether the initial log entry should be printed. /// + /// + /// If set to true, the library will attempt to print the current version of the library, as well as + /// the API version it uses on startup. + /// internal bool DisplayInitialLog { get; set; } = true; } } diff --git a/src/Discord.Net.Core/Entities/Activities/GameAsset.cs b/src/Discord.Net.Core/Entities/Activities/GameAsset.cs index b0c8ea975..467b2885f 100644 --- a/src/Discord.Net.Core/Entities/Activities/GameAsset.cs +++ b/src/Discord.Net.Core/Entities/Activities/GameAsset.cs @@ -19,7 +19,7 @@ namespace Discord public string ImageId { get; internal set; } /// - /// Returns the image URL of the asset, or when the application ID does not exist. + /// Returns the image URL of the asset, or null when the application ID does not exist. /// public string GetImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => ApplicationId.HasValue ? CDN.GetRichAssetUrl(ApplicationId.Value, ImageId, size, format) : null; diff --git a/src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs b/src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs index beec4eebc..23f88687d 100644 --- a/src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs +++ b/src/Discord.Net.Core/Entities/Activities/SpotifyGame.cs @@ -13,36 +13,65 @@ namespace Discord /// /// Gets the song's artist(s). /// + /// + /// A collection of string containing all artists featured in the track (e.g. Avicii; Rita Ora). + /// public IReadOnlyCollection Artists { get; internal set; } /// /// Gets the Spotify album title of the song. /// + /// + /// A string containing the name of the album (e.g. AVĪCI (01)). + /// public string AlbumTitle { get; internal set; } /// /// Gets the track title of the song. /// + /// + /// A string containing the name of the song (e.g. Lonely Together (feat. Rita Ora)). + /// public string TrackTitle { get; internal set; } /// /// Gets the duration of the song. /// + /// + /// A containing the duration of the song. + /// public TimeSpan? Duration { get; internal set; } /// /// Gets the track ID of the song. /// + /// + /// A string containing the Spotify ID of the track (e.g. 7DoN0sCGIT9IcLrtBDm4f0). + /// public string TrackId { get; internal set; } /// /// Gets the session ID of the song. /// + /// + /// The purpose of this property is currently unknown. + /// + /// + /// A string containing the session ID. + /// public string SessionId { get; internal set; } /// /// Gets the URL of the album art. /// + /// + /// A URL pointing to the album art of the track (e.g. + /// https://i.scdn.co/image/ba2fd8823d42802c2f8738db0b33a4597f2f39e7). + /// public string AlbumArtUrl { get; internal set; } /// /// Gets the direct Spotify URL of the track. /// + /// + /// A URL pointing directly to the track on Spotify. (e.g. + /// https://open.spotify.com/track/7DoN0sCGIT9IcLrtBDm4f0). + /// public string TrackUrl { get; internal set; } internal SpotifyGame() { } @@ -50,6 +79,10 @@ namespace Discord /// /// Gets the full information of the song. /// + /// + /// A string containing the full information of the song (e.g. + /// Avicii, Rita Ora - Lonely Together (feat. Rita Ora) (3:08) + /// public override string ToString() => $"{string.Join(", ", Artists)} - {TrackTitle} ({Duration})"; private string DebuggerDisplay => $"{Name} (Spotify)"; } diff --git a/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs b/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs new file mode 100644 index 000000000..e5a4ff30a --- /dev/null +++ b/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// The action type within a + /// + public enum ActionType + { + GuildUpdated = 1, + + ChannelCreated = 10, + ChannelUpdated = 11, + ChannelDeleted = 12, + + OverwriteCreated = 13, + OverwriteUpdated = 14, + OverwriteDeleted = 15, + + Kick = 20, + Prune = 21, + Ban = 22, + Unban = 23, + + MemberUpdated = 24, + MemberRoleUpdated = 25, + + RoleCreated = 30, + RoleUpdated = 31, + RoleDeleted = 32, + + InviteCreated = 40, + InviteUpdated = 41, + InviteDeleted = 42, + + WebhookCreated = 50, + WebhookUpdated = 51, + WebhookDeleted = 52, + + EmojiCreated = 60, + EmojiUpdated = 61, + EmojiDeleted = 62, + + MessageDeleted = 72 + } +} diff --git a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs new file mode 100644 index 000000000..47aaffb26 --- /dev/null +++ b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents data applied to an + /// + public interface IAuditLogData + { } +} diff --git a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs new file mode 100644 index 000000000..b85730a1d --- /dev/null +++ b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents an entry in an audit log + /// + public interface IAuditLogEntry : IEntity + { + /// + /// The action which occured to create this entry + /// + ActionType Action { get; } + + /// + /// The data for this entry. May be if no data was available. + /// + IAuditLogData Data { get; } + + /// + /// The user responsible for causing the changes + /// + IUser User { get; } + + /// + /// The reason behind the change. May be if no reason was provided. + /// + string Reason { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs b/src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs index fdbd0447c..a0edfc796 100644 --- a/src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs +++ b/src/Discord.Net.Core/Entities/Channels/GuildChannelProperties.cs @@ -3,14 +3,7 @@ namespace Discord /// /// Properties that are used to modify an with the specified changes. /// - /// - /// - /// await (Context.Channel as ITextChannel)?.ModifyAsync(x => - /// { - /// x.Name = "do-not-enter"; - /// }); - /// - /// + /// public class GuildChannelProperties { /// diff --git a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs index fdbe77653..3d11e2c6f 100644 --- a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs @@ -24,7 +24,7 @@ namespace Discord /// Gets the parent ID (category) of this channel in the guild's channel list. /// /// - /// The parent category ID associated with this channel, or if none is set. + /// The parent category ID associated with this channel, or null if none is set. /// ulong? CategoryId { get; } /// @@ -57,16 +57,16 @@ namespace Discord /// Creates a new invite to this channel. /// /// - /// The time (in seconds) until the invite expires. Set to to never expire. + /// The time (in seconds) until the invite expires. Set to null to never expire. /// /// - /// The max amount of times this invite may be used. Set to to have unlimited uses. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. /// /// - /// If , a user accepting this invite will be kicked from the guild after closing their client. + /// If true, a user accepting this invite will be kicked from the guild after closing their client. /// /// - /// If , don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). /// /// /// The options to be used when sending the request. @@ -86,12 +86,12 @@ namespace Discord Task ModifyAsync(Action func, RequestOptions options = null); /// - /// Gets the permission overwrite for a specific role, or if one does not exist. + /// Gets the permission overwrite for a specific role, or null if one does not exist. /// /// The role to get the overwrite from. OverwritePermissions? GetPermissionOverwrite(IRole role); /// - /// Gets the permission overwrite for a specific user, or if one does not exist. + /// Gets the permission overwrite for a specific user, or null if one does not exist. /// /// The user to get the overwrite from. OverwritePermissions? GetPermissionOverwrite(IUser user); diff --git a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs index 9837a3048..837e90604 100644 --- a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs @@ -17,10 +17,13 @@ namespace Discord /// Whether the message should be read aloud by Discord or not. /// The to be sent. /// The options to be used when sending the request. + /// + /// An awaitable Task containing the message sent to the channel. + /// Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null); #if FILESYSTEM /// - /// Sends a file to this message channel, with an optional caption. + /// Sends a file to this message channel with an optional caption. /// /// The file path of the file. /// The message to be sent. @@ -32,10 +35,13 @@ namespace Discord /// upload the file and refer to the file with "attachment://filename.ext" in the /// . /// + /// + /// An awaitable Task containing the message sent to the channel. + /// Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); #endif /// - /// Sends a file to this message channel, with an optional caption. + /// Sends a file to this message channel with an optional caption. /// /// The of the file to be sent. /// The name of the attachment. @@ -48,16 +54,19 @@ namespace Discord /// upload the file and refer to the file with "attachment://filename.ext" in the /// . /// + /// + /// An awaitable Task containing the message sent to the channel. + /// Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); /// - /// Gets a message from this message channel with the given id, or if not found. + /// Gets a message from this message channel with the given id, or null if not found. /// /// The ID of the message. /// The that determines whether the object should be fetched from cache. /// The options to be used when sending the request. /// - /// The message gotten from either the cache or the download, or if none is found. + /// The message gotten from either the cache or the download, or null if none is found. /// Task GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); @@ -108,7 +117,7 @@ namespace Discord /// /// The options to be used when sending the request. /// - /// A collection of messages. + /// An awaitable Task containing a collection of messages. /// Task> GetPinnedMessagesAsync(RequestOptions options = null); diff --git a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs index d1b2465ad..29c67bf6b 100644 --- a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs @@ -14,7 +14,7 @@ namespace Discord /// Determines whether the channel is NSFW. /// /// - /// if the channel has the NSFW flag enabled; otherwise, . + /// true if the channel has the NSFW flag enabled; otherwise, false. /// bool IsNsfw { get; } @@ -22,19 +22,29 @@ namespace Discord /// Gets the current topic for this text channel. /// /// - /// The topic set in the channel, or if none is set. + /// The topic set in the channel, or null if none is set. /// string Topic { get; } /// /// Bulk-deletes multiple messages. /// + /// + /// + /// This method can only remove messages that are posted within 14 days! + /// + /// /// The messages to be bulk-deleted. /// The options to be used when sending the request. Task DeleteMessagesAsync(IEnumerable messages, RequestOptions options = null); /// /// Bulk-deletes multiple messages. /// + /// + /// + /// This method can only remove messages that are posted within 14 days! + /// + /// /// The IDs of the messages to be bulk-deleted. /// The options to be used when sending the request. Task DeleteMessagesAsync(IEnumerable messageIds, RequestOptions options = null); @@ -62,7 +72,7 @@ namespace Discord /// The ID of the webhook. /// The options to be used when sending the request. /// - /// A webhook associated with the , or if not found. + /// A webhook associated with the , or null if not found. /// Task GetWebhookAsync(ulong id, RequestOptions options = null); /// diff --git a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs index f69e6e22e..e1efb1a86 100644 --- a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs @@ -14,7 +14,7 @@ namespace Discord int Bitrate { get; } /// /// Gets the max amount of users allowed to be connected to this channel at one time, or - /// if none is set. + /// null if none is set. /// int? UserLimit { get; } diff --git a/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs b/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs index b68c416b7..03b56b26c 100644 --- a/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs +++ b/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs @@ -1,8 +1,11 @@ +using System; + namespace Discord { /// /// Properties that are used to modify an with the specified changes. /// + /// public class TextChannelProperties : GuildChannelProperties { /// diff --git a/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs b/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs index c285560df..46e8f8550 100644 --- a/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs +++ b/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs @@ -10,7 +10,7 @@ namespace Discord /// public Optional Bitrate { get; set; } /// - /// Gets or sets the maximum number of users that can be present in a channel, or if none. + /// Gets or sets the maximum number of users that can be present in a channel, or null if none. /// public Optional UserLimit { get; set; } } diff --git a/src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs b/src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs index 721345afe..de457a0dc 100644 --- a/src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs +++ b/src/Discord.Net.Core/Entities/Emotes/EmoteProperties.cs @@ -5,6 +5,7 @@ namespace Discord /// /// Properties that are used to modify an with the specified changes. /// + /// public class EmoteProperties { /// diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs b/src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs index 68925b103..2977cd10c 100644 --- a/src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs +++ b/src/Discord.Net.Core/Entities/Guilds/GuildEmbedProperties.cs @@ -10,11 +10,11 @@ namespace Discord /// public Optional Enabled { get; set; } /// - /// Sets the channel that the invite should place its users in, if not . + /// Sets the channel that the invite should place its users in, if not null. /// public Optional Channel { get; set; } /// - /// Sets the channel the invite should place its users in, if not . + /// Sets the channel the invite should place its users in, if not null. /// public Optional ChannelId { get; set; } } diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs index 3c136b579..eccd852dd 100644 --- a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs +++ b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs @@ -3,28 +3,19 @@ namespace Discord /// /// Properties that are used to modify an with the specified changes. /// - /// - /// - /// await Context.Guild.ModifyAsync(async x => - /// { - /// x.Name = "aaaaaah"; - /// }); - /// - /// - /// + /// public class GuildProperties { - public Optional Username { get; set; } /// - /// Gets or sets the name of the Guild. + /// Gets or sets the name of the guild. Must be within 100 characters. /// public Optional Name { get; set; } /// - /// Gets or sets the region for the Guild's voice connections. + /// Gets or sets the region for the guild's voice connections. /// public Optional Region { get; set; } /// - /// Gets or sets the ID of the region for the Guild's voice connections. + /// Gets or sets the ID of the region for the guild's voice connections. /// public Optional RegionId { get; set; } /// diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index 057b94788..581ca551e 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -13,17 +13,23 @@ namespace Discord /// /// Gets the name of this guild. /// + /// + /// A string containing the name of this guild. + /// string Name { get; } /// /// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are - /// automatically moved to the AFK voice channel, if one is set. + /// automatically moved to the AFK voice channel. /// + /// + /// The amount of time in seconds for a user to be marked as inactive and moved into the AFK voice channel. + /// int AFKTimeout { get; } /// /// Determines if this guild is embeddable (i.e. can use widget). /// /// - /// if this guild can be embedded via widgets; otherwise . + /// true if this guild can be embedded via widgets; otherwise false. /// bool IsEmbeddable { get; } /// @@ -34,38 +40,61 @@ namespace Discord /// Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to /// perform administrative actions in this guild. /// + /// + /// The level of MFA requirement. + /// MfaLevel MfaLevel { get; } /// /// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. /// + /// + /// The level of requirements. + /// VerificationLevel VerificationLevel { get; } /// - /// Returns the ID of this guild's icon, or if none is set. + /// Gets the ID of this guild's icon. /// + /// + /// An identifier for the splash image; null if none is set. + /// string IconId { get; } /// - /// Returns the URL of this guild's icon, or if none is set. + /// Gets the URL of this guild's icon. /// + /// + /// A URL pointing to the guild's icon; null if none is set. + /// string IconUrl { get; } /// - /// Returns the ID of this guild's splash image, or if none is set. + /// Gets the ID of this guild's splash image. /// + /// + /// An identifier for the splash image; null if none is set. + /// string SplashId { get; } /// - /// Returns the URL of this guild's splash image, or if none is set. + /// Gets the URL of this guild's splash image. /// + /// + /// A URL pointing to the guild's splash image; null if none is set. + /// string SplashUrl { get; } /// /// Determines if this guild is currently connected and ready to be used. /// + /// + /// + /// This property only applies to a WebSocket-based client. + /// + /// This boolean is used to determine if the guild is currently connected to the WebSocket and is ready to be used/accessed. + /// /// - /// Returns if this guild is currently connected and ready to be used. Only applies - /// to the WebSocket client. + /// true if this guild is currently connected and ready to be used; otherwise false. /// bool Available { get; } /// - /// Gets the ID of the AFK voice channel for this guild, or if none is set. + /// Gets the ID of the AFK voice channel for this guild, or null if none is set. /// ulong? AFKChannelId { get; } /// @@ -73,11 +102,11 @@ namespace Discord /// ulong DefaultChannelId { get; } /// - /// Gets the ID of the embed channel set in the widget settings of this guild, or if none is set. + /// Gets the ID of the embed channel set in the widget settings of this guild, or null if none is set. /// ulong? EmbedChannelId { get; } /// - /// Gets the ID of the channel where randomized welcome messages are sent, or if none is set. + /// Gets the ID of the channel where randomized welcome messages are sent, or null if none is set. /// ulong? SystemChannelId { get; } /// @@ -143,7 +172,7 @@ namespace Discord /// Task ModifyEmbedAsync(Action func, RequestOptions options = null); /// - /// Bulk modifies the order of channels in this guild. + /// Bulk-modifies the order of channels in this guild. /// /// The properties used to modify the channel positions with. /// The options to be used when sending the request. @@ -152,17 +181,21 @@ namespace Discord /// Task ReorderChannelsAsync(IEnumerable args, RequestOptions options = null); /// - /// Bulk modifies the order of roles in this guild. + /// Bulk-modifies the order of roles in this guild. /// /// The properties used to modify the role positions with. /// The options to be used when sending the request. - Task ReorderRolesAsync(IEnumerable args, RequestOptions options = null); /// /// An awaitable . /// + Task ReorderRolesAsync(IEnumerable args, RequestOptions options = null); /// - /// Leaves this guild. If you are the owner, use instead. + /// Leaves this guild. /// + /// + /// This method will make the currently logged-in user leave the guild. If the user is the owner, use + /// instead. + /// /// The options to be used when sending the request. /// /// An awaitable . @@ -178,7 +211,25 @@ namespace Discord /// Task> GetBansAsync(RequestOptions options = null); /// - /// Bans the provided user from this guild and optionally prunes their recent messages. + /// Gets a ban object for a banned user. + /// + /// The banned user. + /// + /// An awaitable containing the ban object, which contains the user information and the + /// reason for the ban; null if the ban entry cannot be found. + /// + Task GetBanAsync(IUser user, RequestOptions options = null); + /// + /// Gets a ban object for a banned user. + /// + /// The snowflake identifier for the banned user. + /// + /// An awaitable containing the ban object, which contains the user information and the + /// reason for the ban; null if the ban entry cannot be found. + /// + Task GetBanAsync(ulong userId, RequestOptions options = null); + /// + /// Bans the user from this guild and optionally prunes their recent messages. /// /// The user to ban. /// @@ -192,9 +243,9 @@ namespace Discord /// Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null); /// - /// Bans the provided user ID from this guild and optionally prunes their recent messages. + /// Bans the user from this guild and optionally prunes their recent messages. /// - /// The ID of the user to ban. + /// The snowflake ID of the user to ban. /// /// The number of days to remove messages from this user for - must be between [0, 7]. /// @@ -245,7 +296,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the generic channel with the specified ID, or - /// if none is found. + /// null if none is found. /// Task GetChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -260,7 +311,7 @@ namespace Discord /// Task> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// - /// Gets a text channel in this guild with the provided ID, or if not found. + /// Gets a text channel in this guild with the provided ID, or null if not found. /// /// The text channel ID. /// @@ -269,7 +320,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the text channel with the specified ID, or - /// if none is found. + /// null if none is found. /// Task GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -304,7 +355,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the voice channel with the specified ID, or - /// if none is found. + /// null if none is found. /// Task GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -316,7 +367,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the AFK voice channel set within this guild, or - /// if none is set. + /// null if none is set. /// Task GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -328,7 +379,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the system channel within this guild, or - /// if none is set. + /// null if none is set. /// Task GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -340,7 +391,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the first viewable text channel in this guild, or - /// if none is found. + /// null if none is found. /// Task GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -352,7 +403,7 @@ namespace Discord /// The options to be used when sending the request. /// /// An awaitable containing the embed channel set within the server's widget settings, or - /// if none is set. + /// null if none is set. /// Task GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -389,12 +440,19 @@ namespace Discord /// /// Gets a collection of all invites to this guild. /// + /// The options to be used when sending the request. + /// + /// An awaitable containing a collection of invites found within this guild. + /// Task> GetInvitesAsync(RequestOptions options = null); /// - /// Gets the role in this guild with the provided ID, or if not found. + /// Gets a role in this guild. /// /// The role ID. + /// + /// A role that matches the provided snowflake identifier; null if none is found. + /// IRole GetRole(ulong id); /// /// Creates a new role with the provided name. @@ -412,25 +470,30 @@ namespace Discord /// /// Gets a collection of all users in this guild. /// - /// The that determines whether the object should be fetched from - /// cache. + /// + /// This method retrieves all users found within this guild. + /// + /// This may return an incomplete list on the WebSocket implementation. + /// + /// + /// + /// The that determines whether the object should be fetched from cache. + /// /// The options to be used when sending the request. /// /// An awaitable containing a collection of users found within this guild. /// - /// - /// This may return an incomplete list on the WebSocket implementation because Discord only sends offline - /// users on large guilds. - /// Task> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// - /// Gets the user in this guild with the provided ID, or if not found. + /// Gets a user found in this guild. /// - /// The user ID. - /// The that determines whether the object should be fetched from cache. + /// The user ID to search for. + /// The that determines whether the object should be fetched from + /// cache. /// The options to be used when sending the request. /// - /// An awaitable containing the guild user with the specified ID, otherwise . + /// An awaitable containing the guild user with the specified ID; null if none is + /// found. /// Task GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// @@ -459,25 +522,33 @@ namespace Discord /// Task DownloadUsersAsync(); /// - /// Removes all users from this guild if they have not logged on in a provided number of - /// or, if is , returns the - /// number of users that would be removed. + /// Prunes inactive users. /// + /// + /// This method removes all users that have not logged on in the provided number of days or, if + /// is true, returns the number of users that would be removed. + /// /// The number of days required for the users to be kicked. /// Whether this prune action is a simulation. /// The options to be used when sending the request. /// - /// An awaitable containing the number of users to be or has been removed from this guild. + /// An awaitable containing the number of users to be or has been removed from this + /// guild. /// Task PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null); + /// Gets the specified number of audit log entries for this guild. + Task> GetAuditLogAsync(int limit = DiscordConfig.MaxAuditLogEntriesPerBatch, + CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// - /// Gets the webhook in this guild with the provided ID, or if not found. + /// Gets a webhook found within this guild. /// /// The webhook ID. /// The options to be used when sending the request. /// - /// An awaitable containing the webhook with the specified ID, otherwise . + /// An awaitable containing the webhook with the specified ID; null if none is + /// found. /// Task GetWebhookAsync(ulong id, RequestOptions options = null); /// @@ -495,7 +566,8 @@ namespace Discord /// The guild emote ID. /// The options to be used when sending the request. /// - /// An awaitable containing the emote found with the specified ID, or if not found. + /// An awaitable containing the emote found with the specified ID; null if none is + /// found. /// Task GetEmoteAsync(ulong id, RequestOptions options = null); /// diff --git a/src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs index 5da2ce5da..b6685edf6 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs @@ -7,11 +7,11 @@ namespace Discord /// string Name { get; } /// - /// Gets the icon URL associated with this guild, or if one is not set. + /// Gets the icon URL associated with this guild, or null if one is not set. /// string IconUrl { get; } /// - /// Returns if the current user owns this guild. + /// Returns true if the current user owns this guild. /// bool IsOwner { get; } /// diff --git a/src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs b/src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs index eef208905..8516036f1 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IVoiceRegion.cs @@ -14,19 +14,19 @@ namespace Discord /// string Name { get; } /// - /// Returns if this voice region is exclusive to VIP accounts. + /// Returns true if this voice region is exclusive to VIP accounts. /// bool IsVip { get; } /// - /// Returns if this voice region is the closest to your machine. + /// Returns true if this voice region is the closest to your machine. /// bool IsOptimal { get; } /// - /// Returns if this is a deprecated voice region (avoid switching to these). + /// Returns true if this is a deprecated voice region (avoid switching to these). /// bool IsDeprecated { get; } /// - /// Returns if this is a custom voice region (used for events/etc). + /// Returns true if this is a custom voice region (used for events/etc). /// bool IsCustom { get; } } diff --git a/src/Discord.Net.Core/Entities/Image.cs b/src/Discord.Net.Core/Entities/Image.cs index dd77ec6ae..5453027ac 100644 --- a/src/Discord.Net.Core/Entities/Image.cs +++ b/src/Discord.Net.Core/Entities/Image.cs @@ -35,7 +35,7 @@ namespace Discord /// is a zero-length string, contains only white space, or contains one or more invalid /// characters as defined by . /// - /// is . + /// is null. /// /// The specified path, file name, or both exceed the system-defined maximum length. For example, on /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 diff --git a/src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs b/src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs index dcd3de997..1c6b1dd79 100644 --- a/src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs +++ b/src/Discord.Net.Core/Entities/Invites/IInviteMetadata.cs @@ -10,20 +10,20 @@ namespace Discord /// IUser Inviter { get; } /// - /// Returns if this invite was revoked. + /// Returns true if this invite was revoked. /// bool IsRevoked { get; } /// - /// Returns if users accepting this invite will be removed from the guild when they + /// Returns true if users accepting this invite will be removed from the guild when they /// log off. /// bool IsTemporary { get; } /// - /// Gets the time (in seconds) until the invite expires, or if it never expires. + /// Gets the time (in seconds) until the invite expires, or null if it never expires. /// int? MaxAge { get; } /// - /// Gets the max amount of times this invite may be used, or if there is no limit. + /// Gets the max amount of times this invite may be used, or null if there is no limit. /// int? MaxUses { get; } /// diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedAuthor.cs b/src/Discord.Net.Core/Entities/Messages/EmbedAuthor.cs index ab1360ce3..e596c0707 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedAuthor.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedAuthor.cs @@ -3,7 +3,7 @@ using System.Diagnostics; namespace Discord { /// - /// Represents a author field of an . + /// A author field of an . /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public struct EmbedAuthor diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index 087b30993..034d7eb73 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -106,7 +106,7 @@ namespace Discord /// Gets or sets the list of of an . /// An embed builder's fields collection is set to - /// . + /// null. /// Description length exceeds . /// /// The list of existing . @@ -125,28 +125,28 @@ namespace Discord /// Gets or sets the timestamp of an . /// /// - /// The timestamp of the embed, or if none is set. + /// The timestamp of the embed, or null if none is set. /// public DateTimeOffset? Timestamp { get; set; } /// /// Gets or sets the sidebar color of an . /// /// - /// The color of the embed, or if none is set. + /// The color of the embed, or null if none is set. /// public Color? Color { get; set; } /// /// Gets or sets the of an . /// /// - /// The author field builder of the embed, or if none is set. + /// The author field builder of the embed, or null if none is set. /// public EmbedAuthorBuilder Author { get; set; } /// /// Gets or sets the of an . /// /// - /// The footer field builder of the embed, or if none is set. + /// The footer field builder of the embed, or null if none is set. /// public EmbedFooterBuilder Footer { get; set; } @@ -438,7 +438,6 @@ namespace Discord { private string _name; private string _value; - private EmbedField _field; /// /// Gets the maximum field length for name allowed by Discord. /// @@ -452,7 +451,7 @@ namespace Discord /// Gets or sets the field name. /// /// - /// Field name is , empty or entirely whitespace. + /// Field name is null, empty or entirely whitespace. /// - or - /// Field name length exceeds . /// @@ -474,7 +473,7 @@ namespace Discord /// Gets or sets the field value. /// /// - /// Field value is , empty or entirely whitespace. + /// Field value is null, empty or entirely whitespace. /// - or - /// Field value length exceeds . /// @@ -540,7 +539,7 @@ namespace Discord /// The current builder. /// /// - /// or is , empty or entirely whitespace. + /// or is null, empty or entirely whitespace. /// - or - /// or exceeds the maximum length allowed by Discord. /// diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedField.cs b/src/Discord.Net.Core/Entities/Messages/EmbedField.cs index 3ae000022..5d8fd3c6b 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedField.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedField.cs @@ -3,7 +3,7 @@ using System.Diagnostics; namespace Discord { /// - /// Represents a field for an . + /// A field for an . /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public struct EmbedField diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs b/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs index 4368f74a4..d02b2cdc3 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedVideo.cs @@ -13,11 +13,11 @@ namespace Discord /// public string Url { get; } /// - /// Gets the height of the video, or if none. + /// Gets the height of the video, or null if none. /// public int? Height { get; } /// - /// Gets the weight of the video, or if none. + /// Gets the weight of the video, or null if none. /// public int? Width { get; } diff --git a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs index f01876186..5d4d32cfa 100644 --- a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs +++ b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs @@ -6,33 +6,54 @@ namespace Discord public interface IAttachment { /// - /// Gets the snowflake ID of the attachment. + /// Gets the ID of this attachment. /// + /// + /// A snowflake ID associated with this attachment. + /// ulong Id { get; } /// - /// Gets the filename of the attachment. + /// Gets the filename of this attachment. /// + /// + /// A string containing the full filename of this attachment (e.g. textFile.txt). + /// string Filename { get; } /// - /// Gets the URL of the attachment. + /// Gets the URL of this attachment. /// + /// + /// A string containing the URL of this attachment. + /// string Url { get; } /// - /// Gets the proxied URL of the attachment. + /// Gets a proxied URL of this attachment. /// + /// + /// A string containing the proxied URL of this attachment. + /// string ProxyUrl { get; } /// - /// Gets the file size of the attachment. + /// Gets the file size of this attachment. /// + /// + /// The size of this attachment in bytes. + /// int Size { get; } /// - /// Gets the height of the attachment if it is an image, or return when it is not. + /// Gets the height of this attachment. /// + /// + /// The height of this attachment if it is a picture; otherwise null. + /// int? Height { get; } /// - /// Gets the width of the attachment if it is an image, or return when it is not. + /// Gets the width of this attachment. /// + /// + /// The width of this attachment if it is a picture; otherwise null. + /// int? Width { get; } } } diff --git a/src/Discord.Net.Core/Entities/Messages/IEmbed.cs b/src/Discord.Net.Core/Entities/Messages/IEmbed.cs index 473a61ed5..4c1029a10 100644 --- a/src/Discord.Net.Core/Entities/Messages/IEmbed.cs +++ b/src/Discord.Net.Core/Entities/Messages/IEmbed.cs @@ -9,56 +9,96 @@ namespace Discord public interface IEmbed { /// - /// Gets the title URL of the embed. + /// Gets the title URL of this embed. /// + /// + /// A string containing the URL set in a title of the embed. + /// string Url { get; } /// - /// Gets the title of the embed. + /// Gets the title of this embed. /// + /// + /// The title of the embed. + /// string Title { get; } /// - /// Gets the description of the embed. + /// Gets the description of this embed. /// + /// + /// The description field of the embed. + /// string Description { get; } /// - /// Gets the type of the embed. + /// Gets the type of this embed. /// + /// + /// The type of the embed. + /// EmbedType Type { get; } /// - /// Gets the timestamp of the embed, or if none is set. + /// Gets the timestamp of this embed. /// + /// + /// A based on the timestamp present at the bottom left of the embed, or + /// null if none is set. + /// DateTimeOffset? Timestamp { get; } /// - /// Gets the sidebar color of the embed, or if none is set. + /// Gets the color of this embed. /// + /// + /// The color of the embed present on the side of the embed, or null if none is set. + /// Color? Color { get; } /// - /// Gets the image of the embed, or if none is set. + /// Gets the image of this embed. /// + /// + /// The image of the embed, or null if none is set. + /// EmbedImage? Image { get; } /// - /// Gets the video of the embed, or if none is set. + /// Gets the video of this embed. /// + /// + /// The video of the embed, or null if none is set. + /// EmbedVideo? Video { get; } /// - /// Gets the author field of the embed, or if none is set. + /// Gets the author field of this embed. /// + /// + /// The author field of the embed, or null if none is set. + /// EmbedAuthor? Author { get; } /// - /// Gets the footer field of the embed, or if none is set. + /// Gets the footer field of this embed. /// + /// + /// The author field of the embed, or null if none is set. + /// EmbedFooter? Footer { get; } /// - /// Gets the provider of the embed, or if none is set. + /// Gets the provider of this embed. /// + /// + /// The source of the embed, or null if none is set. + /// EmbedProvider? Provider { get; } /// - /// Gets the thumbnail featured in the embed, or if none is set. + /// Gets the thumbnail featured in this embed. /// + /// + /// The thumbnail featured in the embed, or null if none is set. + /// EmbedThumbnail? Thumbnail { get; } /// /// Gets the fields of the embed. /// + /// + /// An array of the fields of the embed. + /// ImmutableArray Fields { get; } } } diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index d66a6b883..edbe4f4b6 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -17,11 +17,11 @@ namespace Discord /// MessageSource Source { get; } /// - /// Returns if this message was sent as a text-to-speech message. + /// Returns true if this message was sent as a text-to-speech message. /// bool IsTTS { get; } /// - /// Returns if this message was added to its channel's pinned messages. + /// Returns true if this message was added to its channel's pinned messages. /// bool IsPinned { get; } /// @@ -31,14 +31,20 @@ namespace Discord /// /// Gets the time this message was sent. /// + /// + /// Time of when the message was sent. + /// DateTimeOffset Timestamp { get; } /// - /// Gets the time of this message's last edit, or if none is set. + /// Gets the time of this message's last edit. /// + /// + /// Time of when the message was last edited; null when the message is never edited. + /// DateTimeOffset? EditedTimestamp { get; } /// - /// Gets the channel this message was sent to. + /// Gets the source channel of the message. /// IMessageChannel Channel { get; } /// @@ -49,10 +55,16 @@ namespace Discord /// /// Returns all attachments included in this message. /// + /// + /// Collection of attachments. + /// IReadOnlyCollection Attachments { get; } /// /// Returns all embeds included in this message. /// + /// + /// Collection of embed objects. + /// IReadOnlyCollection Embeds { get; } /// /// Returns all tags included in this message's content. @@ -61,14 +73,23 @@ namespace Discord /// /// Returns the IDs of channels mentioned in this message. /// + /// + /// Collection of channel IDs. + /// IReadOnlyCollection MentionedChannelIds { get; } /// /// Returns the IDs of roles mentioned in this message. /// + /// + /// Collection of role IDs. + /// IReadOnlyCollection MentionedRoleIds { get; } /// /// Returns the IDs of users mentioned in this message. /// + /// + /// Collection of user IDs. + /// IReadOnlyCollection MentionedUserIds { get; } } } diff --git a/src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs b/src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs index 0f5a171d1..89cd17a35 100644 --- a/src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/ISystemMessage.cs @@ -1,7 +1,7 @@ namespace Discord { /// - /// Represents a message sent by the system. + /// Represents a generic message sent by the system. /// public interface ISystemMessage : IMessage { diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs index 1afb3a3b2..18ef93266 100644 --- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace Discord { /// - /// Represents a Discord message object. + /// Represents a generic message sent by a user. /// public interface IUserMessage : IMessage { diff --git a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs index c2892117a..2cc0eab8e 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs @@ -4,23 +4,9 @@ namespace Discord /// Properties that are used to modify an with the specified changes. /// /// - /// The content of a message can be cleared with if and only if an is present. + /// The content of a message can be cleared with if and only if an is present. /// - /// - /// - /// var message = await ReplyAsync("abc"); - /// await message.ModifyAsync(x => - /// { - /// x.Content = ""; - /// x.Embed = new EmbedBuilder() - /// .WithColor(new Color(40, 40, 120)) - /// .WithAuthor(a => a.Name = "foxbot") - /// .WithTitle("Embed!") - /// .WithDescription("This is an embed.") - /// .Build(); - /// }); - /// - /// + /// public class MessageProperties { /// diff --git a/src/Discord.Net.Core/Entities/Messages/ReactionMetadata.cs b/src/Discord.Net.Core/Entities/Messages/ReactionMetadata.cs index 8ef11bc47..8f2678cd9 100644 --- a/src/Discord.Net.Core/Entities/Messages/ReactionMetadata.cs +++ b/src/Discord.Net.Core/Entities/Messages/ReactionMetadata.cs @@ -11,7 +11,7 @@ namespace Discord public int ReactionCount { get; internal set; } /// - /// Returns if the current user has used this reaction. + /// Returns true if the current user has used this reaction. /// public bool IsMe { get; internal set; } } diff --git a/src/Discord.Net.Core/Entities/Messages/TagHandling.cs b/src/Discord.Net.Core/Entities/Messages/TagHandling.cs index 667f7241b..eaadd6400 100644 --- a/src/Discord.Net.Core/Entities/Messages/TagHandling.cs +++ b/src/Discord.Net.Core/Entities/Messages/TagHandling.cs @@ -1,21 +1,39 @@ namespace Discord { - /// Specifies the handling type the tag should use. + /// + /// Specifies the handling type the tag should use. + /// + /// + /// public enum TagHandling { - /// Tag handling is ignored. - Ignore = 0, //<@53905483156684800> -> <@53905483156684800> - /// Removes the tag entirely. - Remove, //<@53905483156684800> -> - /// Resolves to username (e.g. @User). - Name, //<@53905483156684800> -> @Voltana - /// Resolves to username without mention prefix (e.g. User). - NameNoPrefix, //<@53905483156684800> -> Voltana - /// Resolves to username with discriminator value. (e.g. @User#0001). - FullName, //<@53905483156684800> -> @Voltana#8252 - /// Resolves to username with discriminator value without mention prefix. (e.g. User#0001). - FullNameNoPrefix, //<@53905483156684800> -> Voltana#8252 - /// Sanitizes the tag. - Sanitize //<@53905483156684800> -> <@53905483156684800> (w/ nbsp) + /// + /// Tag handling is ignored (e.g. <@53905483156684800> -> <@53905483156684800>). + /// + Ignore = 0, + /// + /// Removes the tag entirely. + /// + Remove, + /// + /// Resolves to username (e.g. <@53905483156684800> -> @Voltana). + /// + Name, + /// + /// Resolves to username without mention prefix (e.g. <@53905483156684800> -> Voltana). + /// + NameNoPrefix, + /// + /// Resolves to username with discriminator value. (e.g. <@53905483156684800> -> @Voltana#8252). + /// + FullName, + /// + /// Resolves to username with discriminator value without mention prefix. (e.g. <@53905483156684800> -> Voltana#8252). + /// + FullNameNoPrefix, + /// + /// Sanitizes the tag (e.g. <@53905483156684800> -> <@53905483156684800> (w/ nbsp)). + /// + Sanitize } } diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs index 99134bb90..758bc5758 100644 --- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs @@ -12,7 +12,7 @@ namespace Discord /// Gets a that grants all permissions for text channels. public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001); /// Gets a that grants all permissions for voice channels. - public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000000000_010001); + public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000010000_010001); /// Gets a that grants all permissions for category channels. public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001); /// Gets a that grants all permissions for direct message channels. @@ -37,52 +37,52 @@ namespace Discord /// Gets a packed value representing all the permissions in this . public ulong RawValue { get; } - /// If , a user may create invites. + /// If true, a user may create invites. public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); - /// If , a user may create, delete and modify this channel. + /// If true, a user may create, delete and modify this channel. public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannels); - /// If , a user may add reactions. + /// If true, a user may add reactions. public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); - /// If , a user may join channels. + /// If true, a user may join channels. [Obsolete("Use ViewChannel instead.")] public bool ReadMessages => ViewChannel; - /// If , a user may view channels. + /// If true, a user may view channels. public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); - /// If , a user may send messages. + /// If true, a user may send messages. public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); - /// If , a user may send text-to-speech messages. + /// If true, a user may send text-to-speech messages. public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); - /// If , a user may delete messages. + /// If true, a user may delete messages. public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); - /// If , Discord will auto-embed links sent by this user. + /// If true, Discord will auto-embed links sent by this user. public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); - /// If , a user may send files. + /// If true, a user may send files. public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); - /// If , a user may read previous messages. + /// If true, a user may read previous messages. public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); - /// If , a user may mention @everyone. + /// If true, a user may mention @everyone. public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); - /// If , a user may use custom emoji from other guilds. + /// If true, a user may use custom emoji from other guilds. public bool UseExternalEmojis => Permissions.GetValue(RawValue, ChannelPermission.UseExternalEmojis); - /// If , a user may connect to a voice channel. + /// If true, a user may connect to a voice channel. public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); - /// If , a user may speak in a voice channel. + /// If true, a user may speak in a voice channel. public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); - /// If , a user may mute users. + /// If true, a user may mute users. public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); - /// If , a user may deafen users. + /// If true, a user may deafen users. public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); - /// If , a user may move other users between voice channels. + /// If true, a user may move other users between voice channels. public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); - /// If , a user may use voice-activity-detection rather than push-to-talk. + /// If true, a user may use voice-activity-detection rather than push-to-talk. public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); - /// If , a user may adjust role permissions. This also implictly grants all other permissions. + /// If true, a user may adjust role permissions. This also implictly grants all other permissions. public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); - /// If , a user may edit the webhooks for this channel. + /// If true, a user may edit the webhooks for this channel. public bool ManageWebhooks => Permissions.GetValue(RawValue, ChannelPermission.ManageWebhooks); /// Creates a new with the provided packed value. diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs index e1dbb08fd..9a0cb2919 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs @@ -16,65 +16,65 @@ namespace Discord /// Gets a packed value representing all the permissions in this . public ulong RawValue { get; } - /// If , a user may create invites. + /// If true, a user may create invites. public bool CreateInstantInvite => Permissions.GetValue(RawValue, GuildPermission.CreateInstantInvite); - /// If , a user may ban users from the guild. + /// If true, a user may ban users from the guild. public bool BanMembers => Permissions.GetValue(RawValue, GuildPermission.BanMembers); - /// If , a user may kick users from the guild. + /// If true, a user may kick users from the guild. public bool KickMembers => Permissions.GetValue(RawValue, GuildPermission.KickMembers); - /// If , a user is granted all permissions, and cannot have them revoked via channel permissions. + /// If true, a user is granted all permissions, and cannot have them revoked via channel permissions. public bool Administrator => Permissions.GetValue(RawValue, GuildPermission.Administrator); - /// If , a user may create, delete and modify channels. + /// If true, a user may create, delete and modify channels. public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); - /// If , a user may adjust guild properties. + /// If true, a user may adjust guild properties. public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); - /// If , a user may add reactions. + /// If true, a user may add reactions. public bool AddReactions => Permissions.GetValue(RawValue, GuildPermission.AddReactions); - /// If , a user may view the audit log. + /// If true, a user may view the audit log. public bool ViewAuditLog => Permissions.GetValue(RawValue, GuildPermission.ViewAuditLog); - /// If , a user may join channels. + /// If true, a user may join channels. public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages); - /// If , a user may send messages. + /// If true, a user may send messages. public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages); - /// If , a user may send text-to-speech messages. + /// If true, a user may send text-to-speech messages. public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages); - /// If , a user may delete messages. + /// If true, a user may delete messages. public bool ManageMessages => Permissions.GetValue(RawValue, GuildPermission.ManageMessages); - /// If , Discord will auto-embed links sent by this user. + /// If true, Discord will auto-embed links sent by this user. public bool EmbedLinks => Permissions.GetValue(RawValue, GuildPermission.EmbedLinks); - /// If , a user may send files. + /// If true, a user may send files. public bool AttachFiles => Permissions.GetValue(RawValue, GuildPermission.AttachFiles); - /// If , a user may read previous messages. + /// If true, a user may read previous messages. public bool ReadMessageHistory => Permissions.GetValue(RawValue, GuildPermission.ReadMessageHistory); - /// If , a user may mention @everyone. + /// If true, a user may mention @everyone. public bool MentionEveryone => Permissions.GetValue(RawValue, GuildPermission.MentionEveryone); - /// If , a user may use custom emoji from other guilds. + /// If true, a user may use custom emoji from other guilds. public bool UseExternalEmojis => Permissions.GetValue(RawValue, GuildPermission.UseExternalEmojis); - /// If , a user may connect to a voice channel. + /// If true, a user may connect to a voice channel. public bool Connect => Permissions.GetValue(RawValue, GuildPermission.Connect); - /// If , a user may speak in a voice channel. + /// If true, a user may speak in a voice channel. public bool Speak => Permissions.GetValue(RawValue, GuildPermission.Speak); - /// If , a user may mute users. + /// If true, a user may mute users. public bool MuteMembers => Permissions.GetValue(RawValue, GuildPermission.MuteMembers); - /// If , a user may deafen users. + /// If true, a user may deafen users. public bool DeafenMembers => Permissions.GetValue(RawValue, GuildPermission.DeafenMembers); - /// If , a user may move other users between voice channels. + /// If true, a user may move other users between voice channels. public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); - /// If , a user may use voice-activity-detection rather than push-to-talk. + /// If true, a user may use voice-activity-detection rather than push-to-talk. public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); - /// If , a user may change their own nickname. + /// If true, a user may change their own nickname. public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); - /// If , a user may change the nickname of other users. + /// If true, a user may change the nickname of other users. public bool ManageNicknames => Permissions.GetValue(RawValue, GuildPermission.ManageNicknames); - /// If , a user may adjust roles. + /// If true, a user may adjust roles. public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); - /// If , a user may edit the webhooks for this guild. + /// If true, a user may edit the webhooks for this guild. public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); - /// If , a user may edit the emojis for this guild. + /// If true, a user may edit the emojis for this guild. public bool ManageEmojis => Permissions.GetValue(RawValue, GuildPermission.ManageEmojis); /// Creates a new with the provided packed value. diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs index cdee5284d..fa7624a57 100644 --- a/src/Discord.Net.Core/Entities/Roles/Color.cs +++ b/src/Discord.Net.Core/Entities/Roles/Color.cs @@ -4,7 +4,7 @@ using System.Diagnostics; namespace Discord { /// - /// Represents a Discord color. + /// Represents a color used in Discord. /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public struct Color @@ -65,7 +65,7 @@ namespace Discord /// /// Initializes a struct with the given raw value. /// - /// A raw value for the color (e.g. 0x607D8B). + /// The raw value of the color (e.g. 0x607D8B). public Color(uint rawValue) { RawValue = rawValue; @@ -73,9 +73,9 @@ namespace Discord /// /// Initializes a struct with the given RGB bytes. /// - /// The that represents the red color. - /// The that represents the green color. - /// The that represents the blue color. + /// The byte that represents the red color. + /// The byte that represents the green color. + /// The byte that represents the blue color. public Color(byte r, byte g, byte b) { RawValue = @@ -126,8 +126,11 @@ namespace Discord } /// - /// Gets the hexadecimal representation of the color (e.g. #000ccc). + /// Gets the hexadecimal representation of the color (e.g. #000ccc). /// + /// + /// A hexadecimal string of the color. + /// public override string ToString() => $"#{Convert.ToString(RawValue, 16)}"; private string DebuggerDisplay => diff --git a/src/Discord.Net.Core/Entities/Roles/IRole.cs b/src/Discord.Net.Core/Entities/Roles/IRole.cs index f4cb4c64d..c0f4e9942 100644 --- a/src/Discord.Net.Core/Entities/Roles/IRole.cs +++ b/src/Discord.Net.Core/Entities/Roles/IRole.cs @@ -21,24 +21,24 @@ namespace Discord /// Determines whether the role can be separated in the user list. /// /// - /// Returns if users of this role are separated in the user list; otherwise, returns - /// . + /// Returns true if users of this role are separated in the user list; otherwise, returns + /// false. /// bool IsHoisted { get; } /// /// Determines whether the role is managed by Discord. /// /// - /// Returns if this role is automatically managed by Discord; otherwise, returns - /// . + /// Returns true if this role is automatically managed by Discord; otherwise, returns + /// false. /// bool IsManaged { get; } /// /// Determines whether the role is mentionable. /// /// - /// Returns if this role may be mentioned in messages; otherwise, returns - /// . + /// Returns true if this role may be mentioned in messages; otherwise, returns + /// false. /// bool IsMentionable { get; } /// diff --git a/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs b/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs index 79372b86d..54fa27bfd 100644 --- a/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs +++ b/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs @@ -3,16 +3,7 @@ namespace Discord /// /// Properties that are used to modify an with the specified changes. /// - /// - /// - /// await role.ModifyAsync(x => - /// { - /// x.Color = new Color(180, 15, 40); - /// x.Hoist = true; - /// }); - /// - /// - /// + /// public class RoleProperties { /// diff --git a/src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs b/src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs index beb2c392f..27a8be351 100644 --- a/src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs +++ b/src/Discord.Net.Core/Entities/Users/GuildUserProperties.cs @@ -5,36 +5,28 @@ namespace Discord /// /// Properties that are used to modify an with the following parameters. /// - /// - /// - /// await guildUser.ModifyAsync(x => - /// { - /// x.Nickname = $"festive {guildUser.Username}"; - /// }); - /// - /// - /// + /// public class GuildUserProperties { /// /// Gets or sets whether the user should be muted in a voice channel. /// /// - /// If this value is set to , no user will be able to hear this user speak in the guild. + /// If this value is set to true, no user will be able to hear this user speak in the guild. /// public Optional Mute { get; set; } /// /// Gets or sets whether the user should be deafened in a voice channel. /// /// - /// If this value is set to , this user will not be able to hear anyone speak in the guild. + /// If this value is set to true, this user will not be able to hear anyone speak in the guild. /// public Optional Deaf { get; set; } /// /// Gets or sets the user's nickname. /// /// - /// To clear the user's nickname, this value can be set to or + /// To clear the user's nickname, this value can be set to null or /// . /// public Optional Nickname { get; set; } diff --git a/src/Discord.Net.Core/Entities/Users/ISelfUser.cs b/src/Discord.Net.Core/Entities/Users/ISelfUser.cs index 4a97c86ef..1ead0cbba 100644 --- a/src/Discord.Net.Core/Entities/Users/ISelfUser.cs +++ b/src/Discord.Net.Core/Entities/Users/ISelfUser.cs @@ -13,11 +13,11 @@ namespace Discord /// string Email { get; } /// - /// Returns if this user's email has been verified. + /// Returns true if this user's email has been verified. /// bool IsVerified { get; } /// - /// Returns if this user has enabled MFA on their account. + /// Returns true if this user has enabled MFA on their account. /// bool IsMfaEnabled { get; } diff --git a/src/Discord.Net.Core/Entities/Users/IUser.cs b/src/Discord.Net.Core/Entities/Users/IUser.cs index f651a23f3..96b9ae7ee 100644 --- a/src/Discord.Net.Core/Entities/Users/IUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IUser.cs @@ -12,11 +12,18 @@ namespace Discord /// string AvatarId { get; } /// - /// Gets the URL to this user's avatar. - /// + /// Returns a URL to this user's avatar. + /// + /// The format to return. + /// + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// + /// + /// User's avatar URL. + /// string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); /// - /// Gets the URL to this user's default avatar. + /// Returns the URL to this user's default avatar. /// string GetDefaultAvatarUrl(); /// @@ -28,11 +35,11 @@ namespace Discord /// ushort DiscriminatorValue { get; } /// - /// Returns if this user is a bot user. + /// Gets true if this user is a bot user. /// bool IsBot { get; } /// - /// Returns if this user is a webhook user. + /// Gets true if this user is a webhook user. /// bool IsWebhook { get; } /// @@ -43,6 +50,10 @@ namespace Discord /// /// Returns a direct message channel to this user, or create one if it does not already exist. /// + /// The options to be used when sending the request. + /// + /// An awaitable Task containing the DM channel. + /// Task GetOrCreateDMChannelAsync(RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Users/IVoiceState.cs b/src/Discord.Net.Core/Entities/Users/IVoiceState.cs index 725ef2870..abe06c3b3 100644 --- a/src/Discord.Net.Core/Entities/Users/IVoiceState.cs +++ b/src/Discord.Net.Core/Entities/Users/IVoiceState.cs @@ -6,27 +6,27 @@ namespace Discord public interface IVoiceState { /// - /// Returns if the guild has deafened this user. + /// Returns true if the guild has deafened this user. /// bool IsDeafened { get; } /// - /// Returns if the guild has muted this user. + /// Returns true if the guild has muted this user. /// bool IsMuted { get; } /// - /// Returns if this user has marked themselves as deafened. + /// Returns true if this user has marked themselves as deafened. /// bool IsSelfDeafened { get; } /// - /// Returns if this user has marked themselves as muted. + /// Returns true if this user has marked themselves as muted. /// bool IsSelfMuted { get; } /// - /// Returns if the guild is temporarily blocking audio to/from this user. + /// Returns true if the guild is temporarily blocking audio to/from this user. /// bool IsSuppressed { get; } /// - /// Gets the voice channel this user is currently in, or if none. + /// Gets the voice channel this user is currently in, or null if none. /// IVoiceChannel VoiceChannel { get; } /// diff --git a/src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs b/src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs index d79da0265..e2ae12ba4 100644 --- a/src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs +++ b/src/Discord.Net.Core/Entities/Users/SelfUserProperties.cs @@ -3,15 +3,7 @@ namespace Discord /// /// Properties that are used to modify the with the specified changes. /// - /// - /// - /// await Context.Client.CurrentUser.ModifyAsync(x => - /// { - /// x.Avatar = new Image(File.OpenRead("avatar.jpg")); - /// }); - /// - /// - /// + /// public class SelfUserProperties { /// diff --git a/src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs b/src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs index 387ee6106..00af9f9ef 100644 --- a/src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs +++ b/src/Discord.Net.Core/Entities/Webhooks/WebhookProperties.cs @@ -3,16 +3,7 @@ namespace Discord /// /// Properties used to modify an with the specified changes. /// - /// - /// - /// await webhook.ModifyAsync(x => - /// { - /// x.Name = "Bob"; - /// x.Avatar = new Image("avatar.jpg"); - /// }); - /// - /// - /// + /// public class WebhookProperties { /// diff --git a/src/Discord.Net.Core/Entities/Webhooks/WebhookType.cs b/src/Discord.Net.Core/Entities/Webhooks/WebhookType.cs new file mode 100644 index 000000000..0ddfa393d --- /dev/null +++ b/src/Discord.Net.Core/Entities/Webhooks/WebhookType.cs @@ -0,0 +1,14 @@ +namespace Discord +{ + /// + /// Represents the type of a webhook. + /// + /// + /// This type is currently unused, and is only returned in audit log responses. + /// + public enum WebhookType + { + /// An incoming webhook + Incoming = 1 + } +} diff --git a/src/Discord.Net.Core/Extensions/UserExtensions.cs b/src/Discord.Net.Core/Extensions/UserExtensions.cs index ad00296f7..41e84c3cb 100644 --- a/src/Discord.Net.Core/Extensions/UserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/UserExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using System.IO; @@ -6,7 +7,16 @@ namespace Discord /// An extension class for various Discord user objects. public static class UserExtensions { - /// Sends a message to the user via DM. + /// + /// Sends a message via DM. + /// + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// An awaitable Task containing the message sent to the channel. + /// public static async Task SendMessageAsync(this IUser user, string text, bool isTTS = false, @@ -16,7 +26,23 @@ namespace Discord return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options).ConfigureAwait(false); } - /// Sends a file to the user via DM. + /// + /// Sends a file to this message channel with an optional caption. + /// + /// The of the file to be sent. + /// The name of the attachment. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// If you wish to upload an image and have it embedded in a embed, you may + /// upload the file and refer to the file with "attachment://filename.ext" in the + /// . + /// + /// + /// An awaitable Task containing the message sent to the channel. + /// public static async Task SendFileAsync(this IUser user, Stream stream, string filename, @@ -30,7 +56,22 @@ namespace Discord } #if FILESYSTEM - /// Sends a file to the user via DM. + /// + /// Sends a file via DM with an optional caption. + /// + /// The file path of the file. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// If you wish to upload an image and have it embedded in a embed, you may + /// upload the file and refer to the file with "attachment://filename.ext" in the + /// . + /// + /// + /// An awaitable Task containing the message sent to the channel. + /// public static async Task SendFileAsync(this IUser user, string filePath, string text = null, @@ -41,10 +82,15 @@ namespace Discord return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false); } #endif - /// Bans the provided user from the guild and optionally prunes their recent messages. - /// The user to ban. - /// The number of days to remove messages from this user for - must be between [0, 7] - /// The reason of the ban to be written in the audit log. + /// + /// Bans the provided user from the guild and optionally prunes their recent messages. + /// + /// The user to ban. + /// + /// The number of days to remove messages from this user for - must be between [0, 7] + /// + /// The reason of the ban to be written in the audit log. + /// is not between 0 to 7. public static Task BanAsync(this IGuildUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) => user.Guild.AddBanAsync(user, pruneDays, reason, options); } diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index 92aee2b08..f5bbd0a28 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -10,16 +10,33 @@ namespace Discord /// public interface IDiscordClient : IDisposable { + /// + /// Gets the current state of connection. + /// ConnectionState ConnectionState { get; } + /// + /// Gets the currently logged-in user. + /// ISelfUser CurrentUser { get; } + /// + /// Gets the token type of the logged-in user. + /// TokenType TokenType { get; } Task StartAsync(); Task StopAsync(); /// - /// Gets the application information associated with this account. + /// Gets a Discord application information for the logged-in user. /// + /// + /// This method reflects your application information you submitted when creating a Discord application via + /// the Developer Portal. + /// + /// The options to be used when sending the request. + /// + /// An awaitable containing the application information. + /// Task GetApplicationInfoAsync(RequestOptions options = null); /// @@ -36,11 +53,21 @@ namespace Discord /// Task> GetPrivateChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// - /// Gets a list of direct message channels. + /// Returns a collection of direct message channels. /// + /// + /// This method returns a collection of currently opened direct message channels. + /// + /// This method will not return previously opened DM channels outside of the current session! If you + /// have just started the client, this may return an empty collection. + /// + /// /// /// The that determines whether the object should be fetched from cache. /// + /// + /// An awaitable containing a collection of DM channels. + /// Task> GetDMChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// /// Gets a list of group channels. diff --git a/src/Discord.Net.Core/Net/HttpException.cs b/src/Discord.Net.Core/Net/HttpException.cs index c49273451..aa440bf1c 100644 --- a/src/Discord.Net.Core/Net/HttpException.cs +++ b/src/Discord.Net.Core/Net/HttpException.cs @@ -23,7 +23,7 @@ namespace Discord.Net /// /// A /// JSON error code - /// from Discord, or if none. + /// from Discord, or null if none. /// public int? DiscordCode { get; } /// diff --git a/src/Discord.Net.Core/RequestOptions.cs b/src/Discord.Net.Core/RequestOptions.cs index 2318f3f98..c2d1f6549 100644 --- a/src/Discord.Net.Core/RequestOptions.cs +++ b/src/Discord.Net.Core/RequestOptions.cs @@ -14,7 +14,7 @@ namespace Discord /// /// Gets or set the max time, in milliseconds, to wait for this request to complete. If - /// , a request will not time out. If a rate limit has been triggered for this + /// null, a request will not time out. If a rate limit has been triggered for this /// request's bucket and will not be unpaused in time, this request will fail immediately. /// public int? Timeout { get; set; } diff --git a/src/Discord.Net.Core/Utils/Cacheable.cs b/src/Discord.Net.Core/Utils/Cacheable.cs index 15358dda0..02da682ae 100644 --- a/src/Discord.Net.Core/Utils/Cacheable.cs +++ b/src/Discord.Net.Core/Utils/Cacheable.cs @@ -25,7 +25,7 @@ namespace Discord /// /// /// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is - /// . + /// null. /// public TEntity Value { get; } private Func> DownloadFunc { get; } diff --git a/src/Discord.Net.Core/Utils/ConcurrentHashSet.cs b/src/Discord.Net.Core/Utils/ConcurrentHashSet.cs index 233d1b0b0..bbdc59087 100644 --- a/src/Discord.Net.Core/Utils/ConcurrentHashSet.cs +++ b/src/Discord.Net.Core/Utils/ConcurrentHashSet.cs @@ -157,7 +157,7 @@ namespace Discord : this(collection, EqualityComparer.Default) { } public ConcurrentHashSet(IEqualityComparer comparer) : this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { } - /// is + /// is null public ConcurrentHashSet(IEnumerable collection, IEqualityComparer comparer) : this(comparer) { @@ -165,7 +165,7 @@ namespace Discord InitializeFromCollection(collection); } /// - /// or is + /// or is null /// public ConcurrentHashSet(int concurrencyLevel, IEnumerable collection, IEqualityComparer comparer) : this(concurrencyLevel, DefaultCapacity, false, comparer) @@ -210,7 +210,7 @@ namespace Discord if (_budget == 0) _budget = _tables._buckets.Length / _tables._locks.Length; } - /// is + /// is null public bool ContainsKey(T value) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -234,7 +234,7 @@ namespace Discord return false; } - /// is + /// is null public bool TryAdd(T value) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -284,7 +284,7 @@ namespace Discord } } - /// is + /// is null public bool TryRemove(T value) { if (value == null) throw new ArgumentNullException(nameof(value)); diff --git a/src/Discord.Net.Core/Utils/MentionUtils.cs b/src/Discord.Net.Core/Utils/MentionUtils.cs index edfd3b12c..ae506e142 100644 --- a/src/Discord.Net.Core/Utils/MentionUtils.cs +++ b/src/Discord.Net.Core/Utils/MentionUtils.cs @@ -16,16 +16,25 @@ namespace Discord /// /// Returns a mention string based on the user ID. /// + /// + /// A user mention string (e.g. <@80351110224678912>). + /// public static string MentionUser(ulong id) => MentionUser(id.ToString(), true); internal static string MentionChannel(string id) => $"<#{id}>"; /// /// Returns a mention string based on the channel ID. /// + /// + /// A channel mention string (e.g. <#103735883630395392>). + /// public static string MentionChannel(ulong id) => MentionChannel(id.ToString()); internal static string MentionRole(string id) => $"<@&{id}>"; /// /// Returns a mention string based on the role ID. /// + /// + /// A role mention string (e.g. <@&165511591545143296>). + /// public static string MentionRole(ulong id) => MentionRole(id.ToString()); /// diff --git a/src/Discord.Net.Rest/API/Common/AuditLog.cs b/src/Discord.Net.Rest/API/Common/AuditLog.cs new file mode 100644 index 000000000..cd8ad147d --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AuditLog.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class AuditLog + { + [JsonProperty("webhooks")] + public Webhook[] Webhooks { get; set; } + + [JsonProperty("users")] + public User[] Users { get; set; } + + [JsonProperty("audit_log_entries")] + public AuditLogEntry[] Entries { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AuditLogChange.cs b/src/Discord.Net.Rest/API/Common/AuditLogChange.cs new file mode 100644 index 000000000..44e585021 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AuditLogChange.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Discord.API +{ + internal class AuditLogChange + { + [JsonProperty("key")] + public string ChangedProperty { get; set; } + + [JsonProperty("new_value")] + public JToken NewValue { get; set; } + + [JsonProperty("old_value")] + public JToken OldValue { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs new file mode 100644 index 000000000..80d9a9e97 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class AuditLogEntry + { + [JsonProperty("target_id")] + public ulong? TargetId { get; set; } + [JsonProperty("user_id")] + public ulong UserId { get; set; } + + [JsonProperty("changes")] + public AuditLogChange[] Changes { get; set; } + [JsonProperty("options")] + public AuditLogOptions Options { get; set; } + + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("action_type")] + public ActionType Action { get; set; } + + [JsonProperty("reason")] + public string Reason { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs b/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs new file mode 100644 index 000000000..65b401cce --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AuditLogOptions.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class AuditLogOptions + { + //Message delete + [JsonProperty("count")] + public int? MessageDeleteCount { get; set; } + [JsonProperty("channel_id")] + public ulong? MessageDeleteChannelId { get; set; } + + //Prune + [JsonProperty("delete_member_days")] + public int? PruneDeleteMemberDays { get; set; } + [JsonProperty("members_removed")] + public int? PruneMembersRemoved { get; set; } + + //Overwrite Update + [JsonProperty("role_name")] + public string OverwriteRoleName { get; set; } + [JsonProperty("type")] + public string OverwriteType { get; set; } + [JsonProperty("id")] + public ulong? OverwriteTargetId { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs b/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs new file mode 100644 index 000000000..ceabccbc8 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs @@ -0,0 +1,8 @@ +namespace Discord.API.Rest +{ + class GetAuditLogsParams + { + public Optional Limit { get; set; } + public Optional BeforeEntryId { get; set; } + } +} diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index c59fd0e42..f23547106 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -812,6 +812,15 @@ namespace Discord.API var ids = new BucketIds(guildId: guildId); return await SendAsync>("GET", () => $"guilds/{guildId}/bans", ids, options: options).ConfigureAwait(false); } + public async Task GetGuildBanAsync(ulong guildId, ulong userId, RequestOptions options) + { + Preconditions.NotEqual(userId, 0, nameof(userId)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + return await SendAsync("GET", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); + } public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -1209,6 +1218,26 @@ namespace Discord.API return await SendAsync>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false); } + //Audit logs + public async Task GetAuditLogsAsync(ulong guildId, GetAuditLogsParams args, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotNull(args, nameof(args)); + options = RequestOptions.CreateOrClone(options); + + int limit = args.Limit.GetValueOrDefault(int.MaxValue); + + var ids = new BucketIds(guildId: guildId); + Expression> endpoint; + + if (args.BeforeEntryId.IsSpecified) + endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}&before={args.BeforeEntryId.Value}"; + else + endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}"; + + return await SendAsync("GET", endpoint, ids, options: options).ConfigureAwait(false); + } + //Webhooks public async Task CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null) { diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs new file mode 100644 index 000000000..7936343f3 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + internal static class AuditLogHelper + { + private static readonly Dictionary> CreateMapping + = new Dictionary>() + { + [ActionType.GuildUpdated] = GuildUpdateAuditLogData.Create, + + [ActionType.ChannelCreated] = ChannelCreateAuditLogData.Create, + [ActionType.ChannelUpdated] = ChannelUpdateAuditLogData.Create, + [ActionType.ChannelDeleted] = ChannelDeleteAuditLogData.Create, + + [ActionType.OverwriteCreated] = OverwriteCreateAuditLogData.Create, + [ActionType.OverwriteUpdated] = OverwriteUpdateAuditLogData.Create, + [ActionType.OverwriteDeleted] = OverwriteDeleteAuditLogData.Create, + + [ActionType.Kick] = KickAuditLogData.Create, + [ActionType.Prune] = PruneAuditLogData.Create, + [ActionType.Ban] = BanAuditLogData.Create, + [ActionType.Unban] = UnbanAuditLogData.Create, + [ActionType.MemberUpdated] = MemberUpdateAuditLogData.Create, + [ActionType.MemberRoleUpdated] = MemberRoleAuditLogData.Create, + + [ActionType.RoleCreated] = RoleCreateAuditLogData.Create, + [ActionType.RoleUpdated] = RoleUpdateAuditLogData.Create, + [ActionType.RoleDeleted] = RoleDeleteAuditLogData.Create, + + [ActionType.InviteCreated] = InviteCreateAuditLogData.Create, + [ActionType.InviteUpdated] = InviteUpdateAuditLogData.Create, + [ActionType.InviteDeleted] = InviteDeleteAuditLogData.Create, + + [ActionType.WebhookCreated] = WebhookCreateAuditLogData.Create, + [ActionType.WebhookUpdated] = WebhookUpdateAuditLogData.Create, + [ActionType.WebhookDeleted] = WebhookDeleteAuditLogData.Create, + + [ActionType.EmojiCreated] = EmoteCreateAuditLogData.Create, + [ActionType.EmojiUpdated] = EmoteUpdateAuditLogData.Create, + [ActionType.EmojiDeleted] = EmoteDeleteAuditLogData.Create, + + [ActionType.MessageDeleted] = MessageDeleteAuditLogData.Create, + }; + + public static IAuditLogData CreateData(BaseDiscordClient discord, Model log, EntryModel entry) + { + if (CreateMapping.TryGetValue(entry.Action, out var func)) + return func(discord, log, entry); + + return null; + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs new file mode 100644 index 000000000..4b9d5875f --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class BanAuditLogData : IAuditLogData + { + private BanAuditLogData(IUser user) + { + Target = user; + } + + internal static BanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + return new BanAuditLogData(RestUser.Create(discord, userInfo)); + } + + public IUser Target { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs new file mode 100644 index 000000000..ef4787295 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs @@ -0,0 +1,52 @@ +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class ChannelCreateAuditLogData : IAuditLogData + { + private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection overwrites) + { + ChannelId = id; + ChannelName = name; + ChannelType = type; + Overwrites = overwrites; + } + + internal static ChannelCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + var overwrites = new List(); + + var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); + var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var type = typeModel.NewValue.ToObject(); + var name = nameModel.NewValue.ToObject(); + + foreach (var overwrite in overwritesModel.NewValue) + { + var deny = overwrite.Value("deny"); + var _type = overwrite.Value("type"); + var id = overwrite.Value("id"); + var allow = overwrite.Value("allow"); + + PermissionTarget permType = _type == "member" ? PermissionTarget.User : PermissionTarget.Role; + + overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny))); + } + + return new ChannelCreateAuditLogData(entry.TargetId.Value, name, type, overwrites.ToReadOnlyCollection()); + } + + public ulong ChannelId { get; } + public string ChannelName { get; } + public ChannelType ChannelType { get; } + public IReadOnlyCollection Overwrites { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs new file mode 100644 index 000000000..4816ce770 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class ChannelDeleteAuditLogData : IAuditLogData + { + private ChannelDeleteAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection overwrites) + { + ChannelId = id; + ChannelName = name; + ChannelType = type; + Overwrites = overwrites; + } + + internal static ChannelDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); + var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var overwrites = overwritesModel.OldValue.ToObject() + .Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny))) + .ToList(); + var type = typeModel.OldValue.ToObject(); + var name = nameModel.OldValue.ToObject(); + var id = entry.TargetId.Value; + + return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection()); + } + + public ulong ChannelId { get; } + public string ChannelName { get; } + public ChannelType ChannelType { get; } + public IReadOnlyCollection Overwrites { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs new file mode 100644 index 000000000..e2d6064a9 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs @@ -0,0 +1,18 @@ +namespace Discord.Rest +{ + public struct ChannelInfo + { + internal ChannelInfo(string name, string topic, int? bitrate, int? limit) + { + Name = name; + Topic = topic; + Bitrate = bitrate; + UserLimit = limit; + } + + public string Name { get; } + public string Topic { get; } + public int? Bitrate { get; } + public int? UserLimit { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs new file mode 100644 index 000000000..f3403138d --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs @@ -0,0 +1,45 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class ChannelUpdateAuditLogData : IAuditLogData + { + private ChannelUpdateAuditLogData(ulong id, ChannelInfo before, ChannelInfo after) + { + ChannelId = id; + Before = before; + After = after; + } + + internal static ChannelUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var topicModel = changes.FirstOrDefault(x => x.ChangedProperty == "topic"); + var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate"); + var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit"); + + string oldName = nameModel?.OldValue?.ToObject(), + newName = nameModel?.NewValue?.ToObject(); + string oldTopic = topicModel?.OldValue?.ToObject(), + newTopic = topicModel?.NewValue?.ToObject(); + int? oldBitrate = bitrateModel?.OldValue?.ToObject(), + newBitrate = bitrateModel?.NewValue?.ToObject(); + int? oldLimit = userLimitModel?.OldValue?.ToObject(), + newLimit = userLimitModel?.NewValue?.ToObject(); + + var before = new ChannelInfo(oldName, oldTopic, oldBitrate, oldLimit); + var after = new ChannelInfo(newName, newTopic, newBitrate, newLimit); + + return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after); + } + + public ulong ChannelId { get; } + public ChannelInfo Before { get; set; } + public ChannelInfo After { get; set; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs new file mode 100644 index 000000000..5d1ef8463 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class EmoteCreateAuditLogData : IAuditLogData + { + private EmoteCreateAuditLogData(ulong id, string name) + { + EmoteId = id; + Name = name; + } + + internal static EmoteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var emoteName = change.NewValue?.ToObject(); + return new EmoteCreateAuditLogData(entry.TargetId.Value, emoteName); + } + + public ulong EmoteId { get; } + public string Name { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs new file mode 100644 index 000000000..d0a11191f --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs @@ -0,0 +1,28 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class EmoteDeleteAuditLogData : IAuditLogData + { + private EmoteDeleteAuditLogData(ulong id, string name) + { + EmoteId = id; + Name = name; + } + + internal static EmoteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var emoteName = change.OldValue?.ToObject(); + + return new EmoteDeleteAuditLogData(entry.TargetId.Value, emoteName); + } + + public ulong EmoteId { get; } + public string Name { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs new file mode 100644 index 000000000..60020bcaa --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs @@ -0,0 +1,31 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class EmoteUpdateAuditLogData : IAuditLogData + { + private EmoteUpdateAuditLogData(ulong id, string oldName, string newName) + { + EmoteId = id; + OldName = oldName; + NewName = newName; + } + + internal static EmoteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var newName = change.NewValue?.ToObject(); + var oldName = change.OldValue?.ToObject(); + + return new EmoteUpdateAuditLogData(entry.TargetId.Value, oldName, newName); + } + + public ulong EmoteId { get; } + public string NewName { get; } + public string OldName { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildInfo.cs new file mode 100644 index 000000000..90865ef72 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildInfo.cs @@ -0,0 +1,32 @@ +namespace Discord.Rest +{ + public struct GuildInfo + { + internal GuildInfo(int? afkTimeout, DefaultMessageNotifications? defaultNotifs, + ulong? afkChannel, string name, string region, string icon, + VerificationLevel? verification, IUser owner, MfaLevel? mfa, int? filter) + { + AfkTimeout = afkTimeout; + DefaultMessageNotifications = defaultNotifs; + AfkChannelId = afkChannel; + Name = name; + RegionId = region; + IconHash = icon; + VerificationLevel = verification; + Owner = owner; + MfaLevel = mfa; + ContentFilterLevel = filter; + } + + public int? AfkTimeout { get; } + public DefaultMessageNotifications? DefaultMessageNotifications { get; } + public ulong? AfkChannelId { get; } + public string Name { get; } + public string RegionId { get; } + public string IconHash { get; } + public VerificationLevel? VerificationLevel { get; } + public IUser Owner { get; } + public MfaLevel? MfaLevel { get; } + public int? ContentFilterLevel { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs new file mode 100644 index 000000000..08550ed7a --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs @@ -0,0 +1,79 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class GuildUpdateAuditLogData : IAuditLogData + { + private GuildUpdateAuditLogData(GuildInfo before, GuildInfo after) + { + Before = before; + After = after; + } + + internal static GuildUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var afkTimeoutModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var defaultMessageNotificationsModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var afkChannelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var regionIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var iconHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var verificationLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var ownerIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); + + int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject(), + newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject(); + DefaultMessageNotifications? oldDefaultMessageNotifications = defaultMessageNotificationsModel?.OldValue?.ToObject(), + newDefaultMessageNotifications = defaultMessageNotificationsModel?.NewValue?.ToObject(); + ulong? oldAfkChannelId = afkChannelModel?.OldValue?.ToObject(), + newAfkChannelId = afkChannelModel?.NewValue?.ToObject(); + string oldName = nameModel?.OldValue?.ToObject(), + newName = nameModel?.NewValue?.ToObject(); + string oldRegionId = regionIdModel?.OldValue?.ToObject(), + newRegionId = regionIdModel?.NewValue?.ToObject(); + string oldIconHash = iconHashModel?.OldValue?.ToObject(), + newIconHash = iconHashModel?.NewValue?.ToObject(); + VerificationLevel? oldVerificationLevel = verificationLevelModel?.OldValue?.ToObject(), + newVerificationLevel = verificationLevelModel?.NewValue?.ToObject(); + ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject(), + newOwnerId = ownerIdModel?.NewValue?.ToObject(); + MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject(), + newMfaLevel = mfaLevelModel?.NewValue?.ToObject(); + int? oldContentFilter = contentFilterModel?.OldValue?.ToObject(), + newContentFilter = contentFilterModel?.NewValue?.ToObject(); + + IUser oldOwner = null; + if (oldOwnerId != null) + { + var oldOwnerInfo = log.Users.FirstOrDefault(x => x.Id == oldOwnerId.Value); + oldOwner = RestUser.Create(discord, oldOwnerInfo); + } + + IUser newOwner = null; + if (newOwnerId != null) + { + var newOwnerInfo = log.Users.FirstOrDefault(x => x.Id == newOwnerId.Value); + newOwner = RestUser.Create(discord, newOwnerInfo); + } + + var before = new GuildInfo(oldAfkTimeout, oldDefaultMessageNotifications, + oldAfkChannelId, oldName, oldRegionId, oldIconHash, oldVerificationLevel, oldOwner, + oldMfaLevel, oldContentFilter); + var after = new GuildInfo(newAfkTimeout, newDefaultMessageNotifications, + newAfkChannelId, newName, newRegionId, newIconHash, newVerificationLevel, newOwner, + newMfaLevel, newContentFilter); + + return new GuildUpdateAuditLogData(before, after); + } + + public GuildInfo Before { get; } + public GuildInfo After { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs new file mode 100644 index 000000000..292715420 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs @@ -0,0 +1,55 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class InviteCreateAuditLogData : IAuditLogData + { + private InviteCreateAuditLogData(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses) + { + MaxAge = maxAge; + Code = code; + Temporary = temporary; + Creator = inviter; + ChannelId = channelId; + Uses = uses; + MaxUses = maxUses; + } + + internal static InviteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); + var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code"); + var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary"); + var inviterIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "inviter_id"); + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); + var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); + + var maxAge = maxAgeModel.NewValue.ToObject(); + var code = codeModel.NewValue.ToObject(); + var temporary = temporaryModel.NewValue.ToObject(); + var inviterId = inviterIdModel.NewValue.ToObject(); + var channelId = channelIdModel.NewValue.ToObject(); + var uses = usesModel.NewValue.ToObject(); + var maxUses = maxUsesModel.NewValue.ToObject(); + + var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); + var inviter = RestUser.Create(discord, inviterInfo); + + return new InviteCreateAuditLogData(maxAge, code, temporary, inviter, channelId, uses, maxUses); + } + + public int MaxAge { get; } + public string Code { get; } + public bool Temporary { get; } + public IUser Creator { get; } + public ulong ChannelId { get; } + public int Uses { get; } + public int MaxUses { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs new file mode 100644 index 000000000..1dc6d518b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs @@ -0,0 +1,55 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class InviteDeleteAuditLogData : IAuditLogData + { + private InviteDeleteAuditLogData(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses) + { + MaxAge = maxAge; + Code = code; + Temporary = temporary; + Creator = inviter; + ChannelId = channelId; + Uses = uses; + MaxUses = maxUses; + } + + internal static InviteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); + var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code"); + var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary"); + var inviterIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "inviter_id"); + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); + var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); + + var maxAge = maxAgeModel.OldValue.ToObject(); + var code = codeModel.OldValue.ToObject(); + var temporary = temporaryModel.OldValue.ToObject(); + var inviterId = inviterIdModel.OldValue.ToObject(); + var channelId = channelIdModel.OldValue.ToObject(); + var uses = usesModel.OldValue.ToObject(); + var maxUses = maxUsesModel.OldValue.ToObject(); + + var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); + var inviter = RestUser.Create(discord, inviterInfo); + + return new InviteDeleteAuditLogData(maxAge, code, temporary, inviter, channelId, uses, maxUses); + } + + public int MaxAge { get; } + public string Code { get; } + public bool Temporary { get; } + public IUser Creator { get; } + public ulong ChannelId { get; } + public int Uses { get; } + public int MaxUses { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteInfo.cs new file mode 100644 index 000000000..c9840f6cc --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteInfo.cs @@ -0,0 +1,20 @@ +namespace Discord.Rest +{ + public struct InviteInfo + { + internal InviteInfo(int? maxAge, string code, bool? temporary, ulong? channelId, int? maxUses) + { + MaxAge = maxAge; + Code = code; + Temporary = temporary; + ChannelId = channelId; + MaxUses = maxUses; + } + + public int? MaxAge { get; } + public string Code { get; } + public bool? Temporary { get; } + public ulong? ChannelId { get; } + public int? MaxUses { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs new file mode 100644 index 000000000..b932cfbfc --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs @@ -0,0 +1,46 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class InviteUpdateAuditLogData : IAuditLogData + { + private InviteUpdateAuditLogData(InviteInfo before, InviteInfo after) + { + Before = before; + After = after; + } + + internal static InviteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); + var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code"); + var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary"); + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); + + int? oldMaxAge = maxAgeModel?.OldValue?.ToObject(), + newMaxAge = maxAgeModel?.NewValue?.ToObject(); + string oldCode = codeModel?.OldValue?.ToObject(), + newCode = codeModel?.NewValue?.ToObject(); + bool? oldTemporary = temporaryModel?.OldValue?.ToObject(), + newTemporary = temporaryModel?.NewValue?.ToObject(); + ulong? oldChannelId = channelIdModel?.OldValue?.ToObject(), + newChannelId = channelIdModel?.NewValue?.ToObject(); + int? oldMaxUses = maxUsesModel?.OldValue?.ToObject(), + newMaxUses = maxUsesModel?.NewValue?.ToObject(); + + var before = new InviteInfo(oldMaxAge, oldCode, oldTemporary, oldChannelId, oldMaxUses); + var after = new InviteInfo(newMaxAge, newCode, newTemporary, newChannelId, newMaxUses); + + return new InviteUpdateAuditLogData(before, after); + } + + public InviteInfo Before { get; } + public InviteInfo After { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs new file mode 100644 index 000000000..41b5526b8 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class KickAuditLogData : IAuditLogData + { + private KickAuditLogData(RestUser user) + { + Target = user; + } + + internal static KickAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + return new KickAuditLogData(RestUser.Create(discord, userInfo)); + } + + public IUser Target { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs new file mode 100644 index 000000000..b0f0a1fe1 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class MemberRoleAuditLogData : IAuditLogData + { + private MemberRoleAuditLogData(IReadOnlyCollection roles, IUser target) + { + Roles = roles; + Target = target; + } + + internal static MemberRoleAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var roleInfos = changes.SelectMany(x => x.NewValue.ToObject(), + (model, role) => new { model.ChangedProperty, Role = role }) + .Select(x => new RoleInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add")) + .ToList(); + + var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + var user = RestUser.Create(discord, userInfo); + + return new MemberRoleAuditLogData(roleInfos.ToReadOnlyCollection(), user); + } + + public IReadOnlyCollection Roles { get; } + public IUser Target { get; } + + public struct RoleInfo + { + internal RoleInfo(string name, ulong roleId, bool added) + { + Name = name; + RoleId = roleId; + Added = added; + } + + public string Name { get; } + public ulong RoleId { get; } + public bool Added { get; } + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs new file mode 100644 index 000000000..38f078848 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs @@ -0,0 +1,35 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class MemberUpdateAuditLogData : IAuditLogData + { + private MemberUpdateAuditLogData(IUser target, string newNick, string oldNick) + { + Target = target; + NewNick = newNick; + OldNick = oldNick; + } + + internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "nick"); + + var newNick = changes.NewValue?.ToObject(); + var oldNick = changes.OldValue?.ToObject(); + + var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + var user = RestUser.Create(discord, targetInfo); + + return new MemberUpdateAuditLogData(user, newNick, oldNick); + } + + public IUser Target { get; } + public string NewNick { get; } + public string OldNick { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs new file mode 100644 index 000000000..3949cdd68 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs @@ -0,0 +1,22 @@ +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class MessageDeleteAuditLogData : IAuditLogData + { + private MessageDeleteAuditLogData(ulong channelId, int count) + { + ChannelId = channelId; + MessageCount = count; + } + + internal static MessageDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + return new MessageDeleteAuditLogData(entry.Options.MessageDeleteChannelId.Value, entry.Options.MessageDeleteCount.Value); + } + + public int MessageCount { get; } + public ulong ChannelId { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs new file mode 100644 index 000000000..d58488136 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs @@ -0,0 +1,37 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class OverwriteCreateAuditLogData : IAuditLogData + { + private OverwriteCreateAuditLogData(Overwrite overwrite) + { + Overwrite = overwrite; + } + + internal static OverwriteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); + var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); + + var deny = denyModel.NewValue.ToObject(); + var allow = allowModel.NewValue.ToObject(); + + var permissions = new OverwritePermissions(allow, deny); + + var id = entry.Options.OverwriteTargetId.Value; + var type = entry.Options.OverwriteType; + + PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role; + + return new OverwriteCreateAuditLogData(new Overwrite(id, target, permissions)); + } + + public Overwrite Overwrite { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs new file mode 100644 index 000000000..445c2e302 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; +using OptionModel = Discord.API.AuditLogOptions; + +namespace Discord.Rest +{ + public class OverwriteDeleteAuditLogData : IAuditLogData + { + private OverwriteDeleteAuditLogData(Overwrite deletedOverwrite) + { + Overwrite = deletedOverwrite; + } + + internal static OverwriteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); + var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); + var idModel = changes.FirstOrDefault(x => x.ChangedProperty == "id"); + var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); + + var deny = denyModel.OldValue.ToObject(); + var type = typeModel.OldValue.ToObject(); + var id = idModel.OldValue.ToObject(); + var allow = allowModel.OldValue.ToObject(); + + PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role; + + return new OverwriteDeleteAuditLogData(new Overwrite(id, target, new OverwritePermissions(allow, deny))); + } + + public Overwrite Overwrite { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs new file mode 100644 index 000000000..d000146c3 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs @@ -0,0 +1,44 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class OverwriteUpdateAuditLogData : IAuditLogData + { + private OverwriteUpdateAuditLogData(OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType) + { + OldPermissions = before; + NewPermissions = after; + OverwriteTargetId = targetId; + OverwriteType = targetType; + } + + internal static OverwriteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); + var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); + + var beforeAllow = allowModel?.OldValue?.ToObject(); + var afterAllow = allowModel?.NewValue?.ToObject(); + var beforeDeny = denyModel?.OldValue?.ToObject(); + var afterDeny = denyModel?.OldValue?.ToObject(); + + var beforePermissions = new OverwritePermissions(beforeAllow ?? 0, beforeDeny ?? 0); + var afterPermissions = new OverwritePermissions(afterAllow ?? 0, afterDeny ?? 0); + + PermissionTarget target = entry.Options.OverwriteType == "member" ? PermissionTarget.User : PermissionTarget.Role; + + return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, target); + } + + public OverwritePermissions OldPermissions { get; } + public OverwritePermissions NewPermissions { get; } + + public ulong OverwriteTargetId { get; } + public PermissionTarget OverwriteType { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs new file mode 100644 index 000000000..0005e304d --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs @@ -0,0 +1,22 @@ +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class PruneAuditLogData : IAuditLogData + { + private PruneAuditLogData(int pruneDays, int membersRemoved) + { + PruneDays = pruneDays; + MembersRemoved = membersRemoved; + } + + internal static PruneAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + return new PruneAuditLogData(entry.Options.PruneDeleteMemberDays.Value, entry.Options.PruneMembersRemoved.Value); + } + + public int PruneDays { get; } + public int MembersRemoved { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs new file mode 100644 index 000000000..aa951d6e7 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs @@ -0,0 +1,47 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class RoleCreateAuditLogData : IAuditLogData + { + private RoleCreateAuditLogData(ulong id, RoleInfo props) + { + RoleId = id; + Properties = props; + } + + internal static RoleCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); + var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable"); + var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); + + uint? colorRaw = colorModel?.NewValue?.ToObject(); + bool? mentionable = mentionableModel?.NewValue?.ToObject(); + bool? hoist = hoistModel?.NewValue?.ToObject(); + string name = nameModel?.NewValue?.ToObject(); + ulong? permissionsRaw = permissionsModel?.NewValue?.ToObject(); + + Color? color = null; + GuildPermissions? permissions = null; + + if (colorRaw.HasValue) + color = new Color(colorRaw.Value); + if (permissionsRaw.HasValue) + permissions = new GuildPermissions(permissionsRaw.Value); + + return new RoleCreateAuditLogData(entry.TargetId.Value, + new RoleInfo(color, mentionable, hoist, name, permissions)); + } + + public ulong RoleId { get; } + public RoleInfo Properties { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs new file mode 100644 index 000000000..e90d70d4d --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs @@ -0,0 +1,47 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class RoleDeleteAuditLogData : IAuditLogData + { + private RoleDeleteAuditLogData(ulong id, RoleInfo props) + { + RoleId = id; + Properties = props; + } + + internal static RoleDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); + var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable"); + var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); + + uint? colorRaw = colorModel?.OldValue?.ToObject(); + bool? mentionable = mentionableModel?.OldValue?.ToObject(); + bool? hoist = hoistModel?.OldValue?.ToObject(); + string name = nameModel?.OldValue?.ToObject(); + ulong? permissionsRaw = permissionsModel?.OldValue?.ToObject(); + + Color? color = null; + GuildPermissions? permissions = null; + + if (colorRaw.HasValue) + color = new Color(colorRaw.Value); + if (permissionsRaw.HasValue) + permissions = new GuildPermissions(permissionsRaw.Value); + + return new RoleDeleteAuditLogData(entry.TargetId.Value, + new RoleInfo(color, mentionable, hoist, name, permissions)); + } + + public ulong RoleId { get; } + public RoleInfo Properties { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleInfo.cs new file mode 100644 index 000000000..2208990e6 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleInfo.cs @@ -0,0 +1,21 @@ +namespace Discord.Rest +{ + public struct RoleInfo + { + internal RoleInfo(Color? color, bool? mentionable, bool? hoist, string name, + GuildPermissions? permissions) + { + Color = color; + Mentionable = mentionable; + Hoist = hoist; + Name = name; + Permissions = permissions; + } + + public Color? Color { get; } + public bool? Mentionable { get; } + public bool? Hoist { get; } + public string Name { get; } + public GuildPermissions? Permissions { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs new file mode 100644 index 000000000..be484e2d5 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs @@ -0,0 +1,62 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class RoleUpdateAuditLogData : IAuditLogData + { + private RoleUpdateAuditLogData(ulong id, RoleInfo oldProps, RoleInfo newProps) + { + RoleId = id; + Before = oldProps; + After = newProps; + } + + internal static RoleUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); + var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable"); + var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); + + uint? oldColorRaw = colorModel?.OldValue?.ToObject(), + newColorRaw = colorModel?.NewValue?.ToObject(); + bool? oldMentionable = mentionableModel?.OldValue?.ToObject(), + newMentionable = mentionableModel?.NewValue?.ToObject(); + bool? oldHoist = hoistModel?.OldValue?.ToObject(), + newHoist = hoistModel?.NewValue?.ToObject(); + string oldName = nameModel?.OldValue?.ToObject(), + newName = nameModel?.NewValue?.ToObject(); + ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject(), + newPermissionsRaw = permissionsModel?.OldValue?.ToObject(); + + Color? oldColor = null, + newColor = null; + GuildPermissions? oldPermissions = null, + newPermissions = null; + + if (oldColorRaw.HasValue) + oldColor = new Color(oldColorRaw.Value); + if (newColorRaw.HasValue) + newColor = new Color(newColorRaw.Value); + if (oldPermissionsRaw.HasValue) + oldPermissions = new GuildPermissions(oldPermissionsRaw.Value); + if (newPermissionsRaw.HasValue) + newPermissions = new GuildPermissions(newPermissionsRaw.Value); + + var oldProps = new RoleInfo(oldColor, oldMentionable, oldHoist, oldName, oldPermissions); + var newProps = new RoleInfo(newColor, newMentionable, newHoist, newName, newPermissions); + + return new RoleUpdateAuditLogData(entry.TargetId.Value, oldProps, newProps); + } + + public ulong RoleId { get; } + public RoleInfo Before { get; } + public RoleInfo After { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/UnbanAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/UnbanAuditLogData.cs new file mode 100644 index 000000000..c94f18271 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/UnbanAuditLogData.cs @@ -0,0 +1,23 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class UnbanAuditLogData : IAuditLogData + { + private UnbanAuditLogData(IUser user) + { + Target = user; + } + + internal static UnbanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + return new UnbanAuditLogData(RestUser.Create(discord, userInfo)); + } + + public IUser Target { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs new file mode 100644 index 000000000..1ae45fb8c --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs @@ -0,0 +1,44 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class WebhookCreateAuditLogData : IAuditLogData + { + private WebhookCreateAuditLogData(IWebhook webhook, WebhookType type, string name, ulong channelId) + { + Webhook = webhook; + Name = name; + Type = type; + ChannelId = channelId; + } + + internal static WebhookCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + + var channelId = channelIdModel.NewValue.ToObject(); + var type = typeModel.NewValue.ToObject(); + var name = nameModel.NewValue.ToObject(); + + var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); + var webhook = RestWebhook.Create(discord, (IGuild)null, webhookInfo); + + return new WebhookCreateAuditLogData(webhook, type, name, channelId); + } + + //Corresponds to the *current* data + public IWebhook Webhook { get; } + + //Corresponds to the *audit log* data + public WebhookType Type { get; } + public string Name { get; } + public ulong ChannelId { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs new file mode 100644 index 000000000..4133d5dff --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class WebhookDeleteAuditLogData : IAuditLogData + { + private WebhookDeleteAuditLogData(ulong id, ulong channel, WebhookType type, string name, string avatar) + { + WebhookId = id; + ChannelId = channel; + Name = name; + Type = type; + Avatar = avatar; + } + + internal static WebhookDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); + + var channelId = channelIdModel.OldValue.ToObject(); + var type = typeModel.OldValue.ToObject(); + var name = nameModel.OldValue.ToObject(); + var avatarHash = avatarHashModel?.OldValue?.ToObject(); + + return new WebhookDeleteAuditLogData(entry.TargetId.Value, channelId, type, name, avatarHash); + } + + public ulong WebhookId { get; } + public ulong ChannelId { get; } + public WebhookType Type { get; } + public string Name { get; } + public string Avatar { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookInfo.cs new file mode 100644 index 000000000..26975cc7c --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookInfo.cs @@ -0,0 +1,16 @@ +namespace Discord.Rest +{ + public struct WebhookInfo + { + internal WebhookInfo(string name, ulong? channelId, string avatar) + { + Name = name; + ChannelId = channelId; + Avatar = avatar; + } + + public string Name { get; } + public ulong? ChannelId { get; } + public string Avatar { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs new file mode 100644 index 000000000..54da42a8b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class WebhookUpdateAuditLogData : IAuditLogData + { + private WebhookUpdateAuditLogData(IWebhook webhook, WebhookInfo before, WebhookInfo after) + { + Webhook = webhook; + Before = before; + After = after; + } + + internal static WebhookUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var changes = entry.Changes; + + var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); + var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); + + var oldName = nameModel?.OldValue?.ToObject(); + var oldChannelId = channelIdModel?.OldValue?.ToObject(); + var oldAvatar = avatarHashModel?.OldValue?.ToObject(); + var before = new WebhookInfo(oldName, oldChannelId, oldAvatar); + + var newName = nameModel?.NewValue?.ToObject(); + var newChannelId = channelIdModel?.NewValue?.ToObject(); + var newAvatar = avatarHashModel?.NewValue?.ToObject(); + var after = new WebhookInfo(newName, newChannelId, newAvatar); + + var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); + var webhook = RestWebhook.Create(discord, (IGuild)null, webhookInfo); + + return new WebhookUpdateAuditLogData(webhook, before, after); + } + + //Again, the *current* data + public IWebhook Webhook { get; } + + //And the *audit log* data + public WebhookInfo Before { get; } + public WebhookInfo After { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs new file mode 100644 index 000000000..9e30a5014 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs @@ -0,0 +1,38 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + public class RestAuditLogEntry : RestEntity, IAuditLogEntry + { + private RestAuditLogEntry(BaseDiscordClient discord, Model fullLog, EntryModel model, IUser user) + : base(discord, model.Id) + { + Action = model.Action; + Data = AuditLogHelper.CreateData(discord, fullLog, model); + User = user; + Reason = model.Reason; + } + + internal static RestAuditLogEntry Create(BaseDiscordClient discord, Model fullLog, EntryModel model) + { + var userInfo = fullLog.Users.FirstOrDefault(x => x.Id == model.UserId); + IUser user = null; + if (userInfo != null) + user = RestUser.Create(discord, userInfo); + + return new RestAuditLogEntry(discord, fullLog, model, user); + } + + /// + public ActionType Action { get; } + /// + public IAuditLogData Data { get; } + /// + public IUser User { get; } + /// + public string Reason { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index 8976a8557..6a3521bff 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -168,7 +168,7 @@ namespace Discord.Rest /// invalid characters as defined by . /// /// - /// is . + /// is null. /// /// /// The specified path, file name, or both exceed the system-defined maximum length. For example, on diff --git a/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs b/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs index 2895dc17d..b0eed8b25 100644 --- a/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs @@ -12,37 +12,102 @@ namespace Discord.Rest /// /// Sends a message to this message channel. /// + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null); #if FILESYSTEM /// /// Sends a file to this message channel, with an optional caption. /// + /// The file path of the file. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// If you wish to upload an image and have it embedded in a embed, you may + /// upload the file and refer to the file with "attachment://filename.ext" in the + /// . + /// + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); #endif /// /// Sends a file to this message channel, with an optional caption. /// + /// The of the file to be sent. + /// The name of the attachment. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// If you wish to upload an image and have it embedded in a embed, you may + /// upload the file and refer to the file with "attachment://filename.ext" in the + /// . + /// + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); /// - /// Gets a message from this message channel with the given ID, or if not found. + /// Gets a message from this message channel with the given id, or null if not found. /// + /// The ID of the message. + /// The options to be used when sending the request. + /// + /// The message gotten from either the cache or the download, or null if none is found. + /// Task GetMessageAsync(ulong id, RequestOptions options = null); /// /// Gets the last N messages from this message channel. /// + /// The numbers of message to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of messages. Flattening the paginated response into a collection of messages with + /// is required if you wish to access the messages. + /// IAsyncEnumerable> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null); /// /// Gets a collection of messages in this channel. /// + /// The ID of the starting message to get the messages from. + /// The direction of the messages to be gotten from. + /// The numbers of message to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of messages. Flattening the paginated response into a collection of messages with + /// is required if you wish to access the messages. + /// IAsyncEnumerable> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null); /// /// Gets a collection of messages in this channel. /// + /// The starting message to get the messages from. + /// The direction of the messages to be gotten from. + /// The numbers of message to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of messages. Flattening the paginated response into a collection of messages with + /// is required if you wish to access the messages. + /// IAsyncEnumerable> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null); /// /// Gets a collection of pinned messages in this channel. /// + /// The options to be used when sending the request. + /// + /// An awaitable Task containing a collection of messages. + /// new Task> GetPinnedMessagesAsync(RequestOptions options = null); } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs index d9a6c1a31..4b4ccb057 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs @@ -84,14 +84,40 @@ namespace Discord.Rest => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options); /// + /// Message content is too long, length must be less or equal to . public Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options); #if FILESYSTEM /// + /// + /// is a zero-length string, contains only white space, or contains one or more + /// invalid characters as defined by . + /// + /// + /// is null. + /// + /// + /// The specified path, file name, or both exceed the system-defined maximum length. For example, on + /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 + /// characters. + /// + /// + /// The specified path is invalid, (for example, it is on an unmapped drive). + /// + /// + /// specified a directory.-or- The caller does not have the required permission. + /// + /// + /// The file specified in was not found. + /// + /// is in an invalid format. + /// An I/O error occurred while opening the file. + /// Message content is too long, length must be less or equal to . public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options); #endif /// + /// Message content is too long, length must be less or equal to . public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options); diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index b279f06a3..64f195a0d 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -14,7 +14,7 @@ namespace Discord.Rest internal static class GuildHelper { //General - /// is . + /// is null. public static async Task ModifyAsync(IGuild guild, BaseDiscordClient client, Action func, RequestOptions options) { @@ -32,7 +32,6 @@ namespace Discord.Rest Icon = args.Icon.IsSpecified ? args.Icon.Value?.ToModel() : Optional.Create(), Name = args.Name, Splash = args.Splash.IsSpecified ? args.Splash.Value?.ToModel() : Optional.Create(), - Username = args.Username, VerificationLevel = args.VerificationLevel }; @@ -63,7 +62,7 @@ namespace Discord.Rest return await client.ApiClient.ModifyGuildAsync(guild.Id, apiArgs, options).ConfigureAwait(false); } - /// is . + /// is null. public static async Task ModifyEmbedAsync(IGuild guild, BaseDiscordClient client, Action func, RequestOptions options) { @@ -113,6 +112,11 @@ namespace Discord.Rest var models = await client.ApiClient.GetGuildBansAsync(guild.Id, options).ConfigureAwait(false); return models.Select(x => RestBan.Create(client, x)).ToImmutableArray(); } + public static async Task GetBanAsync(IGuild guild, BaseDiscordClient client, ulong userId, RequestOptions options) + { + var model = await client.ApiClient.GetGuildBanAsync(guild.Id, userId, options).ConfigureAwait(false); + return RestBan.Create(client, model); + } public static async Task AddBanAsync(IGuild guild, BaseDiscordClient client, ulong userId, int pruneDays, string reason, RequestOptions options) @@ -141,7 +145,7 @@ namespace Discord.Rest var models = await client.ApiClient.GetGuildChannelsAsync(guild.Id, options).ConfigureAwait(false); return models.Select(x => RestGuildChannel.Create(client, guild, x)).ToImmutableArray(); } - /// is . + /// is null. public static async Task CreateTextChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options) { @@ -151,7 +155,7 @@ namespace Discord.Rest var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); return RestTextChannel.Create(client, guild, model); } - /// is . + /// is null. public static async Task CreateVoiceChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options) { @@ -161,7 +165,7 @@ namespace Discord.Rest var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); return RestVoiceChannel.Create(client, guild, model); } - /// is . + /// is null. public static async Task CreateCategoryChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options) { @@ -196,7 +200,7 @@ namespace Discord.Rest } //Roles - /// is . + /// is null. public static async Task CreateRoleAsync(IGuild guild, BaseDiscordClient client, string name, GuildPermissions? permissions, Color? color, bool isHoisted, RequestOptions options) { @@ -269,6 +273,35 @@ namespace Discord.Rest return model.Pruned; } + // Audit logs + public static IAsyncEnumerable> GetAuditLogsAsync(IGuild guild, BaseDiscordClient client, + ulong? from, int? limit, RequestOptions options) + { + return new PagedAsyncEnumerable( + DiscordConfig.MaxAuditLogEntriesPerBatch, + async (info, ct) => + { + var args = new GetAuditLogsParams + { + Limit = info.PageSize + }; + if (info.Position != null) + args.BeforeEntryId = info.Position.Value; + var model = await client.ApiClient.GetAuditLogsAsync(guild.Id, args, options); + return model.Entries.Select((x) => RestAuditLogEntry.Create(client, model, x)).ToImmutableArray(); + }, + nextPage: (info, lastPage) => + { + if (lastPage.Count != DiscordConfig.MaxAuditLogEntriesPerBatch) + return false; + info.Position = lastPage.Min(x => x.Id); + return true; + }, + start: from, + count: limit + ); + } + //Webhooks public static async Task GetWebhookAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) { @@ -303,7 +336,7 @@ namespace Discord.Rest var emote = await client.ApiClient.CreateGuildEmoteAsync(guild.Id, apiargs, options).ConfigureAwait(false); return emote.ToEntity(); } - /// is . + /// is null. public static async Task ModifyEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, Action func, RequestOptions options) { diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 5a79565ba..e301db892 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -132,7 +132,7 @@ namespace Discord.Rest => GuildHelper.DeleteAsync(this, Discord, options); /// - /// is . + /// is null. public async Task ModifyAsync(Action func, RequestOptions options = null) { var model = await GuildHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); @@ -140,7 +140,7 @@ namespace Discord.Rest } /// - /// is . + /// is null. public async Task ModifyEmbedAsync(Action func, RequestOptions options = null) { var model = await GuildHelper.ModifyEmbedAsync(this, Discord, func, options).ConfigureAwait(false); @@ -148,7 +148,7 @@ namespace Discord.Rest } /// - /// is . + /// is null. public async Task ReorderChannelsAsync(IEnumerable args, RequestOptions options = null) { var arr = args.ToArray(); @@ -172,6 +172,10 @@ namespace Discord.Rest //Bans public Task> GetBansAsync(RequestOptions options = null) => GuildHelper.GetBansAsync(this, Discord, options); + public Task GetBanAsync(IUser user, RequestOptions options = null) + => GuildHelper.GetBanAsync(this, Discord, user.Id, options); + public Task GetBanAsync(ulong userId, RequestOptions options = null) + => GuildHelper.GetBanAsync(this, Discord, userId, options); /// public Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) @@ -301,6 +305,10 @@ namespace Discord.Rest public Task PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null) => GuildHelper.PruneUsersAsync(this, Discord, days, simulate, options); + //Audit logs + public IAsyncEnumerable> GetAuditLogsAsync(int limit, RequestOptions options = null) + => GuildHelper.GetAuditLogsAsync(this, Discord, null, limit, options); + //Webhooks public Task GetWebhookAsync(ulong id, RequestOptions options = null) => GuildHelper.GetWebhookAsync(this, Discord, id, options); @@ -324,7 +332,7 @@ namespace Discord.Rest public Task CreateEmoteAsync(string name, Image image, Optional> roles = default(Optional>), RequestOptions options = null) => GuildHelper.CreateEmoteAsync(this, Discord, name, image, roles, options); /// - /// is . + /// is null. public Task ModifyEmoteAsync(GuildEmote emote, Action func, RequestOptions options = null) => GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options); /// @@ -344,6 +352,12 @@ namespace Discord.Rest /// async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); + /// + async Task IGuild.GetBanAsync(IUser user, RequestOptions options) + => await GetBanAsync(user, options).ConfigureAwait(false); + /// + async Task IGuild.GetBanAsync(ulong userId, RequestOptions options) + => await GetBanAsync(userId, options).ConfigureAwait(false); /// async Task> IGuild.GetChannelsAsync(CacheMode mode, RequestOptions options) @@ -498,6 +512,14 @@ namespace Discord.Rest Task IGuild.DownloadUsersAsync() => throw new NotSupportedException(); + async Task> IGuild.GetAuditLogAsync(int limit, CacheMode cacheMode, RequestOptions options) + { + if (cacheMode == CacheMode.AllowDownload) + return (await GetAuditLogsAsync(limit, options).FlattenAsync().ConfigureAwait(false)).ToImmutableArray(); + else + return ImmutableArray.Create(); + } + /// async Task IGuild.GetWebhookAsync(ulong id, RequestOptions options) => await GetWebhookAsync(id, options).ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs index a51ac8e09..0f5aaf438 100644 --- a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs +++ b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs @@ -3,7 +3,9 @@ using Model = Discord.API.Attachment; namespace Discord { - /// A Discord attachment. + /// + /// An attachment file seen in a . + /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class Attachment : IAttachment { @@ -39,7 +41,12 @@ namespace Discord model.Width.IsSpecified ? model.Width.Value : (int?)null); } - /// Returns the filename of the attachment. + /// + /// Returns the filename of this attachment. + /// + /// + /// A string containing the filename of this attachment. + /// public override string ToString() => Filename; private string DebuggerDisplay => $"{Filename} ({Size} bytes)"; } diff --git a/src/Discord.Net.Rest/Entities/RestApplication.cs b/src/Discord.Net.Rest/Entities/RestApplication.cs index 198ce1a61..d033978d0 100644 --- a/src/Discord.Net.Rest/Entities/RestApplication.cs +++ b/src/Discord.Net.Rest/Entities/RestApplication.cs @@ -6,7 +6,7 @@ using Model = Discord.API.Application; namespace Discord.Rest { /// - /// Represents a REST entity that contains information about a Discord application created via the developer portal. + /// Represents a REST-based entity that contains information about a Discord application created via the developer portal. /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestApplication : RestEntity, IApplication diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index fdfe9b5a1..68930e74c 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -9,7 +9,7 @@ using Model = Discord.API.GuildMember; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestGuildUser : RestUser, IGuildUser, IUpdateable + public class RestGuildUser : RestUser, IGuildUser { private long? _joinedAtTicks; private ImmutableArray _roleIds; diff --git a/src/Discord.Net.WebSocket/Audio/AudioClient.cs b/src/Discord.Net.WebSocket/Audio/AudioClient.cs index c3cbc9ca7..c3960fa67 100644 --- a/src/Discord.Net.WebSocket/Audio/AudioClient.cs +++ b/src/Discord.Net.WebSocket/Audio/AudioClient.cs @@ -16,7 +16,7 @@ using System.Collections.Generic; namespace Discord.Audio { //TODO: Add audio reconnecting - internal partial class AudioClient : IAudioClient, IDisposable + internal partial class AudioClient : IAudioClient { internal struct StreamPair { diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index 304592442..c236b1045 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -165,6 +165,13 @@ namespace Discord.WebSocket remove { _userVoiceStateUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _userVoiceStateUpdatedEvent = new AsyncEvent>(); + /// Fired when the bot connects to a Discord voice server. + public event Func VoiceServerUpdated + { + add { _voiceServerUpdatedEvent.Add(value); } + remove { _voiceServerUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _voiceServerUpdatedEvent = new AsyncEvent>(); /// Fired when the connected account is updated. public event Func CurrentUserUpdated { add { _selfUpdatedEvent.Add(value); } diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.cs b/src/Discord.Net.WebSocket/BaseSocketClient.cs index 81e573e1d..858fec7fe 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.cs @@ -50,55 +50,80 @@ namespace Discord.WebSocket /// /// Gets a Discord application information for the logged-in user. /// + /// + /// This method reflects your application information you submitted when creating a Discord application via + /// the Developer Portal. + /// /// The options to be used when sending the request. /// - /// Application information. This reflects your application information you submitted when creating a - /// Discord application via the Developer Portal. + /// An awaitable containing the application information. /// public abstract Task GetApplicationInfoAsync(RequestOptions options = null); /// - /// Gets a user who shares a mutual guild with logged-in user with the provided snowflake ID. + /// Gets a user. /// /// The user snowflake ID. + /// + /// This method gets the user present in the WebSocket cache with the given condition. + /// + /// Sometimes a user may return null due to Discord not sending offline users in large + /// guilds (i.e. guild with 100+ members) actively. To download users on startup, consider enabling + /// . + /// + /// + /// This method does not attempt to fetch users that the logged-in user does not have access to (i.e. + /// users who don't share mutual guild(s) with the current user). + /// + /// /// - /// A user who shares a mutual guild with the logged-in user and who is also present in the WebSocket cache; - /// or when the user cannot be found. + /// A WebSocket-based generic user; null when the user cannot be found. /// public abstract SocketUser GetUser(ulong id); /// - /// Gets a user who shares a mutual guild with the logged-in user with the provided username and discriminator value combo. + /// Gets a user. /// /// The name of the user. /// The discriminator value of the user. + /// + /// This method gets the user present in the WebSocket cache with the given condition. + /// + /// Sometimes a user may return null due to Discord not sending offline users in large + /// guilds (i.e. guild with 100+ members) actively. To download users on startup, consider enabling + /// . + /// + /// + /// This method does not attempt to fetch users that the logged-in user does not have access to (i.e. + /// users who don't share mutual guild(s) with the current user). + /// + /// /// - /// A user who shares a mutual guild with the logged-in user and who is also present in the WebSocket cache; - /// or when the user cannot be found. + /// A WebSocket-based generic user; null when the user cannot be found. /// public abstract SocketUser GetUser(string username, string discriminator); /// - /// Gets a channel that the logged-in user is accessible to with the provided ID. + /// Gets a channel. /// /// The channel snowflake ID. /// - /// A generic channel object (voice, text, category, etc.); or when the channel - /// cannot be found. + /// A generic WebSocket-based channel object (voice, text, category, etc.); null when the + /// channel cannot be found. /// public abstract SocketChannel GetChannel(ulong id); /// - /// Gets a guild that the logged-in user is accessible to with the provided ID. + /// Gets a guild. /// /// The guild snowflake ID. /// - /// A guild; or when the guild cannot be found. + /// A WebSocket-based guild; null when the guild cannot be found. /// public abstract SocketGuild GetGuild(ulong id); /// - /// Gets a voice region with the provided ID. + /// Gets a voice region. /// /// The unique identifier of the voice region. /// - /// A voice region; or if none can be found. + /// A REST-based voice region; null if none can be found. /// public abstract RestVoiceRegion GetVoiceRegion(string id); /// @@ -127,9 +152,14 @@ namespace Discord.WebSocket /// Sets the of the logged-in user. /// /// - /// This method sets the of the user. Please note that Rich Presence cannot be - /// set via this method or client. Rich Presence is strictly limited to RPC clients only. Furthermore, - /// Discord will only accept setting of name and the type of activity. + /// This method sets the of the user. + /// + /// Discord will only accept setting of name and the type of activity. + /// + /// + /// Rich Presence cannot be set via this method or client. Rich Presence is strictly limited to RPC + /// clients only. + /// /// /// The activty to be set. /// @@ -149,8 +179,10 @@ namespace Discord.WebSocket /// Creates a guild for the logged-in user who is in less than 10 active guilds. /// /// - /// This method creates a new guild on behalf of the logged-in user. Note that due to Discord's limitation, - /// this method will only work for users that are in less than 10 guilds. + /// This method creates a new guild on behalf of the logged-in user. + /// + /// Due to Discord's limitation, this method will only work for users that are in less than 10 guilds. + /// /// /// The name of the new guild. /// The voice region to create the guild with. diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index eef1b1c90..039ea2fe5 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -134,7 +134,7 @@ namespace Discord.WebSocket private int GetShardIdFor(ulong guildId) => (int)((guildId >> 22) % (uint)_totalShards); public int GetShardIdFor(IGuild guild) - => GetShardIdFor(guild.Id); + => GetShardIdFor(guild?.Id ?? 0); private DiscordSocketClient GetShardFor(ulong guildId) => GetShard(GetShardIdFor(guildId)); public DiscordSocketClient GetShardFor(IGuild guild) diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index d43e8a1d4..dc4e72020 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -66,9 +66,9 @@ namespace Discord.WebSocket public override IReadOnlyCollection Guilds => State.Guilds; /// public override IReadOnlyCollection PrivateChannels => State.PrivateChannels; - public IReadOnlyCollection DMChannels + public IReadOnlyCollection DMChannels => State.PrivateChannels.Select(x => x as SocketDMChannel).Where(x => x != null).ToImmutableArray(); - public IReadOnlyCollection GroupChannels + public IReadOnlyCollection GroupChannels => State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray(); /// public override IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection(); @@ -94,11 +94,11 @@ namespace Discord.WebSocket _stateLock = new SemaphoreSlim(1, 1); _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); - _connection = new ConnectionManager(_stateLock, _gatewayLogger, config.ConnectionTimeout, + _connection = new ConnectionManager(_stateLock, _gatewayLogger, config.ConnectionTimeout, OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x); _connection.Connected += () => TimedInvokeAsync(_connectedEvent, nameof(Connected)); _connection.Disconnected += (ex, recon) => TimedInvokeAsync(_disconnectedEvent, nameof(Disconnected), ex); - + _nextAudioId = 1; _connectionGroupLock = groupLock; _parentClient = parentClient; @@ -109,7 +109,7 @@ namespace Discord.WebSocket _gatewayLogger.WarningAsync("Serializer Error", e.ErrorContext.Error).GetAwaiter().GetResult(); e.ErrorContext.Handled = true; }; - + ApiClient.SentGatewayMessage += async opCode => await _gatewayLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false); ApiClient.ReceivedGatewayEvent += ProcessMessageAsync; @@ -168,7 +168,7 @@ namespace Discord.WebSocket /// public override async Task StopAsync() => await _connection.StopAsync().ConfigureAwait(false); - + private async Task OnConnectingAsync() { if (_connectionGroupLock != null) @@ -191,11 +191,11 @@ namespace Discord.WebSocket //Wait for READY await _connection.WaitAsync().ConfigureAwait(false); - + await _gatewayLogger.DebugAsync("Sending Status").ConfigureAwait(false); await SendStatusAsync().ConfigureAwait(false); } - finally + finally { if (_connectionGroupLock != null) { @@ -240,22 +240,22 @@ namespace Discord.WebSocket } /// - public override async Task GetApplicationInfoAsync(RequestOptions options = null) + public override async Task GetApplicationInfoAsync(RequestOptions options = null) => _applicationInfo ?? (_applicationInfo = await ClientHelper.GetApplicationInfoAsync(this, options ?? RequestOptions.Default).ConfigureAwait(false)); /// - public override SocketGuild GetGuild(ulong id) - => State.GetGuild(id); + public override SocketGuild GetGuild(ulong id) + => State.GetGuild(id); /// - public override SocketChannel GetChannel(ulong id) + public override SocketChannel GetChannel(ulong id) => State.GetChannel(id); - + /// - public override SocketUser GetUser(ulong id) + public override SocketUser GetUser(ulong id) => State.GetUser(id); /// - public override SocketUser GetUser(string username, string discriminator) + public override SocketUser GetUser(string username, string discriminator) => State.Users.FirstOrDefault(x => x.Discriminator == discriminator && x.Username == username); internal SocketGlobalUser GetOrCreateUser(ClientState state, Discord.API.User model) { @@ -276,7 +276,7 @@ namespace Discord.WebSocket return user; }); } - internal void RemoveUser(ulong id) + internal void RemoveUser(ulong id) => State.RemoveUser(id); /// @@ -353,7 +353,7 @@ namespace Discord.WebSocket Activity = activity; await SendStatusAsync().ConfigureAwait(false); } - + private async Task SendStatusAsync() { if (CurrentUser == null) @@ -387,7 +387,7 @@ namespace Discord.WebSocket if (seq != null) _lastSeq = seq.Value; _lastMessageTime = Environment.TickCount; - + try { switch (opCode) @@ -403,7 +403,7 @@ namespace Discord.WebSocket case GatewayOpCode.Heartbeat: { await _gatewayLogger.DebugAsync("Received Heartbeat").ConfigureAwait(false); - + await ApiClient.SendHeartbeatAsync(_lastSeq).ConfigureAwait(false); } break; @@ -428,7 +428,7 @@ namespace Discord.WebSocket _sessionId = null; _lastSeq = 0; - + await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards).ConfigureAwait(false); } break; @@ -488,7 +488,7 @@ namespace Discord.WebSocket } else if (_connection.CancelToken.IsCancellationRequested) return; - + await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false); await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false); }); @@ -527,7 +527,7 @@ namespace Discord.WebSocket if (guild != null) { guild.Update(State, data); - + if (_unavailableGuildCount != 0) _unavailableGuildCount--; await GuildAvailableAsync(guild).ConfigureAwait(false); @@ -1038,7 +1038,7 @@ namespace Discord.WebSocket SocketUser user = guild.GetUser(data.User.Id); if (user == null) - user = SocketUnknownUser.Create(this, State, data.User); + user = SocketUnknownUser.Create(this, State, data.User); await TimedInvokeAsync(_userBannedEvent, nameof(UserBanned), user, guild).ConfigureAwait(false); } else @@ -1338,7 +1338,7 @@ namespace Discord.WebSocket await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false); } } - + var before = user.Clone(); user.Update(State, data, true); await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), before, user).ConfigureAwait(false); @@ -1479,16 +1479,29 @@ namespace Discord.WebSocket var data = (payload as JToken).ToObject(_serializer); var guild = State.GetGuild(data.GuildId); - if (guild != null) + var isCached = guild != null; + var cachedGuild = new Cacheable(guild, data.GuildId, isCached, + () => Task.FromResult(State.GetGuild(data.GuildId) as IGuild)); + + var voiceServer = new SocketVoiceServer(cachedGuild, data.Endpoint, data.Token); + await TimedInvokeAsync(_voiceServerUpdatedEvent, nameof(UserVoiceStateUpdated), voiceServer).ConfigureAwait(false); + + if (isCached) { - string endpoint = data.Endpoint.Substring(0, data.Endpoint.LastIndexOf(':')); + var endpoint = data.Endpoint; + + //Only strip out the port if the endpoint contains it + var portBegin = endpoint.LastIndexOf(':'); + if (portBegin > 0) + endpoint = endpoint.Substring(0, portBegin); + var _ = guild.FinishConnectAudio(endpoint, data.Token).ConfigureAwait(false); } else { await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); - return; } + } break; diff --git a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs index 17f200c08..d85230fec 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs @@ -15,7 +15,7 @@ namespace Discord.WebSocket public const string GatewayEncoding = "json"; /// - /// Gets or sets the WebSocket host to connect to. If , the client will use the + /// Gets or sets the WebSocket host to connect to. If null, the client will use the /// /gateway endpoint. /// public string GatewayHost { get; set; } = null; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs index 6d769b9c4..c37311a41 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs @@ -10,7 +10,12 @@ namespace Discord.WebSocket /// public interface ISocketMessageChannel : IMessageChannel { - /// Gets all messages in this channel's cache. + /// + /// Gets all messages in this channel's cache. + /// + /// + /// A collection of WebSocket-based messages. + /// IReadOnlyCollection CachedMessages { get; } /// @@ -20,6 +25,9 @@ namespace Discord.WebSocket /// Whether the message should be read aloud by Discord or not. /// The to be sent. /// The options to be used when sending the request. + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null); #if FILESYSTEM /// @@ -35,6 +43,9 @@ namespace Discord.WebSocket /// upload the file and refer to the file with "attachment://filename.ext" in the /// . /// + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); #endif /// @@ -51,14 +62,47 @@ namespace Discord.WebSocket /// upload the file and refer to the file with "attachment://filename.ext" in the /// . /// + /// + /// An awaitable Task containing the message sent to the channel. + /// new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); + /// + /// Gets the cached message if one exists. + /// + /// The ID of the message. + /// + /// Cached message object; null if it doesn't exist in the cache. + /// SocketMessage GetCachedMessage(ulong id); - /// Gets the last N messages from this message channel. + /// + /// Gets the last N messages from this message channel. + /// + /// The number of messages to get. + /// + /// A collection of WebSocket-based messages. + /// IReadOnlyCollection GetCachedMessages(int limit = DiscordConfig.MaxMessagesPerBatch); - /// Gets a collection of messages in this channel. + + /// + /// Gets a collection of messages in this channel. + /// + /// The message ID to start the fetching from. + /// The direction of which the message should be gotten from. + /// The number of messages to get. + /// + /// A collection of WebSocket-based messages. + /// IReadOnlyCollection GetCachedMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); - /// Gets a collection of messages in this channel. + /// + /// Gets a collection of messages in this channel. + /// + /// The message to start the fetching from. + /// The direction of which the message should be gotten from. + /// The number of messages to get. + /// + /// A collection of WebSocket-based messages. + /// IReadOnlyCollection GetCachedMessages(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); /// /// Gets a collection of pinned messages in this channel. diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index 1305233e4..37e6afef1 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -14,6 +14,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketCategoryChannel : SocketGuildChannel, ICategoryChannel { + /// public override IReadOnlyCollection Users => Guild.Users.Where(x => Permissions.GetValue( Permissions.ResolveChannel(Guild, x, this, Permissions.ResolveGuild(Guild, x)), diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs index 8008d434a..763296590 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs @@ -30,7 +30,7 @@ namespace Discord.WebSocket Recipient = recipient; recipient.GlobalUser.AddRef(); if (Discord.MessageCacheSize > 0) - _messages = new MessageCache(Discord, this); + _messages = new MessageCache(Discord); } internal static SocketDMChannel Create(DiscordSocketClient discord, ClientState state, Model model) { @@ -78,6 +78,7 @@ namespace Discord.WebSocket => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options); /// + /// Message content is too long, length must be less or equal to . public Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options); #if FILESYSTEM @@ -86,6 +87,7 @@ namespace Discord.WebSocket => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, options); #endif /// + /// Message content is too long, length must be less or equal to . public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, options); diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs index 94bf70493..57fcc51a2 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs @@ -39,7 +39,7 @@ namespace Discord.WebSocket : base(discord, id) { if (Discord.MessageCacheSize > 0) - _messages = new MessageCache(Discord, this); + _messages = new MessageCache(Discord); _voiceStates = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, 5); _users = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, 5); } @@ -108,6 +108,7 @@ namespace Discord.WebSocket => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options); /// + /// Message content is too long, length must be less or equal to . public Task SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null) => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, options); #if FILESYSTEM diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs index 8d6f22133..1151f0141 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs @@ -21,7 +21,7 @@ namespace Discord.WebSocket /// Gets the guild associated with this channel. /// /// - /// The guild that this channel belongs to. + /// A guild that this channel belongs to. /// public SocketGuild Guild { get; } /// @@ -34,7 +34,7 @@ namespace Discord.WebSocket /// Gets the parent category of this channel. /// /// - /// The parent category ID associated with this channel, or if none is set. + /// A parent category ID associated with this channel, or null if none is set. /// public ICategoryChannel Category => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; @@ -42,7 +42,7 @@ namespace Discord.WebSocket /// public IReadOnlyCollection PermissionOverwrites => _overwrites; /// - /// Returns a collection of users that are able to view the channel. + /// Gets a collection of users that are able to view the channel. /// /// /// A collection of users that can access the channel (i.e. the users seen in the user list). diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index ae8ab54da..92bc07c60 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -39,7 +39,7 @@ namespace Discord.WebSocket : base(discord, id, guild) { if (Discord.MessageCacheSize > 0) - _messages = new MessageCache(Discord, this); + _messages = new MessageCache(Discord); } internal new static SocketTextChannel Create(SocketGuild guild, ClientState state, Model model) { @@ -152,7 +152,7 @@ namespace Discord.WebSocket /// The ID of the webhook. /// The options to be used when sending the request. /// - /// A webhook associated with the , or if not found. + /// A webhook associated with the , or null if not found. /// public Task GetWebhookAsync(ulong id, RequestOptions options = null) => ChannelHelper.GetWebhookAsync(this, Discord, id, options); diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 1f027e321..ca8f54d0b 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -91,11 +91,11 @@ namespace Discord.WebSocket public Task SyncPromise => _syncPromise.Task; public Task DownloaderPromise => _downloaderPromise.Task; /// - /// Returns the associated with this guild. + /// Gets the associated with this guild. /// public IAudioClient AudioClient => _audioClient; /// - /// Returns the first viewable text channel. + /// Gets the first viewable text channel. /// /// /// This property does not guarantee the user can send message to it. @@ -105,7 +105,7 @@ namespace Discord.WebSocket .OrderBy(c => c.Position) .FirstOrDefault(); /// - /// Returns the AFK voice channel, or if none is set. + /// Gets the AFK voice channel, or null if none is set. /// public SocketVoiceChannel AFKChannel { @@ -116,7 +116,7 @@ namespace Discord.WebSocket } } /// - /// Gets the embed channel set in the widget settings of this guild, or if none is set. + /// Gets the embed channel set in the widget settings of this guild, or null if none is set. /// public SocketGuildChannel EmbedChannel { @@ -127,7 +127,7 @@ namespace Discord.WebSocket } } /// - /// Gets the channel where randomized welcome messages are sent, or if none is set. + /// Gets the channel where randomized welcome messages are sent, or null if none is set. /// public SocketTextChannel SystemChannel { @@ -138,31 +138,34 @@ namespace Discord.WebSocket } } /// - /// Returns a collection of text channels present in this guild. + /// Gets a collection of text channels present in this guild. /// public IReadOnlyCollection TextChannels => Channels.Select(x => x as SocketTextChannel).Where(x => x != null).ToImmutableArray(); /// - /// Returns a collection of voice channels present in this guild. + /// Gets a collection of voice channels present in this guild. /// public IReadOnlyCollection VoiceChannels => Channels.Select(x => x as SocketVoiceChannel).Where(x => x != null).ToImmutableArray(); /// - /// Returns a collection of category channels present in this guild. + /// Gets a collection of category channels present in this guild. /// public IReadOnlyCollection CategoryChannels => Channels.Select(x => x as SocketCategoryChannel).Where(x => x != null).ToImmutableArray(); /// - /// Returns the current logged-in user. + /// Gets the current logged-in user. /// public SocketGuildUser CurrentUser => _members.TryGetValue(Discord.CurrentUser.Id, out SocketGuildUser member) ? member : null; /// - /// Returns the @everyone role in this guild. + /// Gets the @everyone role in this guild. /// public SocketRole EveryoneRole => GetRole(Id); /// - /// Returns a collection of channels present in this guild. + /// Gets a collection of channels present in this guild. /// + /// + /// Collection of channels. + /// public IReadOnlyCollection Channels { get @@ -175,10 +178,16 @@ namespace Discord.WebSocket /// /// Gets a collection of emotes created in this guild. /// + /// + /// Collection of emotes. + /// public IReadOnlyCollection Emotes => _emotes; /// /// Gets a collection of features enabled in this guild. /// + /// + /// Collection of features in string. + /// public IReadOnlyCollection Features => _features; /// /// Gets a collection of users in this guild. @@ -188,10 +197,16 @@ namespace Discord.WebSocket /// You may need to enable to fetch the full user list /// upon startup, or use to manually download the users. /// + /// + /// Collection of users. + /// public IReadOnlyCollection Users => _members.ToReadOnlyCollection(); /// /// Gets a collection of roles in this guild. /// + /// + /// Collection of roles. + /// public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); internal SocketGuild(DiscordSocketClient client, ulong id) @@ -357,12 +372,12 @@ namespace Discord.WebSocket => GuildHelper.DeleteAsync(this, Discord, options); /// - /// is . + /// is null. public Task ModifyAsync(Action func, RequestOptions options = null) => GuildHelper.ModifyAsync(this, Discord, func, options); /// - /// is . + /// is null. public Task ModifyEmbedAsync(Action func, RequestOptions options = null) => GuildHelper.ModifyEmbedAsync(this, Discord, func, options); /// @@ -378,7 +393,7 @@ namespace Discord.WebSocket //Bans /// - /// Gets a collection of the banned users in this guild. + /// Returns a collection of the banned users in this guild. /// /// The options to be used when sending the request. /// @@ -386,6 +401,10 @@ namespace Discord.WebSocket /// public Task> GetBansAsync(RequestOptions options = null) => GuildHelper.GetBansAsync(this, Discord, options); + public Task GetBanAsync(IUser user, RequestOptions options = null) + => GuildHelper.GetBanAsync(this, Discord, user.Id, options); + public Task GetBanAsync(ulong userId, RequestOptions options = null) + => GuildHelper.GetBanAsync(this, Discord, userId, options); /// public Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) @@ -440,7 +459,7 @@ namespace Discord.WebSocket /// /// The name of the new channel. /// The options to be used when sending the request. - /// is . + /// is null. /// /// The created text channel. /// @@ -452,7 +471,7 @@ namespace Discord.WebSocket /// /// The name of the new channel. /// The options to be used when sending the request. - /// is . + /// is null. /// /// The created voice channel. /// @@ -464,7 +483,7 @@ namespace Discord.WebSocket /// /// The name of the new channel. /// The options to be used when sending the request. - /// is . + /// is null. /// /// The created category channel. /// @@ -522,12 +541,12 @@ namespace Discord.WebSocket /// /// The name of the new role. /// - /// The permissions that the new role possesses. Set to to use the default permissions. + /// The permissions that the new role possesses. Set to null to use the default permissions. /// - /// The color of the role. Set to to use the default color. + /// The color of the role. Set to null to use the default color. /// Used to determine if users of this role are separated in the user list. /// The options to be used when sending the request. - /// is . + /// is null. /// /// The created role. /// @@ -627,6 +646,10 @@ namespace Discord.WebSocket _downloaderPromise.TrySetResultAsync(true); } + //Audit logs + public IAsyncEnumerable> GetAuditLogsAsync(int limit, RequestOptions options = null) + => GuildHelper.GetAuditLogsAsync(this, Discord, null, limit, options); + //Webhooks /// /// Returns the webhook with the provided ID. @@ -634,7 +657,7 @@ namespace Discord.WebSocket /// The ID of the webhook. /// The options to be used when sending the request. /// - /// A webhook associated with the ID. + /// An awaitable Task containing the webhook associated with the ID. /// public Task GetWebhookAsync(ulong id, RequestOptions options = null) => GuildHelper.GetWebhookAsync(this, Discord, id, options); @@ -643,7 +666,7 @@ namespace Discord.WebSocket /// /// The options to be used when sending the request. /// - /// A collection of webhooks. + /// An awaitable Task containing a collection of webhooks. /// public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); @@ -656,7 +679,7 @@ namespace Discord.WebSocket public Task CreateEmoteAsync(string name, Image image, Optional> roles = default(Optional>), RequestOptions options = null) => GuildHelper.CreateEmoteAsync(this, Discord, name, image, roles, options); /// - /// is . + /// is null. public Task ModifyEmoteAsync(GuildEmote emote, Action func, RequestOptions options = null) => GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options); /// @@ -866,6 +889,12 @@ namespace Discord.WebSocket /// async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); + /// + async Task IGuild.GetBanAsync(IUser user, RequestOptions options) + => await GetBanAsync(user, options).ConfigureAwait(false); + /// + async Task IGuild.GetBanAsync(ulong userId, RequestOptions options) + => await GetBanAsync(userId, options).ConfigureAwait(false); /// Task> IGuild.GetChannelsAsync(CacheMode mode, RequestOptions options) @@ -941,6 +970,14 @@ namespace Discord.WebSocket Task IGuild.GetOwnerAsync(CacheMode mode, RequestOptions options) => Task.FromResult(Owner); + async Task> IGuild.GetAuditLogAsync(int limit, CacheMode cacheMode, RequestOptions options) + { + if (cacheMode == CacheMode.AllowDownload) + return (await GetAuditLogsAsync(limit, options).FlattenAsync().ConfigureAwait(false)).ToImmutableArray(); + else + return ImmutableArray.Create(); + } + /// async Task IGuild.GetWebhookAsync(ulong id, RequestOptions options) => await GetWebhookAsync(id, options).ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs b/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs index c2cad4d86..8cac95cd3 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/MessageCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -14,7 +14,7 @@ namespace Discord.WebSocket public IReadOnlyCollection Messages => _messages.ToReadOnlyCollection(); - public MessageCache(DiscordSocketClient discord, IChannel channel) + public MessageCache(DiscordSocketClient discord) { _size = discord.MessageCacheSize; _messages = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(_size * 1.05)); @@ -28,7 +28,7 @@ namespace Discord.WebSocket _orderedMessages.Enqueue(message.Id); while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out ulong msgId)) - _messages.TryRemove(msgId, out SocketMessage msg); + _messages.TryRemove(msgId, out SocketMessage _); } } @@ -44,6 +44,8 @@ namespace Discord.WebSocket return result; return null; } + + /// is less than 0. public IReadOnlyCollection GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) { if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index d339a20ed..0767f2ad7 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -14,8 +14,20 @@ namespace Discord.WebSocket public abstract class SocketMessage : SocketEntity, IMessage { private long _timestampTicks; - + + /// + /// Gets the author of this message. + /// + /// + /// A WebSocket-based user object. + /// public SocketUser Author { get; } + /// + /// Gets the source channel of the message. + /// + /// + /// A WebSocket-based message channel. + /// public ISocketMessageChannel Channel { get; } /// public MessageSource Source { get; } @@ -31,10 +43,40 @@ namespace Discord.WebSocket public virtual bool IsPinned => false; /// public virtual DateTimeOffset? EditedTimestamp => null; + /// + /// Returns all attachments included in this message. + /// + /// + /// Collection of attachments. + /// public virtual IReadOnlyCollection Attachments => ImmutableArray.Create(); + /// + /// Returns all embeds included in this message. + /// + /// + /// Collection of embed objects. + /// public virtual IReadOnlyCollection Embeds => ImmutableArray.Create(); + /// + /// Returns the channels mentioned in this message. + /// + /// + /// Collection of WebSocket-based guild channels. + /// public virtual IReadOnlyCollection MentionedChannels => ImmutableArray.Create(); + /// + /// Returns the roles mentioned in this message. + /// + /// + /// Collection of WebSocket-based roles. + /// public virtual IReadOnlyCollection MentionedRoles => ImmutableArray.Create(); + /// + /// Returns the users mentioned in this message. + /// + /// + /// Collection of WebSocket-based users. + /// public virtual IReadOnlyCollection MentionedUsers => ImmutableArray.Create(); /// public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); @@ -69,6 +111,12 @@ namespace Discord.WebSocket public Task DeleteAsync(RequestOptions options = null) => MessageHelper.DeleteAsync(this, Discord, options); + /// + /// Gets the content of the message. + /// + /// + /// Content of the message. + /// public override string ToString() => Content; internal SocketMessage Clone() => MemberwiseClone() as SocketMessage; diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketReaction.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketReaction.cs index bfd6aa042..8df6d51b4 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketReaction.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketReaction.cs @@ -2,12 +2,45 @@ using Model = Discord.API.Gateway.Reaction; namespace Discord.WebSocket { + /// + /// Represents a WebSocket-based reaction object. + /// public class SocketReaction : IReaction { + /// + /// Gets the ID of the user who added the reaction. + /// + /// + /// A user snowflake ID. + /// public ulong UserId { get; } + /// + /// Gets the user who added the reaction if possible. + /// + /// + /// A user object where possible. This value is not always returned. + /// public Optional User { get; } + /// + /// Gets the ID of the message that has been reacted to. + /// + /// + /// A message snowflake ID. + /// public ulong MessageId { get; } + /// + /// Gets the message that has been reacted to if possible. + /// + /// + /// A WebSocket-based message where possible. This value is not always returned. + /// public Optional Message { get; } + /// + /// Gets the channel where the reaction takes place in. + /// + /// + /// A WebSocket-based message channel. + /// public ISocketMessageChannel Channel { get; } /// public IEmote Emote { get; } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs index c37f04124..d0ce5025b 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketSystemMessage.cs @@ -3,6 +3,9 @@ using Model = Discord.API.Message; namespace Discord.WebSocket { + /// + /// Represents a WebSocket-based message sent by the system. + /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketSystemMessage : SocketMessage, ISystemMessage { diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index 58e87017c..d22464652 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -9,6 +9,9 @@ using Model = Discord.API.Message; namespace Discord.WebSocket { + /// + /// Represents a WebSocket-based message sent by a user. + /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketUserMessage : SocketMessage, IUserMessage { diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs index 3117eb14c..48de7552a 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Linq; using Model = Discord.API.User; using PresenceModel = Discord.API.Presence; @@ -54,7 +54,8 @@ namespace Discord.WebSocket Presence = SocketPresence.Create(model); DMChannel = state.DMChannels.FirstOrDefault(x => x.Recipient.Id == Id); } - + + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Global)"; internal new SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs index 10701b418..601677e2e 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs @@ -35,6 +35,7 @@ namespace Discord.WebSocket return entity; } + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Group)"; internal new SocketGroupUser Clone() => MemberwiseClone() as SocketGroupUser; //IVoiceState diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 73f5f0b8a..8721e722b 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -61,7 +61,7 @@ namespace Discord.WebSocket public IReadOnlyCollection Roles => _roleIds.Select(id => Guild.GetRole(id)).Where(x => x != null).ToReadOnlyCollection(() => _roleIds.Length); /// - /// Returns the voice channel the user is in, or if none. + /// Returns the voice channel the user is in, or null if none. /// public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; /// @@ -173,6 +173,7 @@ namespace Discord.WebSocket public ChannelPermissions GetPermissions(IGuildChannel channel) => new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, GuildPermissions.RawValue)); + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Guild)"; internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; //IGuildUser diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index 972ba6ea0..af7710629 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -67,6 +67,7 @@ namespace Discord.WebSocket public Task ModifyAsync(Action func, RequestOptions options = null) => UserHelper.ModifyAsync(this, Discord, func, options); + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Self)"; internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs index 4cfaa686d..b3eb08f6d 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs @@ -29,6 +29,7 @@ namespace Discord.WebSocket return entity; } + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Unknown)"; internal new SocketUnknownUser Clone() => MemberwiseClone() as SocketUnknownUser; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs index 428405431..d5f0433ad 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs @@ -23,7 +23,7 @@ namespace Discord.WebSocket private readonly Flags _voiceStates; /// - /// Gets the voice channel that the user is currently in; or if none. + /// Gets the voice channel that the user is currently in; or null if none. /// public SocketVoiceChannel VoiceChannel { get; } /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs index b0374c85d..b66f14e7d 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs @@ -44,6 +44,7 @@ namespace Discord.WebSocket return entity; } + private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Webhook)"; internal new SocketWebhookUser Clone() => MemberwiseClone() as SocketWebhookUser; diff --git a/src/Discord.Net.WebSocket/Entities/Voice/SocketVoiceServer.cs b/src/Discord.Net.WebSocket/Entities/Voice/SocketVoiceServer.cs new file mode 100644 index 000000000..c5f13b1a9 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Voice/SocketVoiceServer.cs @@ -0,0 +1,42 @@ +using System.Diagnostics; + +namespace Discord.WebSocket +{ + /// + /// Represents a WebSocket-based voice server. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class SocketVoiceServer + { + /// + /// Gets the guild associated with the voice server. + /// + /// + /// A cached entity of the guild. + /// + public Cacheable Guild { get; } + /// + /// Gets the endpoint URL of the voice server host. + /// + /// + /// An URL representing the voice server host. + /// + public string Endpoint { get; } + /// + /// Gets the voice connection token. + /// + /// + /// A voice connection token. + /// + public string Token { get; } + + internal SocketVoiceServer(Cacheable guild, string endpoint, string token) + { + Guild = guild; + Endpoint = endpoint; + Token = token; + } + + private string DebuggerDisplay => $"SocketVoiceServer ({Guild.Id})"; + } +}