Browse Source

Merge branch 'dev' into stickers

pull/1726/head
Paulo GitHub 4 years ago
parent
commit
b187009a72
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 526 additions and 98 deletions
  1. +103
    -0
      CHANGELOG.md
  2. +1
    -1
      Discord.Net.targets
  3. +0
    -2
      README.md
  4. +1
    -1
      samples/03_sharded_client/Modules/PublicModule.cs
  5. +1
    -1
      src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs
  6. +12
    -1
      src/Discord.Net.Core/Entities/Messages/IMessage.cs
  7. +36
    -0
      src/Discord.Net.Core/Entities/Messages/MessageFlags.cs
  8. +12
    -0
      src/Discord.Net.Core/Entities/Messages/MessageProperties.cs
  9. +7
    -0
      src/Discord.Net.Core/Entities/Roles/IRole.cs
  10. +40
    -0
      src/Discord.Net.Core/Entities/Roles/RoleTags.cs
  11. +5
    -0
      src/Discord.Net.Core/Entities/Users/IGuildUser.cs
  12. +10
    -0
      src/Discord.Net.Core/Entities/Users/IUser.cs
  13. +39
    -9
      src/Discord.Net.Core/Entities/Users/UserProperties.cs
  14. +1
    -1
      src/Discord.Net.Rest/API/Common/AllowedMentions.cs
  15. +1
    -1
      src/Discord.Net.Rest/API/Common/AuditLogEntry.cs
  16. +2
    -0
      src/Discord.Net.Rest/API/Common/GuildMember.cs
  17. +0
    -10
      src/Discord.Net.Rest/API/Common/MessageFlags.cs
  18. +3
    -1
      src/Discord.Net.Rest/API/Common/Role.cs
  19. +15
    -0
      src/Discord.Net.Rest/API/Common/RoleTags.cs
  20. +2
    -0
      src/Discord.Net.Rest/API/Common/User.cs
  21. +5
    -1
      src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs
  22. +2
    -0
      src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
  23. +9
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs
  24. +5
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs
  25. +10
    -4
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessagePinAuditLogData.cs
  26. +10
    -4
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageUnpinAuditLogData.cs
  27. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs
  28. +29
    -4
      src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
  29. +5
    -0
      src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
  30. +2
    -6
      src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
  31. +4
    -0
      src/Discord.Net.Rest/Entities/Roles/RestRole.cs
  32. +4
    -0
      src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
  33. +4
    -0
      src/Discord.Net.Rest/Entities/Users/RestUser.cs
  34. +2
    -0
      src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs
  35. +4
    -2
      src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs
  36. +7
    -0
      src/Discord.Net.Rest/Extensions/EntityExtensions.cs
  37. +31
    -0
      src/Discord.Net.WebSocket/BaseSocketClient.cs
  38. +14
    -0
      src/Discord.Net.WebSocket/DiscordShardedClient.cs
  39. +42
    -21
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  40. +6
    -0
      src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
  41. +2
    -6
      src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
  42. +4
    -0
      src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs
  43. +4
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
  44. +7
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs
  45. +2
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs
  46. +4
    -2
      src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs
  47. +16
    -16
      src/Discord.Net/Discord.Net.nuspec

+ 103
- 0
CHANGELOG.md View File

@@ -1,5 +1,108 @@
# Changelog

## [2.3.1] - 2021-03-10
### Fixed
- #1761 Deadlock in DiscordShardedClient when Ready is never received (73e5cc2)
- #1773 Private methods aren't added as commands (0fc713a)
- #1780 NullReferenceException in pin/unpin audit logs (f794163)
- #1786 Add ChannelType property to ChannelInfo audit log (6ac5ea1)
- #1791 Update Webhook ChannelId from model change (d2518db)
- #1794 Audit log UserId can be null (d41aeee)

### Misc
- #1774 Add remark regarding CustomStatus as the activity (51b7afe)

## [2.3.0] - 2021-01-28
### Added
- #1491 Add INVITE_CREATE and INVITE_DELETE events (1ab670b)
- #1520 Support reading multiple activities (421a0c1)
- #1521 Allow for inherited commands in modules (a51cdf6)
- #1526 Add Direction.Around to GetMessagesAsync (f2130f8)
- #1537 Implement gateway ratelimit (ec673e1)
- #1544 Add MESSAGE_REACTION_REMOVE_EMOJI and RemoveAllReactionsForEmoteAsync (a89f076)
- #1549 Add GetUsersAsync to SocketGuild (30b5a83)
- #1566 Support Gateway Intents (d5d10d3)
- #1573 Add missing properties to Guild and deprecate GuildEmbed (ec212b1)
- #1581 Add includeRoleIds to PruneUsersAsync (a80e5ff)
- #1588 Add GetStreams to AudioClient (1e012ac)
- #1596 Add missing channel properties (2d80037)
- #1604 Add missing application properties (including Teams) (10fcde0)
- #1619 Add "View Guild Insights" to GuildPermission (2592264)
- #1637 Added CultureInvariant RegexOption to WebhookUrlRegex (e3925a7)
- #1659 Add inline replies (e3850e1)
- #1688 Send presence on Identify payload (25d5d36)
- #1721 Add role tags (6a62c47)
- #1722 Add user public flags (c683b29)
- #1724 Add MessageFlags and AllowedMentions to message modify (225550d)
- #1731 Add GuildUser IsPending property (8b25c9b)
- #1690 Add max bitrate value to SocketGuild (aacfea0)

### Fixed
- #1244 Missing AddReactions permission for DM channels. (e40ca4a)
- #1469 unsupported property causes an exception (468f826)
- #1525 AllowedMentions and AllowedMentionTypes (3325031)
- #1531 Add AllowedMentions to SendFileAsync (ab32607)
- #1532 GuildEmbed.ChannelId as nullable per API documentation (971d519)
- #1546 Different ratelimits for the same route (implement discord buckets) (2f6c017)
- #1548 Incomplete Ready, DownloadUsersAsync, and optimize AlwaysDownloadUsers (dc8c959)
- #1555 InvalidOperationException at MESSAGE_CREATE (bd4672a)
- #1557 Sending 2 requests instead of 1 to create a Guild role. (5430cc8)
- #1571 Not using the new domain name. (df8a0f7)
- #1578 Trim token before passing it to the authorization header (42ba372)
- #1580 Stop TaskCanceledException from bubbling up (b8fa464)
- #1599 Invite audit log without inviter (b95b95b)
- #1602 Add AllowedMentions to webhooks (bd4516b)
- #1603 Cancel reconnection when 4014 (f396cd9)
- #1608 Voice overwrites and CategoryId remarks (43c8fc0)
- #1614 Check error 404 and return null for GetBanAsync (ae9fff6)
- #1621 Parse mentions from message payload (366ca9a)
- #1622 Do not update overwrite cache locally (3860da0)
- #1623 Invoke UserUpdated from GuildMemberUpdated if needed (3085e88)
- #1624 Handle null PreferredLocale in rare cases (c1d04b4)
- #1639 Invite and InviteMetadata properties (dd2e524)
- #1642 Add missing permissions (4b389f3)
- #1647 handicap member downloading for verified bots (fa5ef5e)
- #1652 Update README.MD to reflect new discord domain (03b831e)
- #1667 Audio stream dispose (a2af985)
- #1671 Crosspost throwing InvalidOperationException (9134443)
- #1672 Team is nullable, not optional (be60d81)
- #1681 Emoji url encode (04389a4)
- #1683 SocketGuild.HasAllMembers is false if a user left a guild (47f571e)
- #1686 Revert PremiumSubscriptionCount type (97e71cd)
- #1695 Possible NullReferenceException when receiving InvalidSession (5213916)
- #1702 Rollback Activities to Game (9d7cb39)
- #1727 Move and fix internal AllowedMentions object (4a7f8fe)
- limit request members batch size (084db25)
- UserMentions throwing NullRef (5ed01a3)
- Wrong author for SocketUserMessage.ReferencedMessage (1e9b252)
- Discord sends null when there's no team (05a1f0a)
- IMessage.Embeds docs remarks (a4d32d3)
- Missing MessageReference when sending files (2095701)

### Misc
- #1545 MutualGuilds optimization (323a677)
- #1551 Update webhook regex to support discord.com (7585789)
- #1556 Add SearchUsersAsync (57880de)
- #1561 Minor refactor to switch expression (42826df)
- #1576 Updating comments for privileged intents (c42bfa6)
- #1678 Change ratelimit messages (47ed806)
- #1714 Update summary of SocketVoiceChannel.Users (e385c40)
- #1720 VoiceRegions and related changes (5934c79)
- Add updated libraries for LastModified (d761846)
- Add alternative documentation link (accd351)
- Temporarily disable StyleCops until all the fixes are impl'd (36de7b2)
- Remove redundant CreateGuildRoleParams (3df0539)
- Add minor tweaks to DiscordSocketConfig docs strings (2cd1880)
- Fix MaxWaitBetweenGuildAvailablesBeforeReady docs string (e31cdc7)
- Missing summary tag for GatewayIntents (3a10018)
- Add new method of role ID copy (857ef77)
- Resolve inheritdocs for IAttachment (9ea3291)
- Mark null as a specific langword in summary (13a41f8)
- Cleanup GatewayReconnectException docs (833ee42)
- Update Docfx.Plugins.LastModified to v1.2.4 (28a6f97)
- Update framework version for tests to Core 3.1 to comply with LTS (4988a07)
- Move bulk deletes remarks from <summary> to <remarks> (62539f0)

## [2.2.0] - 2020-04-16
### Added
- #1247 Implement Client Status Support (9da11b4)


+ 1
- 1
Discord.Net.targets View File

@@ -1,6 +1,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>2.3.0</VersionPrefix>
<VersionPrefix>2.4.0</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<LangVersion>latest</LangVersion>
<Authors>Discord.Net Contributors</Authors>


+ 0
- 2
README.md View File

@@ -8,8 +8,6 @@ An unofficial .NET API Wrapper for the Discord client (https://discord.com).

## Documentation

- [Stable](https://discord.foxbot.me/)
- Hosted by @foxbot
- [Nightly](https://docs.stillu.cc/)
- [Latest CI repo](https://github.com/discord-net/docs-static)



+ 1
- 1
samples/03_sharded_client/Modules/PublicModule.cs View File

@@ -9,7 +9,7 @@ namespace _03_sharded_client.Modules
[Command("info")]
public async Task InfoAsync()
{
var msg = $@"Hi {Context.User}! There are currently {Context.Client.Shards} shards!
var msg = $@"Hi {Context.User}! There are currently {Context.Client.Shards.Count} shards!
This guild is being served by shard number {Context.Client.GetShardFor(Context.Guild).ShardId}";
await ReplyAsync(msg);
}


+ 1
- 1
src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs View File

@@ -136,7 +136,7 @@ namespace Discord.Commands
builder.Name = typeInfo.Name;

// Get all methods (including from inherited members), that are valid commands
var validCommands = typeInfo.GetMethods().Where(IsValidCommandDefinition);
var validCommands = typeInfo.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(IsValidCommandDefinition);

foreach (var method in validCommands)
{


+ 12
- 1
src/Discord.Net.Core/Entities/Messages/IMessage.cs View File

@@ -92,10 +92,10 @@ namespace Discord
/// Gets all embeds included in this message.
/// </summary>
/// <remarks>
/// </remarks>
/// This property gets a read-only collection of embeds associated with this message. Depending on the
/// message, a sent message may contain one or more embeds. This is usually true when multiple link previews
/// are generated; however, only one <see cref="EmbedType.Rich"/> <see cref="Embed"/> can be featured.
/// </remarks>
/// <returns>
/// A read-only collection of embed objects.
/// </returns>
@@ -171,6 +171,17 @@ namespace Discord
/// A read-only collection of sticker objects.
/// </returns>
IReadOnlyCollection<ISticker> Stickers { get; }
/// <summary>
/// Gets the flags related to this message.
/// </summary>
/// <remarks>
/// This value is determined by bitwise OR-ing <see cref="MessageFlags"/> values together.
/// </remarks>
/// <returns>
/// A message's flags, if any is associated.
/// </returns>
MessageFlags? Flags { get; }

/// <summary>
/// Adds a reaction to this message.


+ 36
- 0
src/Discord.Net.Core/Entities/Messages/MessageFlags.cs View File

@@ -0,0 +1,36 @@
using System;

namespace Discord
{
[Flags]
public enum MessageFlags
{
/// <summary>
/// Default value for flags, when none are given to a message.
/// </summary>
None = 0,
/// <summary>
/// Flag given to messages that have been published to subscribed
/// channels (via Channel Following).
/// </summary>
Crossposted = 1 << 0,
/// <summary>
/// Flag given to messages that originated from a message in another
/// channel (via Channel Following).
/// </summary>
IsCrosspost = 1 << 1,
/// <summary>
/// Flag given to messages that do not display any embeds.
/// </summary>
SuppressEmbeds = 1 << 2,
/// <summary>
/// Flag given to messages that the source message for this crosspost
/// has been deleted (via Channel Following).
/// </summary>
SourceMessageDeleted = 1 << 3,
/// <summary>
/// Flag given to messages that came from the urgent message system.
/// </summary>
Urgent = 1 << 4,
}
}

+ 12
- 0
src/Discord.Net.Core/Entities/Messages/MessageProperties.cs View File

@@ -21,5 +21,17 @@ namespace Discord
/// Gets or sets the embed the message should display.
/// </summary>
public Optional<Embed> Embed { get; set; }
/// <summary>
/// Gets or sets the flags of the message.
/// </summary>
/// <remarks>
/// Only <see cref="MessageFlags.SuppressEmbeds"/> can be set/unset and you need to be
/// the author of the message.
/// </remarks>
public Optional<MessageFlags?> Flags { get; set; }
/// <summary>
/// Gets or sets the allowed mentions of the message.
/// </summary>
public Optional<AllowedMentions> AllowedMentions { get; set; }
}
}

+ 7
- 0
src/Discord.Net.Core/Entities/Roles/IRole.cs View File

@@ -65,6 +65,13 @@ namespace Discord
/// An <see cref="int"/> representing the position of the role in the role list of the guild.
/// </returns>
int Position { get; }
/// <summary>
/// Gets the tags related to this role.
/// </summary>
/// <returns>
/// A <see cref="RoleTags"/> object containing all tags related to this role.
/// </returns>
RoleTags Tags { get; }

/// <summary>
/// Modifies this role.


+ 40
- 0
src/Discord.Net.Core/Entities/Roles/RoleTags.cs View File

@@ -0,0 +1,40 @@
namespace Discord
{
/// <summary>
/// Provides tags related to a discord role.
/// </summary>
public class RoleTags
{
/// <summary>
/// Gets the identifier of the bot that this role belongs to, if it does.
/// </summary>
/// <returns>
/// A <see langword="ulong"/> if this role belongs to a bot; otherwise
/// <see langword="null"/>.
/// </returns>
public ulong? BotId { get; }
/// <summary>
/// Gets the identifier of the integration that this role belongs to, if it does.
/// </summary>
/// <returns>
/// A <see langword="ulong"/> if this role belongs to an integration; otherwise
/// <see langword="null"/>.
/// </returns>
public ulong? IntegrationId { get; }
/// <summary>
/// Gets if this role is the guild's premium subscriber (booster) role.
/// </summary>
/// <returns>
/// <see langword="true"/> if this role is the guild's premium subscriber role;
/// otherwise <see langword="false"/>.
/// </returns>
public bool IsPremiumSubscriberRole { get; }

internal RoleTags(ulong? botId, ulong? integrationId, bool isPremiumSubscriber)
{
BotId = botId;
IntegrationId = integrationId;
IsPremiumSubscriberRole = isPremiumSubscriber;
}
}
}

+ 5
- 0
src/Discord.Net.Core/Entities/Users/IGuildUser.cs View File

@@ -68,6 +68,11 @@ namespace Discord
/// </returns>
IReadOnlyCollection<ulong> RoleIds { get; }

/// <summary>
/// Whether the user has passed the guild's Membership Screening requirements.
/// </summary>
bool? IsPending { get; }

/// <summary>
/// Gets the level permissions granted to this user to a given channel.
/// </summary>


+ 10
- 0
src/Discord.Net.Core/Entities/Users/IUser.cs View File

@@ -75,6 +75,16 @@ namespace Discord
/// Gets the username for this user.
/// </summary>
string Username { get; }
/// <summary>
/// Gets the public flags that are applied to this user's account.
/// </summary>
/// <remarks>
/// This value is determined by bitwise OR-ing <see cref="UserProperties"/> values together.
/// </remarks>
/// <returns>
/// The value of public flags for this user.
/// </returns>
UserProperties? PublicFlags { get; }

/// <summary>
/// Gets the direct message channel of this user, or create one if it does not already exist.


+ 39
- 9
src/Discord.Net.Core/Entities/Users/UserProperties.cs View File

@@ -10,32 +10,62 @@ namespace Discord
/// </summary>
None = 0,
/// <summary>
/// Flag given to Discord staff.
/// Flag given to users who are a Discord employee.
/// </summary>
Staff = 0b1,
Staff = 1 << 0,
/// <summary>
/// Flag given to Discord partners.
/// Flag given to users who are owners of a partnered Discord server.
/// </summary>
Partner = 0b10,
Partner = 1 << 1,
/// <summary>
/// Flag given to users in HypeSquad events.
/// </summary>
HypeSquadEvents = 1 << 2,
/// <summary>
/// Flag given to users who have participated in the bug report program.
/// This flag is obsolete, use <see cref="BugHunterLevel1"/> instead.
/// </summary>
[Obsolete("Use BugHunterLevel1 instead.")]
BugHunter = 1 << 3,
/// <summary>
/// Flag given to users who have participated in the bug report program and are level 1.
/// </summary>
BugHunter = 0b1000,
BugHunterLevel1 = 1 << 3,
/// <summary>
/// Flag given to users who are in the HypeSquad House of Bravery.
/// </summary>
HypeSquadBravery = 0b100_0000,
HypeSquadBravery = 1 << 6,
/// <summary>
/// Flag given to users who are in the HypeSquad House of Brilliance.
/// </summary>
HypeSquadBrilliance = 0b1000_0000,
HypeSquadBrilliance = 1 << 7,
/// <summary>
/// Flag given to users who are in the HypeSquad House of Balance.
/// </summary>
HypeSquadBalance = 0b1_0000_0000,
HypeSquadBalance = 1 << 8,
/// <summary>
/// Flag given to users who subscribed to Nitro before games were added.
/// </summary>
EarlySupporter = 0b10_0000_0000,
EarlySupporter = 1 << 9,
/// <summary>
/// Flag given to users who are part of a team.
/// </summary>
TeamUser = 1 << 10,
/// <summary>
/// Flag given to users who represent Discord (System).
/// </summary>
System = 1 << 12,
/// <summary>
/// Flag given to users who have participated in the bug report program and are level 2.
/// </summary>
BugHunterLevel2 = 1 << 14,
/// <summary>
/// Flag given to users who are verified bots.
/// </summary>
VerifiedBot = 1 << 16,
/// <summary>
/// Flag given to users that developed bots and early verified their accounts.
/// </summary>
EarlyVerifiedBotDeveloper = 1 << 17,
}
}

src/Discord.Net.Rest/Entities/Messages/AllowedMentions.cs → src/Discord.Net.Rest/API/Common/AllowedMentions.cs View File

@@ -2,7 +2,7 @@ using Newtonsoft.Json;

namespace Discord.API
{
public class AllowedMentions
internal class AllowedMentions
{
[JsonProperty("parse")]
public Optional<string[]> Parse { get; set; }

+ 1
- 1
src/Discord.Net.Rest/API/Common/AuditLogEntry.cs View File

@@ -7,7 +7,7 @@ namespace Discord.API
[JsonProperty("target_id")]
public ulong? TargetId { get; set; }
[JsonProperty("user_id")]
public ulong UserId { get; set; }
public ulong? UserId { get; set; }

[JsonProperty("changes")]
public AuditLogChange[] Changes { get; set; }


+ 2
- 0
src/Discord.Net.Rest/API/Common/GuildMember.cs View File

@@ -18,6 +18,8 @@ namespace Discord.API
public Optional<bool> Deaf { get; set; }
[JsonProperty("mute")]
public Optional<bool> Mute { get; set; }
[JsonProperty("pending")]
public Optional<bool> Pending { get; set; }
[JsonProperty("premium_since")]
public Optional<DateTimeOffset?> PremiumSince { get; set; }
}


+ 0
- 10
src/Discord.Net.Rest/API/Common/MessageFlags.cs View File

@@ -1,10 +0,0 @@
using System;

namespace Discord.API
{
[Flags]
internal enum MessageFlags : byte // probably safe to constrain this to 8 values, if not, it's internal so who cares
{
Suppressed = 0x04,
}
}

+ 3
- 1
src/Discord.Net.Rest/API/Common/Role.cs View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API
@@ -21,5 +21,7 @@ namespace Discord.API
public ulong Permissions { get; set; }
[JsonProperty("managed")]
public bool Managed { get; set; }
[JsonProperty("tags")]
public Optional<RoleTags> Tags { get; set; }
}
}

+ 15
- 0
src/Discord.Net.Rest/API/Common/RoleTags.cs View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API
{
internal class RoleTags
{
[JsonProperty("bot_id")]
public Optional<ulong> BotId { get; set; }
[JsonProperty("integration_id")]
public Optional<ulong> IntegrationId { get; set; }
[JsonProperty("premium_subscriber")]
public Optional<bool?> IsPremiumSubscriber { get; set; }
}
}

+ 2
- 0
src/Discord.Net.Rest/API/Common/User.cs View File

@@ -29,5 +29,7 @@ namespace Discord.API
public Optional<PremiumType> PremiumType { get; set; }
[JsonProperty("locale")]
public Optional<string> Locale { get; set; }
[JsonProperty("public_flags")]
public Optional<UserProperties> PublicFlags { get; set; }
}
}

+ 5
- 1
src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
@@ -10,5 +10,9 @@ namespace Discord.API.Rest
public Optional<string> Content { get; set; }
[JsonProperty("embed")]
public Optional<Embed> Embed { get; set; }
[JsonProperty("flags")]
public Optional<MessageFlags?> Flags { get; set; }
[JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; }
}
}

+ 2
- 0
src/Discord.Net.Rest/API/Rest/UploadFileParams.cs View File

@@ -49,6 +49,8 @@ namespace Discord.API.Rest
payload["allowed_mentions"] = AllowedMentions.Value;
if (IsSpoiler)
payload["hasSpoiler"] = IsSpoiler.ToString();
if (MessageReference.IsSpecified)
payload["message_reference"] = MessageReference.Value;

var json = new StringBuilder();
using (var text = new StringWriter(json))


+ 9
- 1
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs View File

@@ -5,13 +5,14 @@ namespace Discord.Rest
/// </summary>
public struct ChannelInfo
{
internal ChannelInfo(string name, string topic, int? rateLimit, bool? nsfw, int? bitrate)
internal ChannelInfo(string name, string topic, int? rateLimit, bool? nsfw, int? bitrate, ChannelType? type)
{
Name = name;
Topic = topic;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
ChannelType = type;
}

/// <summary>
@@ -53,5 +54,12 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? Bitrate { get; }
/// <summary>
/// Gets the type of this channel.
/// </summary>
/// <returns>
/// The channel type of this channel; <c>null</c> if not applicable.
/// </returns>
public ChannelType? ChannelType { get; }
}
}

+ 5
- 2
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs View File

@@ -26,6 +26,7 @@ namespace Discord.Rest
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");

string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
@@ -37,9 +38,11 @@ namespace Discord.Rest
newNsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newBitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
ChannelType? oldType = typeModel?.OldValue?.ToObject<ChannelType>(discord.ApiClient.Serializer),
newType = typeModel?.NewValue?.ToObject<ChannelType>(discord.ApiClient.Serializer);

var before = new ChannelInfo(oldName, oldTopic, oldRateLimitPerUser, oldNsfw, oldBitrate);
var after = new ChannelInfo(newName, newTopic, newRateLimitPerUser, newNsfw, newBitrate);
var before = new ChannelInfo(oldName, oldTopic, oldRateLimitPerUser, oldNsfw, oldBitrate, oldType);
var after = new ChannelInfo(newName, newTopic, newRateLimitPerUser, newNsfw, newBitrate, newType);

return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after);
}


+ 10
- 4
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessagePinAuditLogData.cs View File

@@ -19,8 +19,14 @@ namespace Discord.Rest

internal static MessagePinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new MessagePinAuditLogData(entry.Options.MessageId.Value, entry.Options.ChannelId.Value, RestUser.Create(discord, userInfo));
RestUser user = null;
if (entry.TargetId.HasValue)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
user = RestUser.Create(discord, userInfo);
}

return new MessagePinAuditLogData(entry.Options.MessageId.Value, entry.Options.ChannelId.Value, user);
}

/// <summary>
@@ -38,10 +44,10 @@ namespace Discord.Rest
/// </returns>
public ulong ChannelId { get; }
/// <summary>
/// Gets the user of the message that was pinned.
/// Gets the user of the message that was pinned if available.
/// </summary>
/// <returns>
/// A user object representing the user that created the pinned message.
/// A user object representing the user that created the pinned message or <see langword="null"/>.
/// </returns>
public IUser Target { get; }
}


+ 10
- 4
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageUnpinAuditLogData.cs View File

@@ -19,8 +19,14 @@ namespace Discord.Rest

internal static MessageUnpinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new MessageUnpinAuditLogData(entry.Options.MessageId.Value, entry.Options.ChannelId.Value, RestUser.Create(discord, userInfo));
RestUser user = null;
if (entry.TargetId.HasValue)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
user = RestUser.Create(discord, userInfo);
}

return new MessageUnpinAuditLogData(entry.Options.MessageId.Value, entry.Options.ChannelId.Value, user);
}

/// <summary>
@@ -38,10 +44,10 @@ namespace Discord.Rest
/// </returns>
public ulong ChannelId { get; }
/// <summary>
/// Gets the user of the message that was unpinned.
/// Gets the user of the message that was unpinned if available.
/// </summary>
/// <returns>
/// A user object representing the user that created the unpinned message.
/// A user object representing the user that created the unpinned message or <see langword="null"/>.
/// </returns>
public IUser Target { get; }
}


+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs View File

@@ -22,7 +22,7 @@ namespace Discord.Rest

internal static RestAuditLogEntry Create(BaseDiscordClient discord, Model fullLog, EntryModel model)
{
var userInfo = fullLog.Users.FirstOrDefault(x => x.Id == model.UserId);
var userInfo = model.UserId != null ? fullLog.Users.FirstOrDefault(x => x.Id == model.UserId) : null;
IUser user = null;
if (userInfo != null)
user = RestUser.Create(discord, userInfo);


+ 29
- 4
src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs View File

@@ -27,21 +27,46 @@ namespace Discord.Rest
public static async Task<Model> ModifyAsync(IMessage msg, BaseDiscordClient client, Action<MessageProperties> func,
RequestOptions options)
{
if (msg.Author.Id != client.CurrentUser.Id)
throw new InvalidOperationException("Only the author of a message may modify the message.");

var args = new MessageProperties();
func(args);

if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embed.IsSpecified || args.AllowedMentions.IsSpecified))
throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions.");

bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content);
bool hasEmbed = args.Embed.IsSpecified ? args.Embed.Value != null : msg.Embeds.Any();
if (!hasText && !hasEmbed)
Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content));

if (args.AllowedMentions.IsSpecified)
{
AllowedMentions allowedMentions = args.AllowedMentions.Value;
Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed.");
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed.");

// check that user flag and user Id list are exclusive, same with role flag and role Id list
if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue)
{
if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) &&
allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0)
{
throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions));
}

if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) &&
allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0)
{
throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions));
}
}
}

var apiArgs = new API.Rest.ModifyMessageParams
{
Content = args.Content,
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>()
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>(),
Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create<MessageFlags?>(),
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create<API.AllowedMentions>(),
};
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false);
}


+ 5
- 0
src/Discord.Net.Rest/Entities/Messages/RestMessage.cs View File

@@ -69,6 +69,8 @@ namespace Discord.Rest
public MessageApplication Application { get; private set; }
/// <inheritdoc />
public MessageReference Reference { get; private set; }
/// <inheritdoc />
public MessageFlags? Flags { get; private set; }

internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source)
: base(discord, id)
@@ -126,6 +128,9 @@ namespace Discord.Rest
};
}

if (model.Flags.IsSpecified)
Flags = model.Flags.Value;

if (model.Reactions.IsSpecified)
{
var value = model.Reactions.Value;


+ 2
- 6
src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs View File

@@ -13,7 +13,7 @@ namespace Discord.Rest
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUserMessage : RestMessage, IUserMessage
{
private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed;
private bool _isMentioningEveryone, _isTTS, _isPinned;
private long? _editedTimestampTicks;
private IUserMessage _referencedMessage;
private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>();
@@ -28,7 +28,7 @@ namespace Discord.Rest
/// <inheritdoc />
public override bool IsPinned => _isPinned;
/// <inheritdoc />
public override bool IsSuppressed => _isSuppressed;
public override bool IsSuppressed => Flags.HasValue && Flags.Value.HasFlag(MessageFlags.SuppressEmbeds);
/// <inheritdoc />
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);
/// <inheritdoc />
@@ -73,10 +73,6 @@ namespace Discord.Rest
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks;
if (model.MentionEveryone.IsSpecified)
_isMentioningEveryone = model.MentionEveryone.Value;
if (model.Flags.IsSpecified)
{
_isSuppressed = model.Flags.Value.HasFlag(API.MessageFlags.Suppressed);
}
if (model.RoleMentions.IsSpecified)
_roleMentionIds = model.RoleMentions.Value.ToImmutableArray();



+ 4
- 0
src/Discord.Net.Rest/Entities/Roles/RestRole.cs View File

@@ -26,6 +26,8 @@ namespace Discord.Rest
public GuildPermissions Permissions { get; private set; }
/// <inheritdoc />
public int Position { get; private set; }
/// <inheritdoc />
public RoleTags Tags { get; private set; }

/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
@@ -56,6 +58,8 @@ namespace Discord.Rest
Position = model.Position;
Color = new Color(model.Color);
Permissions = new GuildPermissions(model.Permissions);
if (model.Tags.IsSpecified)
Tags = model.Tags.Value.ToEntity();
}

/// <inheritdoc />


+ 4
- 0
src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs View File

@@ -29,6 +29,8 @@ namespace Discord.Rest
public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks);
/// <inheritdoc />
public ulong GuildId => Guild.Id;
/// <inheritdoc />
public bool? IsPending { get; private set; }

/// <inheritdoc />
/// <exception cref="InvalidOperationException" accessor="get">Resolving permissions requires the parent guild to be downloaded.</exception>
@@ -73,6 +75,8 @@ namespace Discord.Rest
UpdateRoles(model.Roles.Value);
if (model.PremiumSince.IsSpecified)
_premiumSinceTicks = model.PremiumSince.Value?.UtcTicks;
if (model.Pending.IsSpecified)
IsPending = model.Pending.Value;
}
private void UpdateRoles(ulong[] roleIds)
{


+ 4
- 0
src/Discord.Net.Rest/Entities/Users/RestUser.cs View File

@@ -21,6 +21,8 @@ namespace Discord.Rest
public ushort DiscriminatorValue { get; private set; }
/// <inheritdoc />
public string AvatarId { get; private set; }
/// <inheritdoc />
public UserProperties? PublicFlags { get; private set; }

/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
@@ -65,6 +67,8 @@ namespace Discord.Rest
IsBot = model.Bot.Value;
if (model.Username.IsSpecified)
Username = model.Username.Value;
if (model.PublicFlags.IsSpecified)
PublicFlags = model.PublicFlags.Value;
}

/// <inheritdoc />


+ 2
- 0
src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs View File

@@ -52,6 +52,8 @@ namespace Discord.Rest
/// <inheritdoc />
string IGuildUser.Nickname => null;
/// <inheritdoc />
bool? IGuildUser.IsPending => null;
/// <inheritdoc />
GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook;

/// <inheritdoc />


+ 4
- 2
src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs View File

@@ -11,11 +11,11 @@ namespace Discord.Rest
internal IGuild Guild { get; private set; }
internal ITextChannel Channel { get; private set; }

/// <inheritdoc />
public ulong ChannelId { get; }
/// <inheritdoc />
public string Token { get; }

/// <inheritdoc />
public ulong ChannelId { get; private set; }
/// <inheritdoc />
public string Name { get; private set; }
/// <inheritdoc />
@@ -56,6 +56,8 @@ namespace Discord.Rest

internal void Update(Model model)
{
if (ChannelId != model.ChannelId)
ChannelId = model.ChannelId;
if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value;
if (model.Creator.IsSpecified)


+ 7
- 0
src/Discord.Net.Rest/Extensions/EntityExtensions.cs View File

@@ -34,6 +34,13 @@ namespace Discord.Rest
model.Thumbnail.IsSpecified ? model.Thumbnail.Value.ToEntity() : (EmbedThumbnail?)null,
model.Fields.IsSpecified ? model.Fields.Value.Select(x => x.ToEntity()).ToImmutableArray() : ImmutableArray.Create<EmbedField>());
}
public static RoleTags ToEntity(this API.RoleTags model)
{
return new RoleTags(
model.BotId.IsSpecified ? model.BotId.Value : null,
model.IntegrationId.IsSpecified ? model.IntegrationId.Value : null,
model.IsPremiumSubscriber.IsSpecified ? true : false);
}
public static API.Embed ToModel(this Embed entity)
{
if (entity == null) return null;


+ 31
- 0
src/Discord.Net.WebSocket/BaseSocketClient.cs View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@@ -75,6 +76,7 @@ namespace Discord.WebSocket
/// <returns>
/// A read-only collection of voice regions that the user has access to.
/// </returns>
[Obsolete("This property is obsolete, use the GetVoiceRegionsAsync method instead.")]
public abstract IReadOnlyCollection<RestVoiceRegion> VoiceRegions { get; }

internal BaseSocketClient(DiscordSocketConfig config, DiscordRestApiClient client)
@@ -169,7 +171,26 @@ namespace Discord.WebSocket
/// A REST-based voice region associated with the identifier; <c>null</c> if the voice region is not
/// found.
/// </returns>
[Obsolete("This method is obsolete, use GetVoiceRegionAsync instead.")]
public abstract RestVoiceRegion GetVoiceRegion(string id);
/// <summary>
/// Gets all voice regions.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that contains a read-only collection of REST-based voice regions.
/// </returns>
public abstract ValueTask<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null);
/// <summary>
/// Gets a voice region.
/// </summary>
/// <param name="id">The identifier of the voice region (e.g. <c>eu-central</c> ).</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that contains a REST-based voice region associated with the identifier; <c>null</c> if the
/// voice region is not found.
/// </returns>
public abstract ValueTask<RestVoiceRegion> GetVoiceRegionAsync(string id, RequestOptions options = null);
/// <inheritdoc />
public abstract Task StartAsync();
/// <inheritdoc />
@@ -188,6 +209,12 @@ namespace Discord.WebSocket
/// <param name="name">The name of the game.</param>
/// <param name="streamUrl">If streaming, the URL of the stream. Must be a valid Twitch URL.</param>
/// <param name="type">The type of the game.</param>
/// <remarks>
/// <note type="warning">
/// Bot accounts cannot set <see cref="ActivityType.CustomStatus"/> as their activity
/// type and it will have no effect.
/// </note>
/// </remarks>
/// <returns>
/// A task that represents the asynchronous set operation.
/// </returns>
@@ -201,6 +228,10 @@ namespace Discord.WebSocket
/// Discord will only accept setting of name and the type of activity.
/// </note>
/// <note type="warning">
/// Bot accounts cannot set <see cref="ActivityType.CustomStatus"/> as their activity
/// type and it will have no effect.
/// </note>
/// <note type="warning">
/// Rich Presence cannot be set via this method or client. Rich Presence is strictly limited to RPC
/// clients only.
/// </note>


+ 14
- 0
src/Discord.Net.WebSocket/DiscordShardedClient.cs View File

@@ -37,6 +37,7 @@ namespace Discord.WebSocket
public override IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels => GetPrivateChannels().ToReadOnlyCollection(GetPrivateChannelCount);
public IReadOnlyCollection<DiscordSocketClient> Shards => _shards;
/// <inheritdoc />
[Obsolete("This property is obsolete, use the GetVoiceRegionsAsync method instead.")]
public override IReadOnlyCollection<RestVoiceRegion> VoiceRegions => _shards[0].VoiceRegions;

/// <summary>
@@ -264,9 +265,22 @@ namespace Discord.WebSocket
}

/// <inheritdoc />
[Obsolete("This method is obsolete, use GetVoiceRegionAsync instead.")]
public override RestVoiceRegion GetVoiceRegion(string id)
=> _shards[0].GetVoiceRegion(id);

/// <inheritdoc />
public override async ValueTask<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
{
return await _shards[0].GetVoiceRegionsAsync().ConfigureAwait(false);
}

/// <inheritdoc />
public override async ValueTask<RestVoiceRegion> GetVoiceRegionAsync(string id, RequestOptions options = null)
{
return await _shards[0].GetVoiceRegionAsync(id, options).ConfigureAwait(false);
}

/// <inheritdoc />
/// <exception cref="ArgumentNullException"><paramref name="guilds"/> is <see langword="null"/></exception>
public override async Task DownloadUsersAsync(IEnumerable<IGuild> guilds)


+ 42
- 21
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -110,7 +110,8 @@ namespace Discord.WebSocket
public IReadOnlyCollection<SocketGroupChannel> GroupChannels
=> State.PrivateChannels.OfType<SocketGroupChannel>().ToImmutableArray();
/// <inheritdoc />
public override IReadOnlyCollection<RestVoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection();
[Obsolete("This property is obsolete, use the GetVoiceRegionsAsync method instead.")]
public override IReadOnlyCollection<RestVoiceRegion> VoiceRegions => GetVoiceRegionsAsync().GetAwaiter().GetResult();

/// <summary>
/// Initializes a new REST/WebSocket-based Discord client.
@@ -178,7 +179,6 @@ namespace Discord.WebSocket
return Task.Delay(0);
};

_voiceRegions = ImmutableDictionary.Create<string, RestVoiceRegion>();
_largeGuilds = new ConcurrentQueue<ulong>();
}
private static API.DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config)
@@ -204,13 +204,6 @@ namespace Discord.WebSocket
/// <inheritdoc />
internal override async Task OnLoginAsync(TokenType tokenType, string token)
{
if (_parentClient == null)
{
var voiceRegions = await ApiClient.GetVoiceRegionsAsync(new RequestOptions { IgnoreState = true, RetryMode = RetryMode.AlwaysRetry }).ConfigureAwait(false);
_voiceRegions = voiceRegions.Select(x => RestVoiceRegion.Create(this, x)).ToImmutableDictionary(x => x.Id);
}
else
_voiceRegions = _parentClient._voiceRegions;
await Rest.OnLoginAsync(tokenType, token);
}
/// <inheritdoc />
@@ -218,7 +211,7 @@ namespace Discord.WebSocket
{
await StopAsync().ConfigureAwait(false);
_applicationInfo = null;
_voiceRegions = ImmutableDictionary.Create<string, RestVoiceRegion>();
_voiceRegions = null;
await Rest.OnLogoutAsync();
}

@@ -252,15 +245,15 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Identifying").ConfigureAwait(false);
await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards, guildSubscriptions: _guildSubscriptions, gatewayIntents: _gatewayIntents, presence: BuildCurrentStatus()).ConfigureAwait(false);
}

//Wait for READY
await _connection.WaitAsync().ConfigureAwait(false);
}
finally
{
if (locked)
_shardedClient.ReleaseIdentifyLock();
}

//Wait for READY
await _connection.WaitAsync().ConfigureAwait(false);
}
private async Task OnDisconnectingAsync(Exception ex)
{
@@ -350,11 +343,39 @@ namespace Discord.WebSocket
=> State.RemoveUser(id);

/// <inheritdoc />
[Obsolete("This method is obsolete, use GetVoiceRegionAsync instead.")]
public override RestVoiceRegion GetVoiceRegion(string id)
=> GetVoiceRegionAsync(id).GetAwaiter().GetResult();

/// <inheritdoc />
public override async ValueTask<IReadOnlyCollection<RestVoiceRegion>> GetVoiceRegionsAsync(RequestOptions options = null)
{
if (_parentClient == null)
{
if (_voiceRegions == null)
{
options = RequestOptions.CreateOrClone(options);
options.IgnoreState = true;
var voiceRegions = await ApiClient.GetVoiceRegionsAsync(options).ConfigureAwait(false);
_voiceRegions = voiceRegions.Select(x => RestVoiceRegion.Create(this, x)).ToImmutableDictionary(x => x.Id);
}
return _voiceRegions.ToReadOnlyCollection();
}
return await _parentClient.GetVoiceRegionsAsync().ConfigureAwait(false);
}

/// <inheritdoc />
public override async ValueTask<RestVoiceRegion> GetVoiceRegionAsync(string id, RequestOptions options = null)
{
if (_voiceRegions.TryGetValue(id, out RestVoiceRegion region))
return region;
return null;
if (_parentClient == null)
{
if (_voiceRegions == null)
await GetVoiceRegionsAsync().ConfigureAwait(false);
if (_voiceRegions.TryGetValue(id, out RestVoiceRegion region))
return region;
return null;
}
return await _parentClient.GetVoiceRegionAsync(id, options).ConfigureAwait(false);
}

/// <inheritdoc />
@@ -611,7 +632,7 @@ namespace Discord.WebSocket
}
else if (_connection.CancelToken.IsCancellationRequested)
return;
if (BaseConfig.AlwaysDownloadUsers)
_ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers));

@@ -2120,11 +2141,11 @@ namespace Discord.WebSocket
=> Task.FromResult<IUser>(GetUser(username, discriminator));

/// <inheritdoc />
Task<IReadOnlyCollection<IVoiceRegion>> IDiscordClient.GetVoiceRegionsAsync(RequestOptions options)
=> Task.FromResult<IReadOnlyCollection<IVoiceRegion>>(VoiceRegions);
async Task<IReadOnlyCollection<IVoiceRegion>> IDiscordClient.GetVoiceRegionsAsync(RequestOptions options)
=> await GetVoiceRegionsAsync(options).ConfigureAwait(false);
/// <inheritdoc />
Task<IVoiceRegion> IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options)
=> Task.FromResult<IVoiceRegion>(GetVoiceRegion(id));
async Task<IVoiceRegion> IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options)
=> await GetVoiceRegionAsync(id, options).ConfigureAwait(false);

/// <inheritdoc />
async Task IDiscordClient.StartAsync()


+ 6
- 0
src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs View File

@@ -58,6 +58,9 @@ namespace Discord.WebSocket
/// <inheritdoc />
public MessageReference Reference { get; private set; }

/// <inheritdoc />
public MessageFlags? Flags { get; private set; }

/// <summary>
/// Returns all attachments included in this message.
/// </summary>
@@ -158,6 +161,9 @@ namespace Discord.WebSocket
MessageId = model.Reference.Value.MessageId
};
}

if (model.Flags.IsSpecified)
Flags = model.Flags.Value;
}

/// <inheritdoc />


+ 2
- 6
src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs View File

@@ -15,7 +15,7 @@ namespace Discord.WebSocket
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SocketUserMessage : SocketMessage, IUserMessage
{
private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed;
private bool _isMentioningEveryone, _isTTS, _isPinned;
private long? _editedTimestampTicks;
private IUserMessage _referencedMessage;
private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>();
@@ -30,7 +30,7 @@ namespace Discord.WebSocket
/// <inheritdoc />
public override bool IsPinned => _isPinned;
/// <inheritdoc />
public override bool IsSuppressed => _isSuppressed;
public override bool IsSuppressed => Flags.HasValue && Flags.Value.HasFlag(MessageFlags.SuppressEmbeds);
/// <inheritdoc />
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);
/// <inheritdoc />
@@ -77,10 +77,6 @@ namespace Discord.WebSocket
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks;
if (model.MentionEveryone.IsSpecified)
_isMentioningEveryone = model.MentionEveryone.Value;
if (model.Flags.IsSpecified)
{
_isSuppressed = model.Flags.Value.HasFlag(API.MessageFlags.Suppressed);
}
if (model.RoleMentions.IsSpecified)
_roleMentions = model.RoleMentions.Value.Select(x => guild.GetRole(x)).ToImmutableArray();



+ 4
- 0
src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs View File

@@ -36,6 +36,8 @@ namespace Discord.WebSocket
public GuildPermissions Permissions { get; private set; }
/// <inheritdoc />
public int Position { get; private set; }
/// <inheritdoc />
public RoleTags Tags { get; private set; }

/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
@@ -71,6 +73,8 @@ namespace Discord.WebSocket
Position = model.Position;
Color = new Color(model.Color);
Permissions = new GuildPermissions(model.Permissions);
if (model.Tags.IsSpecified)
Tags = model.Tags.Value.ToEntity();
}

/// <inheritdoc />


+ 4
- 0
src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs View File

@@ -57,6 +57,8 @@ namespace Discord.WebSocket
/// <inheritdoc />
public bool IsStreaming => VoiceState?.IsStreaming ?? false;
/// <inheritdoc />
public bool? IsPending { get; private set; }
/// <inheritdoc />
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
/// <summary>
/// Returns a collection of roles that the user possesses.
@@ -142,6 +144,8 @@ namespace Discord.WebSocket
UpdateRoles(model.Roles.Value);
if (model.PremiumSince.IsSpecified)
_premiumSinceTicks = model.PremiumSince.Value?.UtcTicks;
if (model.Pending.IsSpecified)
IsPending = model.Pending.Value;
}
internal void Update(ClientState state, PresenceModel model, bool updatePresence)
{


+ 7
- 0
src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs View File

@@ -26,6 +26,8 @@ namespace Discord.WebSocket
public abstract string AvatarId { get; internal set; }
/// <inheritdoc />
public abstract bool IsWebhook { get; }
/// <inheritdoc />
public UserProperties? PublicFlags { get; private set; }
internal abstract SocketGlobalUser GlobalUser { get; }
internal abstract SocketPresence Presence { get; set; }

@@ -83,6 +85,11 @@ namespace Discord.WebSocket
Username = model.Username.Value;
hasChanges = true;
}
if (model.PublicFlags.IsSpecified && model.PublicFlags.Value != PublicFlags)
{
PublicFlags = model.PublicFlags.Value;
hasChanges = true;
}
return hasChanges;
}



+ 2
- 0
src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs View File

@@ -65,6 +65,8 @@ namespace Discord.WebSocket
/// <inheritdoc />
DateTimeOffset? IGuildUser.PremiumSince => null;
/// <inheritdoc />
bool? IGuildUser.IsPending => null;
/// <inheritdoc />
GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook;

/// <inheritdoc />


+ 4
- 2
src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Webhook;
@@ -11,9 +11,9 @@ namespace Discord.Webhook
private DiscordWebhookClient _client;

public ulong Id { get; }
public ulong ChannelId { get; }
public string Token { get; }

public ulong ChannelId { get; private set; }
public string Name { get; private set; }
public string AvatarId { get; private set; }
public ulong? GuildId { get; private set; }
@@ -36,6 +36,8 @@ namespace Discord.Webhook

internal void Update(Model model)
{
if (ChannelId != model.ChannelId)
ChannelId = model.ChannelId;
if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value;
if (model.GuildId.IsSpecified)


+ 16
- 16
src/Discord.Net/Discord.Net.nuspec View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Discord.Net</id>
<version>2.3.0-dev$suffix$</version>
<version>2.4.0$suffix$</version>
<title>Discord.Net</title>
<authors>Discord.Net Contributors</authors>
<owners>foxbot</owners>
@@ -14,25 +14,25 @@
<iconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl>
<dependencies>
<group targetFramework="net461">
<dependency id="Discord.Net.Core" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Rest" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Commands" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Core" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Commands" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.4.0$suffix$" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="Discord.Net.Core" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Rest" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Commands" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Core" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Commands" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.4.0$suffix$" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="Discord.Net.Core" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Rest" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Commands" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.3.0-dev$suffix$" />
<dependency id="Discord.Net.Core" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.WebSocket" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Commands" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Webhook" version="2.4.0$suffix$" />
</group>
</dependencies>
</metadata>


Loading…
Cancel
Save