@@ -1,5 +1,127 @@ | |||||
# Changelog | # Changelog | ||||
## [2.4.0] - 2021-05-22 | |||||
### Added | |||||
- #1726 Add stickers (91a9063) | |||||
- #1753 Webhook message edit & delete functionality (f67cd8e) | |||||
- #1757 Add ability to add/remove roles by id (4c9910c) | |||||
- #1781 Add GetEmotesAsync to IGuild (df23d57) | |||||
- #1801 Add missing property to MESSAGE_REACTION_ADD event (0715d7d) | |||||
- #1828 Add methods to interact with reactions without a message object (5b244f2) | |||||
- #1830 Add ModifyMessageAsync to IMessageChannel (365a848) | |||||
- #1844 Add Discord Certified Moderator user flag (4b8d444) | |||||
### Fixed | |||||
- #1486 Add type reader when entity type reader exists (c46daaa) | |||||
- #1835 Cached message emoji cleanup at MESSAGE_REACTION_REMOVE_EMOJI (8afef82) | |||||
### Misc | |||||
- #1778 Remove URI check from EmbedBuilder (25b04c4) | |||||
- #1800 Fix spelling in SnowflakeUtils.FromSnowflake (6aff419) | |||||
## [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 | ## [2.2.0] - 2020-04-16 | ||||
### Added | ### Added | ||||
- #1247 Implement Client Status Support (9da11b4) | - #1247 Implement Client Status Support (9da11b4) | ||||
@@ -1,6 +1,6 @@ | |||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
<PropertyGroup> | <PropertyGroup> | ||||
<VersionPrefix>2.3.0</VersionPrefix> | |||||
<VersionPrefix>3.0.0</VersionPrefix> | |||||
<VersionSuffix>dev</VersionSuffix> | <VersionSuffix>dev</VersionSuffix> | ||||
<LangVersion>latest</LangVersion> | <LangVersion>latest</LangVersion> | ||||
<Authors>Discord.Net Contributors</Authors> | <Authors>Discord.Net Contributors</Authors> | ||||
@@ -28,7 +28,7 @@ public async Task SendRichEmbedAsync() | |||||
var embed = new EmbedBuilder | var embed = new EmbedBuilder | ||||
{ | { | ||||
// Embed property can be set within object initializer | // Embed property can be set within object initializer | ||||
Title = "Hello world!" | |||||
Title = "Hello world!", | |||||
Description = "I am a description set by initializer." | Description = "I am a description set by initializer." | ||||
}; | }; | ||||
// Or with methods | // Or with methods | ||||
@@ -134,7 +134,7 @@ If, for whatever reason, you have two commands which are ambiguous to | |||||
each other, you may use the @Discord.Commands.PriorityAttribute to | each other, you may use the @Discord.Commands.PriorityAttribute to | ||||
specify which should be tested before the other. | specify which should be tested before the other. | ||||
The `Priority` attributes are sorted in ascending order; the higher | |||||
The `Priority` attributes are sorted in descending order; the higher | |||||
priority will be called first. | priority will be called first. | ||||
### Command Context | ### Command Context | ||||
@@ -80,15 +80,11 @@ recommended for these operations to be awaited in a | |||||
properly established async context whenever possible. | properly established async context whenever possible. | ||||
To establish an async context, we will be creating an async main method | To establish an async context, we will be creating an async main method | ||||
in your console application, and rewriting the static main method to | |||||
invoke the new async main. | |||||
in your console application. | |||||
[!code-csharp[Async Context](samples/first-bot/async-context.cs)] | [!code-csharp[Async Context](samples/first-bot/async-context.cs)] | ||||
As a result of this, your program will now start and immediately | |||||
jump into an async context. This allows us to create a connection | |||||
to Discord later on without having to worry about setting up the | |||||
correct async implementation. | |||||
As a result of this, your program will now start into an async context. | |||||
> [!WARNING] | > [!WARNING] | ||||
> If your application throws any exceptions within an async context, | > If your application throws any exceptions within an async context, | ||||
@@ -1,7 +1,6 @@ | |||||
public class Program | public class Program | ||||
{ | { | ||||
public static void Main(string[] args) | |||||
=> new Program().MainAsync().GetAwaiter().GetResult(); | |||||
public static Task Main(string[] args) => new Program().MainAsync(); | |||||
public async Task MainAsync() | public async Task MainAsync() | ||||
{ | { | ||||
@@ -2,8 +2,7 @@ public class Program | |||||
{ | { | ||||
private DiscordSocketClient _client; | private DiscordSocketClient _client; | ||||
public static void Main(string[] args) | |||||
=> new Program().MainAsync().GetAwaiter().GetResult(); | |||||
public static Task Main(string[] args) => new Program().MainAsync(); | |||||
public async Task MainAsync() | public async Task MainAsync() | ||||
{ | { | ||||
@@ -10,11 +10,11 @@ using Discord.WebSocket; | |||||
class Program | class Program | ||||
{ | { | ||||
// Program entry point | // Program entry point | ||||
static void Main(string[] args) | |||||
static Task Main(string[] args) | |||||
{ | { | ||||
// Call the Program constructor, followed by the | // Call the Program constructor, followed by the | ||||
// MainAsync method and wait until it finishes (which should be never). | // MainAsync method and wait until it finishes (which should be never). | ||||
new Program().MainAsync().GetAwaiter().GetResult(); | |||||
return new Program().MainAsync(); | |||||
} | } | ||||
private readonly DiscordSocketClient _client; | private readonly DiscordSocketClient _client; | ||||
@@ -9,7 +9,7 @@ namespace _03_sharded_client.Modules | |||||
[Command("info")] | [Command("info")] | ||||
public async Task InfoAsync() | 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}"; | This guild is being served by shard number {Context.Client.GetShardFor(Context.Guild).ShardId}"; | ||||
await ReplyAsync(msg); | await ReplyAsync(msg); | ||||
} | } | ||||
@@ -136,7 +136,7 @@ namespace Discord.Commands | |||||
builder.Name = typeInfo.Name; | builder.Name = typeInfo.Name; | ||||
// Get all methods (including from inherited members), that are valid commands | // 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) | foreach (var method in validCommands) | ||||
{ | { | ||||
@@ -408,7 +408,7 @@ namespace Discord.Commands | |||||
var typeInfo = type.GetTypeInfo(); | var typeInfo = type.GetTypeInfo(); | ||||
if (typeInfo.IsEnum) | if (typeInfo.IsEnum) | ||||
return true; | return true; | ||||
return _entityTypeReaders.Any(x => type == x.EntityType || typeInfo.ImplementedInterfaces.Contains(x.TypeReaderType)); | |||||
return _entityTypeReaders.Any(x => type == x.EntityType || typeInfo.ImplementedInterfaces.Contains(x.EntityType)); | |||||
} | } | ||||
internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader) | internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader) | ||||
{ | { | ||||
@@ -511,7 +511,7 @@ namespace Discord.Commands | |||||
await _commandExecutedEvent.InvokeAsync(Optional.Create<CommandInfo>(), context, searchResult).ConfigureAwait(false); | await _commandExecutedEvent.InvokeAsync(Optional.Create<CommandInfo>(), context, searchResult).ConfigureAwait(false); | ||||
return searchResult; | return searchResult; | ||||
} | } | ||||
var commands = searchResult.Commands; | var commands = searchResult.Commands; | ||||
var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>(); | var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>(); | ||||
@@ -16,7 +16,7 @@ namespace Discord | |||||
/// <see href="https://discord.com/developers/docs/reference#api-versioning">Discord API documentation</see> | /// <see href="https://discord.com/developers/docs/reference#api-versioning">Discord API documentation</see> | ||||
/// .</para> | /// .</para> | ||||
/// </returns> | /// </returns> | ||||
public const int APIVersion = 6; | |||||
public const int APIVersion = 9; | |||||
/// <summary> | /// <summary> | ||||
/// Returns the Voice API version Discord.Net uses. | /// Returns the Voice API version Discord.Net uses. | ||||
/// </summary> | /// </summary> | ||||
@@ -43,7 +43,7 @@ namespace Discord | |||||
/// <returns> | /// <returns> | ||||
/// The user agent used in each Discord.Net request. | /// The user agent used in each Discord.Net request. | ||||
/// </returns> | /// </returns> | ||||
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | |||||
public static string UserAgent { get; } = $"DiscordBot (https://github.com/discord-net/Discord.Net, v{Version})"; | |||||
/// <summary> | /// <summary> | ||||
/// Returns the base Discord API URL. | /// Returns the base Discord API URL. | ||||
/// </summary> | /// </summary> | ||||
@@ -141,18 +141,6 @@ namespace Discord | |||||
/// </remarks> | /// </remarks> | ||||
internal bool DisplayInitialLog { get; set; } = true; | internal bool DisplayInitialLog { get; set; } = true; | ||||
/// <summary> | |||||
/// Gets or sets the level of precision of the rate limit reset response. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// If set to <see cref="RateLimitPrecision.Second"/>, this value will be rounded up to the | |||||
/// nearest second. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// The currently set <see cref="RateLimitPrecision"/>. | |||||
/// </returns> | |||||
public RateLimitPrecision RateLimitPrecision { get; set; } = RateLimitPrecision.Millisecond; | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets whether or not rate-limits should use the system clock. | /// Gets or sets whether or not rate-limits should use the system clock. | ||||
/// </summary> | /// </summary> | ||||
@@ -260,6 +260,21 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task DeleteMessageAsync(IMessage message, RequestOptions options = null); | Task DeleteMessageAsync(IMessage message, RequestOptions options = null); | ||||
/// <summary> | |||||
/// Modifies a message. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This method modifies this message with the specified properties. To see an example of this | |||||
/// method and what properties are available, please refer to <see cref="MessageProperties"/>. | |||||
/// </remarks> | |||||
/// <param name="messageId">The snowflake identifier of the message that would be changed.</param> | |||||
/// <param name="func">A delegate containing the properties to modify the message with.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous modification operation. | |||||
/// </returns> | |||||
Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. | /// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. | ||||
/// </summary> | /// </summary> | ||||
@@ -1,21 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Provides properties that are used to modify the widget of an <see cref="IGuild" /> with the specified changes. | |||||
/// </summary> | |||||
public class GuildEmbedProperties | |||||
{ | |||||
/// <summary> | |||||
/// Sets whether the widget should be enabled. | |||||
/// </summary> | |||||
public Optional<bool> Enabled { get; set; } | |||||
/// <summary> | |||||
/// Sets the channel that the invite should place its users in, if not <c>null</c>. | |||||
/// </summary> | |||||
public Optional<IChannel> Channel { get; set; } | |||||
/// <summary> | |||||
/// Sets the channel the invite should place its users in, if not <c>null</c>. | |||||
/// </summary> | |||||
public Optional<ulong?> ChannelId { get; set; } | |||||
} | |||||
} |
@@ -28,13 +28,6 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
int AFKTimeout { get; } | int AFKTimeout { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets a value that indicates whether this guild is embeddable (i.e. can use widget). | |||||
/// </summary> | |||||
/// <returns> | |||||
/// <see langword="true" /> if this guild has a widget enabled; otherwise <see langword="false" />. | |||||
/// </returns> | |||||
bool IsEmbeddable { get; } | |||||
/// <summary> | |||||
/// Gets a value that indicates whether this guild has the widget enabled. | /// Gets a value that indicates whether this guild has the widget enabled. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
@@ -132,29 +125,6 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
ulong? AFKChannelId { get; } | ulong? AFKChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the ID of the default channel for this guild. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This property retrieves the snowflake identifier of the first viewable text channel for this guild. | |||||
/// <note type="warning"> | |||||
/// This channel does not guarantee the user can send message to it, as it only looks for the first viewable | |||||
/// text channel. | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// A <see langword="ulong"/> representing the snowflake identifier of the default text channel; <c>0</c> if | |||||
/// none can be found. | |||||
/// </returns> | |||||
ulong DefaultChannelId { get; } | |||||
/// <summary> | |||||
/// Gets the ID of the widget embed channel of this guild. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see langword="ulong"/> representing the snowflake identifier of the embedded channel found within the | |||||
/// widget settings of this guild; <see langword="null" /> if none is set. | |||||
/// </returns> | |||||
ulong? EmbedChannelId { get; } | |||||
/// <summary> | |||||
/// Gets the ID of the channel assigned to the widget of this guild. | /// Gets the ID of the channel assigned to the widget of this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
@@ -364,16 +334,6 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task ModifyAsync(Action<GuildProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<GuildProperties> func, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Modifies this guild's embed channel. | |||||
/// </summary> | |||||
/// <param name="func">The delegate containing the properties to modify the guild widget with.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous modification operation. | |||||
/// </returns> | |||||
[Obsolete("This endpoint is deprecated, use ModifyWidgetAsync instead.")] | |||||
Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Modifies this guild's widget. | /// Modifies this guild's widget. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="func">The delegate containing the properties to modify the guild widget with.</param> | /// <param name="func">The delegate containing the properties to modify the guild widget with.</param> | ||||
@@ -592,17 +552,6 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the embed channel (i.e. the channel set in the guild's widget settings) in this guild. | |||||
/// </summary> | |||||
/// <param name="mode">The <see cref="CacheMode" /> that determines whether the object should be fetched from cache.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous get operation. The task result contains the embed channel set | |||||
/// within the server's widget settings; <see langword="null" /> if none is set. | |||||
/// </returns> | |||||
[Obsolete("This endpoint is deprecated, use GetWidgetChannelAsync instead.")] | |||||
Task<IGuildChannel> GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Gets the widget channel (i.e. the channel set in the guild's widget settings) in this guild. | /// Gets the widget channel (i.e. the channel set in the guild's widget settings) in this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="mode">The <see cref="CacheMode" /> that determines whether the object should be fetched from cache.</param> | /// <param name="mode">The <see cref="CacheMode" /> that determines whether the object should be fetched from cache.</param> | ||||
@@ -892,6 +841,15 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null); | ||||
/// <summary> | |||||
/// Gets a collection of emotes from this guild. | |||||
/// </summary> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous get operation. The task result contains a read-only collection | |||||
/// of emotes found within the guild. | |||||
/// </returns> | |||||
Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Gets a specific emote from this guild. | /// Gets a specific emote from this guild. | ||||
/// </summary> | /// </summary> | ||||
@@ -8,10 +8,10 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// The target of the permission is a role. | /// The target of the permission is a role. | ||||
/// </summary> | /// </summary> | ||||
Role, | |||||
Role = 0, | |||||
/// <summary> | /// <summary> | ||||
/// The target of the permission is a user. | /// The target of the permission is a user. | ||||
/// </summary> | /// </summary> | ||||
User | |||||
User = 1, | |||||
} | } | ||||
} | } |
@@ -20,6 +20,13 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
string Url { get; } | string Url { get; } | ||||
/// <summary> | |||||
/// Gets the user that created this invite. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A user that created this invite. | |||||
/// </returns> | |||||
IUser Inviter { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the channel this invite is linked to. | /// Gets the channel this invite is linked to. | ||||
/// </summary> | /// </summary> | ||||
@@ -83,5 +90,19 @@ namespace Discord | |||||
/// invite points to; <c>null</c> if one cannot be obtained. | /// invite points to; <c>null</c> if one cannot be obtained. | ||||
/// </returns> | /// </returns> | ||||
int? MemberCount { get; } | int? MemberCount { get; } | ||||
/// <summary> | |||||
/// Gets the user this invite is linked to via <see cref="TargetUserType"/>. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A user that is linked to this invite. | |||||
/// </returns> | |||||
IUser TargetUser { get; } | |||||
/// <summary> | |||||
/// Gets the type of the linked <see cref="TargetUser"/> for this invite. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// The type of the linked user that is linked to this invite. | |||||
/// </returns> | |||||
TargetUserType TargetUserType { get; } | |||||
} | } | ||||
} | } |
@@ -7,20 +7,6 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public interface IInviteMetadata : IInvite | public interface IInviteMetadata : IInvite | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the user that created this invite. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A user that created this invite. | |||||
/// </returns> | |||||
IUser Inviter { get; } | |||||
/// <summary> | |||||
/// Gets a value that indicates whether the invite has been revoked. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// <c>true</c> if this invite was revoked; otherwise <c>false</c>. | |||||
/// </returns> | |||||
bool IsRevoked { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets a value that indicates whether the invite is a temporary one. | /// Gets a value that indicates whether the invite is a temporary one. | ||||
/// </summary> | /// </summary> | ||||
@@ -12,7 +12,6 @@ namespace Discord | |||||
{ | { | ||||
private string _title; | private string _title; | ||||
private string _description; | private string _description; | ||||
private string _url; | |||||
private EmbedImage? _image; | private EmbedImage? _image; | ||||
private EmbedThumbnail? _thumbnail; | private EmbedThumbnail? _thumbnail; | ||||
private List<EmbedFieldBuilder> _fields; | private List<EmbedFieldBuilder> _fields; | ||||
@@ -70,26 +69,14 @@ namespace Discord | |||||
/// <summary> Gets or sets the URL of an <see cref="Embed"/>. </summary> | /// <summary> Gets or sets the URL of an <see cref="Embed"/>. </summary> | ||||
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | /// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | ||||
/// <returns> The URL of the embed.</returns> | /// <returns> The URL of the embed.</returns> | ||||
public string Url | |||||
{ | |||||
get => _url; | |||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(Url)); | |||||
_url = value; | |||||
} | |||||
} | |||||
public string Url { get; set; } | |||||
/// <summary> Gets or sets the thumbnail URL of an <see cref="Embed"/>. </summary> | /// <summary> Gets or sets the thumbnail URL of an <see cref="Embed"/>. </summary> | ||||
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | /// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | ||||
/// <returns> The thumbnail URL of the embed.</returns> | /// <returns> The thumbnail URL of the embed.</returns> | ||||
public string ThumbnailUrl | public string ThumbnailUrl | ||||
{ | { | ||||
get => _thumbnail?.Url; | get => _thumbnail?.Url; | ||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(ThumbnailUrl)); | |||||
_thumbnail = new EmbedThumbnail(value, null, null, null); | |||||
} | |||||
set => _thumbnail = new EmbedThumbnail(value, null, null, null); | |||||
} | } | ||||
/// <summary> Gets or sets the image URL of an <see cref="Embed"/>. </summary> | /// <summary> Gets or sets the image URL of an <see cref="Embed"/>. </summary> | ||||
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | /// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception> | ||||
@@ -97,11 +84,7 @@ namespace Discord | |||||
public string ImageUrl | public string ImageUrl | ||||
{ | { | ||||
get => _image?.Url; | get => _image?.Url; | ||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(ImageUrl)); | |||||
_image = new EmbedImage(value, null, null, null); | |||||
} | |||||
set => _image = new EmbedImage(value, null, null, null); | |||||
} | } | ||||
/// <summary> Gets or sets the list of <see cref="EmbedFieldBuilder"/> of an <see cref="Embed"/>. </summary> | /// <summary> Gets or sets the list of <see cref="EmbedFieldBuilder"/> of an <see cref="Embed"/>. </summary> | ||||
@@ -553,8 +536,6 @@ namespace Discord | |||||
public class EmbedAuthorBuilder | public class EmbedAuthorBuilder | ||||
{ | { | ||||
private string _name; | private string _name; | ||||
private string _url; | |||||
private string _iconUrl; | |||||
/// <summary> | /// <summary> | ||||
/// Gets the maximum author name length allowed by Discord. | /// Gets the maximum author name length allowed by Discord. | ||||
/// </summary> | /// </summary> | ||||
@@ -585,15 +566,7 @@ namespace Discord | |||||
/// <returns> | /// <returns> | ||||
/// The URL of the author field. | /// The URL of the author field. | ||||
/// </returns> | /// </returns> | ||||
public string Url | |||||
{ | |||||
get => _url; | |||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(Url)); | |||||
_url = value; | |||||
} | |||||
} | |||||
public string Url { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the icon URL of the author field. | /// Gets or sets the icon URL of the author field. | ||||
/// </summary> | /// </summary> | ||||
@@ -601,15 +574,7 @@ namespace Discord | |||||
/// <returns> | /// <returns> | ||||
/// The icon URL of the author field. | /// The icon URL of the author field. | ||||
/// </returns> | /// </returns> | ||||
public string IconUrl | |||||
{ | |||||
get => _iconUrl; | |||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(IconUrl)); | |||||
_iconUrl = value; | |||||
} | |||||
} | |||||
public string IconUrl { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// Sets the name of the author field. | /// Sets the name of the author field. | ||||
@@ -671,7 +636,6 @@ namespace Discord | |||||
public class EmbedFooterBuilder | public class EmbedFooterBuilder | ||||
{ | { | ||||
private string _text; | private string _text; | ||||
private string _iconUrl; | |||||
/// <summary> | /// <summary> | ||||
/// Gets the maximum footer length allowed by Discord. | /// Gets the maximum footer length allowed by Discord. | ||||
@@ -703,15 +667,7 @@ namespace Discord | |||||
/// <returns> | /// <returns> | ||||
/// The icon URL of the footer field. | /// The icon URL of the footer field. | ||||
/// </returns> | /// </returns> | ||||
public string IconUrl | |||||
{ | |||||
get => _iconUrl; | |||||
set | |||||
{ | |||||
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(IconUrl)); | |||||
_iconUrl = value; | |||||
} | |||||
} | |||||
public string IconUrl { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// Sets the name of the footer field. | /// Sets the name of the footer field. | ||||
@@ -92,10 +92,10 @@ namespace Discord | |||||
/// Gets all embeds included in this message. | /// Gets all embeds included in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// </remarks> | |||||
/// This property gets a read-only collection of embeds associated with this message. Depending on the | /// 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 | /// 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. | /// are generated; however, only one <see cref="EmbedType.Rich"/> <see cref="Embed"/> can be featured. | ||||
/// </remarks> | |||||
/// <returns> | /// <returns> | ||||
/// A read-only collection of embed objects. | /// A read-only collection of embed objects. | ||||
/// </returns> | /// </returns> | ||||
@@ -168,6 +168,25 @@ namespace Discord | |||||
/// The <see cref="IMessageComponent"/>'s attached to this message | /// The <see cref="IMessageComponent"/>'s attached to this message | ||||
/// </summary> | /// </summary> | ||||
IReadOnlyCollection<IMessageComponent> Components { get; } | IReadOnlyCollection<IMessageComponent> Components { get; } | ||||
/// Gets all stickers included in this message. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// 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> | /// <summary> | ||||
/// Adds a reaction to this message. | /// Adds a reaction to this message. | ||||
/// </summary> | /// </summary> | ||||
@@ -0,0 +1,67 @@ | |||||
using System.Collections.Generic; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents a discord sticker. | |||||
/// </summary> | |||||
public interface ISticker | |||||
{ | |||||
/// <summary> | |||||
/// Gets the ID of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A snowflake ID associated with this sticker. | |||||
/// </returns> | |||||
ulong Id { get; } | |||||
/// <summary> | |||||
/// Gets the ID of the pack of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A snowflake ID associated with the pack of this sticker. | |||||
/// </returns> | |||||
ulong PackId { get; } | |||||
/// <summary> | |||||
/// Gets the name of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see langword="string"/> with the name of this sticker. | |||||
/// </returns> | |||||
string Name { get; } | |||||
/// <summary> | |||||
/// Gets the description of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see langword="string"/> with the description of this sticker. | |||||
/// </returns> | |||||
string Description { get; } | |||||
/// <summary> | |||||
/// Gets the list of tags of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A read-only list with the tags of this sticker. | |||||
/// </returns> | |||||
IReadOnlyCollection<string> Tags { get; } | |||||
/// <summary> | |||||
/// Gets the asset hash of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see langword="string"/> with the asset hash of this sticker. | |||||
/// </returns> | |||||
string Asset { get; } | |||||
/// <summary> | |||||
/// Gets the preview asset hash of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see langword="string"/> with the preview asset hash of this sticker. | |||||
/// </returns> | |||||
string PreviewAsset { get; } | |||||
/// <summary> | |||||
/// Gets the format type of this sticker. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A <see cref="StickerFormatType"/> with the format type of this sticker. | |||||
/// </returns> | |||||
StickerFormatType FormatType { get; } | |||||
} | |||||
} |
@@ -36,18 +36,6 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task ModifyAsync(Action<MessageProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<MessageProperties> func, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Modifies the suppression of this message. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This method modifies whether or not embeds in this message are suppressed (hidden). | |||||
/// </remarks> | |||||
/// <param name="suppressEmbeds">Whether or not embeds in this message should be suppressed.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous modification operation. | |||||
/// </returns> | |||||
Task ModifySuppressionAsync(bool suppressEmbeds, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Adds this message to its channel's pinned messages. | /// Adds this message to its channel's pinned messages. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="options">The options to be used when sending the request.</param> | /// <param name="options">The options to be used when sending the request.</param> | ||||
@@ -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, | |||||
} | |||||
} |
@@ -26,5 +26,18 @@ namespace Discord | |||||
/// Gets or sets the components for this message. | /// Gets or sets the components for this message. | ||||
/// </summary> | /// </summary> | ||||
public Optional<MessageComponent> Components { get; set; } | public Optional<MessageComponent> Components { 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; } | |||||
} | } | ||||
} | } |
@@ -60,9 +60,6 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// The message is an inline reply. | /// The message is an inline reply. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// Only available in API v8. | |||||
/// </remarks> | |||||
Reply = 19, | Reply = 19, | ||||
/// <summary> | /// <summary> | ||||
/// The message is an Application Command | /// The message is an Application Command | ||||
@@ -0,0 +1,15 @@ | |||||
namespace Discord | |||||
{ | |||||
/// <summary> Defines the types of formats for stickers. </summary> | |||||
public enum StickerFormatType | |||||
{ | |||||
/// <summary> Default value for a sticker format type. </summary> | |||||
None = 0, | |||||
/// <summary> The sticker format type is png. </summary> | |||||
Png = 1, | |||||
/// <summary> The sticker format type is apng. </summary> | |||||
Apng = 2, | |||||
/// <summary> The sticker format type is lottie. </summary> | |||||
Lottie = 3, | |||||
} | |||||
} |
@@ -22,11 +22,6 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
AddReactions = 0x00_00_00_40, | AddReactions = 0x00_00_00_40, | ||||
/// <summary> | /// <summary> | ||||
/// Allows for reading of messages. This flag is obsolete, use <see cref = "ViewChannel" /> instead. | |||||
/// </summary> | |||||
[Obsolete("Use ViewChannel instead.")] | |||||
ReadMessages = ViewChannel, | |||||
/// <summary> | |||||
/// Allows guild members to view a channel, which includes reading messages in text channels. | /// Allows guild members to view a channel, which includes reading messages in text channels. | ||||
/// </summary> | /// </summary> | ||||
ViewChannel = 0x00_00_04_00, | ViewChannel = 0x00_00_04_00, | ||||
@@ -45,9 +45,6 @@ namespace Discord | |||||
/// <summary> If <c>true</c>, a user may add reactions. </summary> | /// <summary> If <c>true</c>, a user may add reactions. </summary> | ||||
public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); | public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); | ||||
/// <summary> If <c>true</c>, a user may join channels. </summary> | |||||
[Obsolete("Use ViewChannel instead.")] | |||||
public bool ReadMessages => ViewChannel; | |||||
/// <summary> If <c>true</c>, a user may view channels. </summary> | /// <summary> If <c>true</c>, a user may view channels. </summary> | ||||
public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); | public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); | ||||
@@ -65,8 +65,6 @@ namespace Discord | |||||
/// Allows for viewing of audit logs. | /// Allows for viewing of audit logs. | ||||
/// </summary> | /// </summary> | ||||
ViewAuditLog = 0x00_00_00_80, | ViewAuditLog = 0x00_00_00_80, | ||||
[Obsolete("Use ViewChannel instead.")] | |||||
ReadMessages = ViewChannel, | |||||
ViewChannel = 0x00_00_04_00, | ViewChannel = 0x00_00_04_00, | ||||
SendMessages = 0x00_00_08_00, | SendMessages = 0x00_00_08_00, | ||||
/// <summary> | /// <summary> | ||||
@@ -37,9 +37,6 @@ namespace Discord | |||||
/// <summary> If <c>true</c>, a user may view the guild insights. </summary> | /// <summary> If <c>true</c>, a user may view the guild insights. </summary> | ||||
public bool ViewGuildInsights => Permissions.GetValue(RawValue, GuildPermission.ViewGuildInsights); | public bool ViewGuildInsights => Permissions.GetValue(RawValue, GuildPermission.ViewGuildInsights); | ||||
/// <summary> If True, a user may join channels. </summary> | |||||
[Obsolete("Use ViewChannel instead.")] | |||||
public bool ReadMessages => ViewChannel; | |||||
/// <summary> If True, a user may view channels. </summary> | /// <summary> If True, a user may view channels. </summary> | ||||
public bool ViewChannel => Permissions.GetValue(RawValue, GuildPermission.ViewChannel); | public bool ViewChannel => Permissions.GetValue(RawValue, GuildPermission.ViewChannel); | ||||
/// <summary> If True, a user may send messages. </summary> | /// <summary> If True, a user may send messages. </summary> | ||||
@@ -90,6 +87,9 @@ namespace Discord | |||||
/// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary> | /// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary> | ||||
public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | ||||
/// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value after converting to ulong. </summary> | |||||
public GuildPermissions(string rawValue) { RawValue = ulong.Parse(rawValue); } | |||||
private GuildPermissions(ulong initialValue, | private GuildPermissions(ulong initialValue, | ||||
bool? createInstantInvite = null, | bool? createInstantInvite = null, | ||||
bool? kickMembers = null, | bool? kickMembers = null, | ||||
@@ -43,9 +43,6 @@ namespace Discord | |||||
/// <summary> If Allowed, a user may add reactions. </summary> | /// <summary> If Allowed, a user may add reactions. </summary> | ||||
public PermValue AddReactions => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.AddReactions); | public PermValue AddReactions => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.AddReactions); | ||||
/// <summary> If Allowed, a user may join channels. </summary> | /// <summary> If Allowed, a user may join channels. </summary> | ||||
[Obsolete("Use ViewChannel instead.")] | |||||
public PermValue ReadMessages => ViewChannel; | |||||
/// <summary> If Allowed, a user may join channels. </summary> | |||||
public PermValue ViewChannel => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ViewChannel); | public PermValue ViewChannel => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ViewChannel); | ||||
/// <summary> If Allowed, a user may send messages. </summary> | /// <summary> If Allowed, a user may send messages. </summary> | ||||
public PermValue SendMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | public PermValue SendMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | ||||
@@ -93,6 +90,13 @@ namespace Discord | |||||
DenyValue = denyValue; | DenyValue = denyValue; | ||||
} | } | ||||
/// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values after converting to ulong. </summary> | |||||
public OverwritePermissions(string allowValue, string denyValue) | |||||
{ | |||||
AllowValue = ulong.Parse(allowValue); | |||||
DenyValue = ulong.Parse(denyValue); | |||||
} | |||||
private OverwritePermissions(ulong allowValue, ulong denyValue, | private OverwritePermissions(ulong allowValue, ulong denyValue, | ||||
PermValue? createInstantInvite = null, | PermValue? createInstantInvite = null, | ||||
PermValue? manageChannel = null, | PermValue? manageChannel = null, | ||||
@@ -65,6 +65,13 @@ namespace Discord | |||||
/// An <see cref="int"/> representing the position of the role in the role list of the guild. | /// An <see cref="int"/> representing the position of the role in the role list of the guild. | ||||
/// </returns> | /// </returns> | ||||
int Position { get; } | 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> | /// <summary> | ||||
/// Modifies this role. | /// Modifies this role. | ||||
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -68,6 +68,11 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
IReadOnlyCollection<ulong> RoleIds { get; } | IReadOnlyCollection<ulong> RoleIds { get; } | ||||
/// <summary> | |||||
/// Whether the user has passed the guild's Membership Screening requirements. | |||||
/// </summary> | |||||
bool? IsPending { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the level permissions granted to this user to a given channel. | /// Gets the level permissions granted to this user to a given channel. | ||||
/// </summary> | /// </summary> | ||||
@@ -108,7 +113,15 @@ namespace Discord | |||||
/// A task that represents the asynchronous modification operation. | /// A task that represents the asynchronous modification operation. | ||||
/// </returns> | /// </returns> | ||||
Task ModifyAsync(Action<GuildUserProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<GuildUserProperties> func, RequestOptions options = null); | ||||
/// <summary> | |||||
/// Adds the specified role to this user in the guild. | |||||
/// </summary> | |||||
/// <param name="roleId">The role to be added to the user.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous role addition operation. | |||||
/// </returns> | |||||
Task AddRoleAsync(ulong roleId, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Adds the specified role to this user in the guild. | /// Adds the specified role to this user in the guild. | ||||
/// </summary> | /// </summary> | ||||
@@ -119,6 +132,15 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task AddRoleAsync(IRole role, RequestOptions options = null); | Task AddRoleAsync(IRole role, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Adds the specified <paramref name="roleIds"/> to this user in the guild. | |||||
/// </summary> | |||||
/// <param name="roleIds">The roles to be added to the user.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous role addition operation. | |||||
/// </returns> | |||||
Task AddRolesAsync(IEnumerable<ulong> roleIds, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Adds the specified <paramref name="roles"/> to this user in the guild. | /// Adds the specified <paramref name="roles"/> to this user in the guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="roles">The roles to be added to the user.</param> | /// <param name="roles">The roles to be added to the user.</param> | ||||
@@ -128,6 +150,15 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null); | Task AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Removes the specified <paramref name="roleId"/> from this user in the guild. | |||||
/// </summary> | |||||
/// <param name="roleId">The role to be removed from the user.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous role removal operation. | |||||
/// </returns> | |||||
Task RemoveRoleAsync(ulong roleId, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Removes the specified <paramref name="role"/> from this user in the guild. | /// Removes the specified <paramref name="role"/> from this user in the guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="role">The role to be removed from the user.</param> | /// <param name="role">The role to be removed from the user.</param> | ||||
@@ -137,6 +168,15 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task RemoveRoleAsync(IRole role, RequestOptions options = null); | Task RemoveRoleAsync(IRole role, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Removes the specified <paramref name="roleIds"/> from this user in the guild. | |||||
/// </summary> | |||||
/// <param name="roleIds">The roles to be removed from the user.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous role removal operation. | |||||
/// </returns> | |||||
Task RemoveRolesAsync(IEnumerable<ulong> roleIds, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Removes the specified <paramref name="roles"/> from this user in the guild. | /// Removes the specified <paramref name="roles"/> from this user in the guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="roles">The roles to be removed from the user.</param> | /// <param name="roles">The roles to be removed from the user.</param> | ||||
@@ -7,10 +7,6 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public interface IPresence | public interface IPresence | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the activity this user is currently doing. | |||||
/// </summary> | |||||
IActivity Activity { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the current status of this user. | /// Gets the current status of this user. | ||||
/// </summary> | /// </summary> | ||||
@@ -75,9 +75,19 @@ namespace Discord | |||||
/// Gets the username for this user. | /// Gets the username for this user. | ||||
/// </summary> | /// </summary> | ||||
string Username { get; } | 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> | /// <summary> | ||||
/// Gets the direct message channel of this user, or create one if it does not already exist. | |||||
/// Creates the direct message channel of this user. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// This method is used to obtain or create a channel used to send a direct message. | /// This method is used to obtain or create a channel used to send a direct message. | ||||
@@ -92,7 +102,7 @@ namespace Discord | |||||
/// <example> | /// <example> | ||||
/// <para>The following example attempts to send a direct message to the target user and logs the incident should | /// <para>The following example attempts to send a direct message to the target user and logs the incident should | ||||
/// it fail.</para> | /// it fail.</para> | ||||
/// <code region="GetOrCreateDMChannelAsync" language="cs" | |||||
/// <code region="CreateDMChannelAsync" language="cs" | |||||
/// source="../../../Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs"/> | /// source="../../../Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs"/> | ||||
/// </example> | /// </example> | ||||
/// <param name="options">The options to be used when sending the request.</param> | /// <param name="options">The options to be used when sending the request.</param> | ||||
@@ -100,6 +110,6 @@ namespace Discord | |||||
/// A task that represents the asynchronous operation for getting or creating a DM channel. The task result | /// A task that represents the asynchronous operation for getting or creating a DM channel. The task result | ||||
/// contains the DM channel associated with this user. | /// contains the DM channel associated with this user. | ||||
/// </returns> | /// </returns> | ||||
Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null); | |||||
Task<IDMChannel> CreateDMChannelAsync(RequestOptions options = null); | |||||
} | } | ||||
} | } |
@@ -10,32 +10,60 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
None = 0, | None = 0, | ||||
/// <summary> | /// <summary> | ||||
/// Flag given to Discord staff. | |||||
/// Flag given to users who are a Discord employee. | |||||
/// </summary> | /// </summary> | ||||
Staff = 0b1, | |||||
Staff = 1 << 0, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to Discord partners. | |||||
/// Flag given to users who are owners of a partnered Discord server. | |||||
/// </summary> | /// </summary> | ||||
Partner = 0b10, | |||||
Partner = 1 << 1, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to users who have participated in the bug report program. | |||||
/// Flag given to users in HypeSquad events. | |||||
/// </summary> | /// </summary> | ||||
BugHunter = 0b1000, | |||||
HypeSquadEvents = 1 << 2, | |||||
/// <summary> | |||||
/// Flag given to users who have participated in the bug report program and are level 1. | |||||
/// </summary> | |||||
BugHunterLevel1 = 1 << 3, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to users who are in the HypeSquad House of Bravery. | /// Flag given to users who are in the HypeSquad House of Bravery. | ||||
/// </summary> | /// </summary> | ||||
HypeSquadBravery = 0b100_0000, | |||||
HypeSquadBravery = 1 << 6, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to users who are in the HypeSquad House of Brilliance. | /// Flag given to users who are in the HypeSquad House of Brilliance. | ||||
/// </summary> | /// </summary> | ||||
HypeSquadBrilliance = 0b1000_0000, | |||||
HypeSquadBrilliance = 1 << 7, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to users who are in the HypeSquad House of Balance. | /// Flag given to users who are in the HypeSquad House of Balance. | ||||
/// </summary> | /// </summary> | ||||
HypeSquadBalance = 0b1_0000_0000, | |||||
HypeSquadBalance = 1 << 8, | |||||
/// <summary> | /// <summary> | ||||
/// Flag given to users who subscribed to Nitro before games were added. | /// Flag given to users who subscribed to Nitro before games were added. | ||||
/// </summary> | /// </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, | |||||
/// <summary> | |||||
/// Flag given to users that are discord certified moderators who has give discord's exam. | |||||
/// </summary> | |||||
DiscordCertifiedModerator = 1 << 18, | |||||
} | } | ||||
} | } |
@@ -1,10 +0,0 @@ | |||||
using System; | |||||
namespace Discord | |||||
{ | |||||
internal static class StringExtensions | |||||
{ | |||||
public static bool IsNullOrUri(this string url) => | |||||
string.IsNullOrEmpty(url) || Uri.IsWellFormedUriString(url, UriKind.Absolute); | |||||
} | |||||
} |
@@ -43,7 +43,7 @@ namespace Discord | |||||
AllowedMentions allowedMentions = null, | AllowedMentions allowedMentions = null, | ||||
MessageComponent component = null) | MessageComponent component = null) | ||||
{ | { | ||||
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options, allowedMentions, component: component).ConfigureAwait(false); | |||||
return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options, allowedMentions, component: component).ConfigureAwait(false); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -95,7 +95,7 @@ namespace Discord | |||||
RequestOptions options = null, | RequestOptions options = null, | ||||
MessageComponent component = null) | MessageComponent component = null) | ||||
{ | { | ||||
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(stream, filename, text, isTTS, embed, options, component: component).ConfigureAwait(false); | |||||
return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(stream, filename, text, isTTS, embed, options, component: component).ConfigureAwait(false); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -151,7 +151,7 @@ namespace Discord | |||||
RequestOptions options = null, | RequestOptions options = null, | ||||
MessageComponent component = null) | MessageComponent component = null) | ||||
{ | { | ||||
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options, component: component).ConfigureAwait(false); | |||||
return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options, component: component).ConfigureAwait(false); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -39,5 +39,16 @@ namespace Discord | |||||
DirectMessageReactions = 1 << 13, | DirectMessageReactions = 1 << 13, | ||||
/// <summary> This intent includes TYPING_START </summary> | /// <summary> This intent includes TYPING_START </summary> | ||||
DirectMessageTyping = 1 << 14, | DirectMessageTyping = 1 << 14, | ||||
/// <summary> | |||||
/// This intent includes all but <see cref="GuildMembers"/> and <see cref="GuildMembers"/> | |||||
/// that are privileged must be enabled for the application. | |||||
/// </summary> | |||||
AllUnprivileged = Guilds | GuildBans | GuildEmojis | GuildIntegrations | GuildWebhooks | GuildInvites | | |||||
GuildVoiceStates | GuildMessages | GuildMessageReactions | GuildMessageTyping | DirectMessages | | |||||
DirectMessageReactions | DirectMessageTyping, | |||||
/// <summary> | |||||
/// This intent includes all of them, including privileged ones. | |||||
/// </summary> | |||||
All = AllUnprivileged | GuildMembers | GuildPresences | |||||
} | } | ||||
} | } |
@@ -1,18 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Specifies the level of precision to request in the rate limit | |||||
/// response header. | |||||
/// </summary> | |||||
public enum RateLimitPrecision | |||||
{ | |||||
/// <summary> | |||||
/// Specifies precision rounded up to the nearest whole second | |||||
/// </summary> | |||||
Second, | |||||
/// <summary> | |||||
/// Specifies precision rounded to the nearest millisecond. | |||||
/// </summary> | |||||
Millisecond | |||||
} | |||||
} |
@@ -5,8 +5,6 @@ namespace Discord | |||||
/// <summary> Specifies the type of token to use with the client. </summary> | /// <summary> Specifies the type of token to use with the client. </summary> | ||||
public enum TokenType | public enum TokenType | ||||
{ | { | ||||
[Obsolete("User logins are deprecated and may result in a ToS strike against your account - please see https://github.com/RogueException/Discord.Net/issues/827", error: true)] | |||||
User, | |||||
/// <summary> | /// <summary> | ||||
/// An OAuth2 token type. | /// An OAuth2 token type. | ||||
/// </summary> | /// </summary> | ||||
@@ -12,7 +12,7 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
/// <param name="value">The snowflake identifier to resolve.</param> | /// <param name="value">The snowflake identifier to resolve.</param> | ||||
/// <returns> | /// <returns> | ||||
/// A <see cref="DateTimeOffset" /> representing the time for when the object is geenrated. | |||||
/// A <see cref="DateTimeOffset" /> representing the time for when the object is generated. | |||||
/// </returns> | /// </returns> | ||||
public static DateTimeOffset FromSnowflake(ulong value) | public static DateTimeOffset FromSnowflake(ulong value) | ||||
=> DateTimeOffset.FromUnixTimeMilliseconds((long)((value >> 22) + 1420070400000UL)); | => DateTimeOffset.FromUnixTimeMilliseconds((long)((value >> 22) + 1420070400000UL)); | ||||
@@ -18,11 +18,11 @@ namespace Discord.Net.Examples.Core.Entities.Users | |||||
#endregion | #endregion | ||||
#region GetOrCreateDMChannelAsync | |||||
#region CreateDMChannelAsync | |||||
public async Task MessageUserAsync(IUser user) | public async Task MessageUserAsync(IUser user) | ||||
{ | { | ||||
var channel = await user.GetOrCreateDMChannelAsync(); | |||||
var channel = await user.CreateDMChannelAsync(); | |||||
try | try | ||||
{ | { | ||||
await channel.SendMessageAsync("Awesome stuff!"); | await channel.SendMessageAsync("Awesome stuff!"); | ||||
@@ -15,7 +15,7 @@ namespace Discord.Net.Examples.WebSocket | |||||
=> client.ReactionAdded += HandleReactionAddedAsync; | => client.ReactionAdded += HandleReactionAddedAsync; | ||||
public async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> cachedMessage, | public async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> cachedMessage, | ||||
ISocketMessageChannel originChannel, SocketReaction reaction) | |||||
Cacheable<IMessageChannel, ulong> originChannel, SocketReaction reaction) | |||||
{ | { | ||||
var message = await cachedMessage.GetOrDownloadAsync(); | var message = await cachedMessage.GetOrDownloadAsync(); | ||||
if (message != null && reaction.User.IsSpecified) | if (message != null && reaction.User.IsSpecified) | ||||
@@ -100,16 +100,17 @@ namespace Discord.Net.Examples.WebSocket | |||||
public void HookMessageDeleted(BaseSocketClient client) | public void HookMessageDeleted(BaseSocketClient client) | ||||
=> client.MessageDeleted += HandleMessageDelete; | => client.MessageDeleted += HandleMessageDelete; | ||||
public Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, ISocketMessageChannel channel) | |||||
public async Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, Cacheable<IMessageChannel, ulong> cachedChannel) | |||||
{ | { | ||||
// check if the message exists in cache; if not, we cannot report what was removed | // check if the message exists in cache; if not, we cannot report what was removed | ||||
if (!cachedMessage.HasValue) return Task.CompletedTask; | |||||
if (!cachedMessage.HasValue) return; | |||||
// gets or downloads the channel if it's not in the cache | |||||
IMessageChannel channel = await cachedChannel.GetOrDownloadAsync(); | |||||
var message = cachedMessage.Value; | var message = cachedMessage.Value; | ||||
Console.WriteLine( | Console.WriteLine( | ||||
$"A message ({message.Id}) from {message.Author} was removed from the channel {channel.Name} ({channel.Id}):" | $"A message ({message.Id}) from {message.Author} was removed from the channel {channel.Name} ({channel.Id}):" | ||||
+ Environment.NewLine | + Environment.NewLine | ||||
+ message.Content); | + message.Content); | ||||
return Task.CompletedTask; | |||||
} | } | ||||
#endregion | #endregion | ||||
@@ -2,7 +2,7 @@ using Newtonsoft.Json; | |||||
namespace Discord.API | namespace Discord.API | ||||
{ | { | ||||
public class AllowedMentions | |||||
internal class AllowedMentions | |||||
{ | { | ||||
[JsonProperty("parse")] | [JsonProperty("parse")] | ||||
public Optional<string[]> Parse { get; set; } | public Optional<string[]> Parse { get; set; } |
@@ -7,7 +7,7 @@ namespace Discord.API | |||||
[JsonProperty("target_id")] | [JsonProperty("target_id")] | ||||
public ulong? TargetId { get; set; } | public ulong? TargetId { get; set; } | ||||
[JsonProperty("user_id")] | [JsonProperty("user_id")] | ||||
public ulong UserId { get; set; } | |||||
public ulong? UserId { get; set; } | |||||
[JsonProperty("changes")] | [JsonProperty("changes")] | ||||
public AuditLogChange[] Changes { get; set; } | public AuditLogChange[] Changes { get; set; } | ||||
@@ -23,10 +23,6 @@ namespace Discord.API | |||||
public ulong? AFKChannelId { get; set; } | public ulong? AFKChannelId { get; set; } | ||||
[JsonProperty("afk_timeout")] | [JsonProperty("afk_timeout")] | ||||
public int AFKTimeout { get; set; } | public int AFKTimeout { get; set; } | ||||
[JsonProperty("embed_enabled")] | |||||
public Optional<bool> EmbedEnabled { get; set; } | |||||
[JsonProperty("embed_channel_id")] | |||||
public Optional<ulong?> EmbedChannelId { get; set; } | |||||
[JsonProperty("verification_level")] | [JsonProperty("verification_level")] | ||||
public VerificationLevel VerificationLevel { get; set; } | public VerificationLevel VerificationLevel { get; set; } | ||||
[JsonProperty("default_message_notifications")] | [JsonProperty("default_message_notifications")] | ||||
@@ -1,13 +0,0 @@ | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
internal class GuildEmbed | |||||
{ | |||||
[JsonProperty("enabled")] | |||||
public bool Enabled { get; set; } | |||||
[JsonProperty("channel_id")] | |||||
public ulong? ChannelId { get; set; } | |||||
} | |||||
} |
@@ -18,6 +18,8 @@ namespace Discord.API | |||||
public Optional<bool> Deaf { get; set; } | public Optional<bool> Deaf { get; set; } | ||||
[JsonProperty("mute")] | [JsonProperty("mute")] | ||||
public Optional<bool> Mute { get; set; } | public Optional<bool> Mute { get; set; } | ||||
[JsonProperty("pending")] | |||||
public Optional<bool> Pending { get; set; } | |||||
[JsonProperty("premium_since")] | [JsonProperty("premium_since")] | ||||
public Optional<DateTimeOffset?> PremiumSince { get; set; } | public Optional<DateTimeOffset?> PremiumSince { get; set; } | ||||
} | } | ||||
@@ -11,9 +11,15 @@ namespace Discord.API | |||||
public Optional<InviteGuild> Guild { get; set; } | public Optional<InviteGuild> Guild { get; set; } | ||||
[JsonProperty("channel")] | [JsonProperty("channel")] | ||||
public InviteChannel Channel { get; set; } | public InviteChannel Channel { get; set; } | ||||
[JsonProperty("inviter")] | |||||
public Optional<User> Inviter { get; set; } | |||||
[JsonProperty("approximate_presence_count")] | [JsonProperty("approximate_presence_count")] | ||||
public Optional<int?> PresenceCount { get; set; } | public Optional<int?> PresenceCount { get; set; } | ||||
[JsonProperty("approximate_member_count")] | [JsonProperty("approximate_member_count")] | ||||
public Optional<int?> MemberCount { get; set; } | public Optional<int?> MemberCount { get; set; } | ||||
[JsonProperty("target_user")] | |||||
public Optional<User> TargetUser { get; set; } | |||||
[JsonProperty("target_user_type")] | |||||
public Optional<TargetUserType> TargetUserType { get; set; } | |||||
} | } | ||||
} | } |
@@ -6,19 +6,15 @@ namespace Discord.API | |||||
{ | { | ||||
internal class InviteMetadata : Invite | internal class InviteMetadata : Invite | ||||
{ | { | ||||
[JsonProperty("inviter")] | |||||
public User Inviter { get; set; } | |||||
[JsonProperty("uses")] | [JsonProperty("uses")] | ||||
public Optional<int> Uses { get; set; } | |||||
public int Uses { get; set; } | |||||
[JsonProperty("max_uses")] | [JsonProperty("max_uses")] | ||||
public Optional<int> MaxUses { get; set; } | |||||
public int MaxUses { get; set; } | |||||
[JsonProperty("max_age")] | [JsonProperty("max_age")] | ||||
public Optional<int> MaxAge { get; set; } | |||||
public int MaxAge { get; set; } | |||||
[JsonProperty("temporary")] | [JsonProperty("temporary")] | ||||
public bool Temporary { get; set; } | public bool Temporary { get; set; } | ||||
[JsonProperty("created_at")] | [JsonProperty("created_at")] | ||||
public Optional<DateTimeOffset> CreatedAt { get; set; } | |||||
[JsonProperty("revoked")] | |||||
public bool Revoked { get; set; } | |||||
public DateTimeOffset CreatedAt { get; set; } | |||||
} | } | ||||
} | } |
@@ -6,5 +6,7 @@ namespace Discord.API | |||||
{ | { | ||||
[JsonProperty("code")] | [JsonProperty("code")] | ||||
public string Code { get; set; } | public string Code { get; set; } | ||||
[JsonProperty("uses")] | |||||
public int Uses { get; set; } | |||||
} | } | ||||
} | } |
@@ -60,5 +60,7 @@ namespace Discord.API | |||||
public Optional<Message> ReferencedMessage { get; set; } | public Optional<Message> ReferencedMessage { get; set; } | ||||
[JsonProperty("components")] | [JsonProperty("components")] | ||||
public Optional<API.ActionRowComponent[]> Components { get; set; } | public Optional<API.ActionRowComponent[]> Components { get; set; } | ||||
[JsonProperty("stickers")] | |||||
public Optional<Sticker[]> Stickers { get; set; } | |||||
} | } | ||||
} | } |
@@ -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, | |||||
} | |||||
} |
@@ -10,8 +10,8 @@ namespace Discord.API | |||||
[JsonProperty("type")] | [JsonProperty("type")] | ||||
public PermissionTarget TargetType { get; set; } | public PermissionTarget TargetType { get; set; } | ||||
[JsonProperty("deny"), Int53] | [JsonProperty("deny"), Int53] | ||||
public ulong Deny { get; set; } | |||||
public string Deny { get; set; } | |||||
[JsonProperty("allow"), Int53] | [JsonProperty("allow"), Int53] | ||||
public ulong Allow { get; set; } | |||||
public string Allow { get; set; } | |||||
} | } | ||||
} | } |
@@ -13,8 +13,6 @@ namespace Discord.API | |||||
public Optional<ulong> GuildId { get; set; } | public Optional<ulong> GuildId { get; set; } | ||||
[JsonProperty("status")] | [JsonProperty("status")] | ||||
public UserStatus Status { get; set; } | public UserStatus Status { get; set; } | ||||
[JsonProperty("game")] | |||||
public Game Game { get; set; } | |||||
[JsonProperty("roles")] | [JsonProperty("roles")] | ||||
public Optional<ulong[]> Roles { get; set; } | public Optional<ulong[]> Roles { get; set; } | ||||
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API | namespace Discord.API | ||||
@@ -18,8 +18,10 @@ namespace Discord.API | |||||
[JsonProperty("position")] | [JsonProperty("position")] | ||||
public int Position { get; set; } | public int Position { get; set; } | ||||
[JsonProperty("permissions"), Int53] | [JsonProperty("permissions"), Int53] | ||||
public ulong Permissions { get; set; } | |||||
public string Permissions { get; set; } | |||||
[JsonProperty("managed")] | [JsonProperty("managed")] | ||||
public bool Managed { get; set; } | public bool Managed { get; set; } | ||||
[JsonProperty("tags")] | |||||
public Optional<RoleTags> Tags { get; set; } | |||||
} | } | ||||
} | } |
@@ -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; } | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
internal class Sticker | |||||
{ | |||||
[JsonProperty("id")] | |||||
public ulong Id { get; set; } | |||||
[JsonProperty("pack_id")] | |||||
public ulong PackId { get; set; } | |||||
[JsonProperty("name")] | |||||
public string Name { get; set; } | |||||
[JsonProperty("description")] | |||||
public string Desription { get; set; } | |||||
[JsonProperty("tags")] | |||||
public Optional<string> Tags { get; set; } | |||||
[JsonProperty("asset")] | |||||
public string Asset { get; set; } | |||||
[JsonProperty("preview_asset")] | |||||
public string PreviewAsset { get; set; } | |||||
[JsonProperty("format_type")] | |||||
public StickerFormatType FormatType { get; set; } | |||||
} | |||||
} |
@@ -29,5 +29,7 @@ namespace Discord.API | |||||
public Optional<PremiumType> PremiumType { get; set; } | public Optional<PremiumType> PremiumType { get; set; } | ||||
[JsonProperty("locale")] | [JsonProperty("locale")] | ||||
public Optional<string> Locale { get; set; } | public Optional<string> Locale { get; set; } | ||||
[JsonProperty("public_flags")] | |||||
public Optional<UserProperties> PublicFlags { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API | namespace Discord.API | ||||
@@ -14,6 +14,6 @@ namespace Discord.API | |||||
[JsonProperty("owner")] | [JsonProperty("owner")] | ||||
public bool Owner { get; set; } | public bool Owner { get; set; } | ||||
[JsonProperty("permissions"), Int53] | [JsonProperty("permissions"), Int53] | ||||
public ulong Permissions { get; set; } | |||||
public string Permissions { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
@@ -7,13 +7,13 @@ namespace Discord.API.Rest | |||||
internal class ModifyChannelPermissionsParams | internal class ModifyChannelPermissionsParams | ||||
{ | { | ||||
[JsonProperty("type")] | [JsonProperty("type")] | ||||
public string Type { get; } | |||||
public int Type { get; } | |||||
[JsonProperty("allow")] | [JsonProperty("allow")] | ||||
public ulong Allow { get; } | |||||
public string Allow { get; } | |||||
[JsonProperty("deny")] | [JsonProperty("deny")] | ||||
public ulong Deny { get; } | |||||
public string Deny { get; } | |||||
public ModifyChannelPermissionsParams(string type, ulong allow, ulong deny) | |||||
public ModifyChannelPermissionsParams(int type, string allow, string deny) | |||||
{ | { | ||||
Type = type; | Type = type; | ||||
Allow = allow; | Allow = allow; | ||||
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
@@ -9,7 +9,7 @@ namespace Discord.API.Rest | |||||
[JsonProperty("name")] | [JsonProperty("name")] | ||||
public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
[JsonProperty("permissions")] | [JsonProperty("permissions")] | ||||
public Optional<ulong> Permissions { get; set; } | |||||
public Optional<string> Permissions { get; set; } | |||||
[JsonProperty("color")] | [JsonProperty("color")] | ||||
public Optional<uint> Color { get; set; } | public Optional<uint> Color { get; set; } | ||||
[JsonProperty("hoist")] | [JsonProperty("hoist")] | ||||
@@ -12,5 +12,9 @@ namespace Discord.API.Rest | |||||
public Optional<Embed> Embed { get; set; } | public Optional<Embed> Embed { get; set; } | ||||
[JsonProperty("components")] | [JsonProperty("components")] | ||||
public Optional<API.ActionRowComponent[]> Components { get; set; } | public Optional<API.ActionRowComponent[]> Components { get; set; } | ||||
[JsonProperty("flags")] | |||||
public Optional<MessageFlags?> Flags { get; set; } | |||||
[JsonProperty("allowed_mentions")] | |||||
public Optional<AllowedMentions> AllowedMentions { get; set; } | |||||
} | } | ||||
} | } |
@@ -0,0 +1,16 @@ | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Rest | |||||
{ | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
internal class ModifyWebhookMessageParams | |||||
{ | |||||
[JsonProperty("content")] | |||||
public Optional<string> Content { get; set; } | |||||
[JsonProperty("embeds")] | |||||
public Optional<Embed[]> Embeds { get; set; } | |||||
[JsonProperty("allowed_mentions")] | |||||
public Optional<AllowedMentions> AllowedMentions { get; set; } | |||||
} | |||||
} |
@@ -1,11 +0,0 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API.Rest | |||||
{ | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
internal class SuppressEmbedParams | |||||
{ | |||||
[JsonProperty("suppress")] | |||||
public bool Suppressed { get; set; } | |||||
} | |||||
} |
@@ -52,6 +52,8 @@ namespace Discord.API.Rest | |||||
payload["components"] = MessageComponent.Value; | payload["components"] = MessageComponent.Value; | ||||
if (IsSpoiler) | if (IsSpoiler) | ||||
payload["hasSpoiler"] = IsSpoiler.ToString(); | payload["hasSpoiler"] = IsSpoiler.ToString(); | ||||
if (MessageReference.IsSpecified) | |||||
payload["message_reference"] = MessageReference.Value; | |||||
var json = new StringBuilder(); | var json = new StringBuilder(); | ||||
using (var text = new StringWriter(json)) | using (var text = new StringWriter(json)) | ||||
@@ -17,7 +17,7 @@ namespace Discord.Rest | |||||
return RestApplication.Create(client, model); | return RestApplication.Create(client, model); | ||||
} | } | ||||
public static async Task<RestChannel> GetChannelAsync(BaseDiscordClient client, | |||||
public static async Task<RestChannel> GetChannelAsync(BaseDiscordClient client, | |||||
ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
{ | { | ||||
var model = await client.ApiClient.GetChannelAsync(id, options).ConfigureAwait(false); | var model = await client.ApiClient.GetChannelAsync(id, options).ConfigureAwait(false); | ||||
@@ -45,13 +45,13 @@ namespace Discord.Rest | |||||
.Where(x => x.Type == ChannelType.Group) | .Where(x => x.Type == ChannelType.Group) | ||||
.Select(x => RestGroupChannel.Create(client, x)).ToImmutableArray(); | .Select(x => RestGroupChannel.Create(client, x)).ToImmutableArray(); | ||||
} | } | ||||
public static async Task<IReadOnlyCollection<RestConnection>> GetConnectionsAsync(BaseDiscordClient client, RequestOptions options) | public static async Task<IReadOnlyCollection<RestConnection>> GetConnectionsAsync(BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
var models = await client.ApiClient.GetMyConnectionsAsync(options).ConfigureAwait(false); | var models = await client.ApiClient.GetMyConnectionsAsync(options).ConfigureAwait(false); | ||||
return models.Select(RestConnection.Create).ToImmutableArray(); | return models.Select(RestConnection.Create).ToImmutableArray(); | ||||
} | } | ||||
public static async Task<RestInviteMetadata> GetInviteAsync(BaseDiscordClient client, | public static async Task<RestInviteMetadata> GetInviteAsync(BaseDiscordClient client, | ||||
string inviteId, RequestOptions options) | string inviteId, RequestOptions options) | ||||
{ | { | ||||
@@ -60,7 +60,7 @@ namespace Discord.Rest | |||||
return RestInviteMetadata.Create(client, null, null, model); | return RestInviteMetadata.Create(client, null, null, model); | ||||
return null; | return null; | ||||
} | } | ||||
public static async Task<RestGuild> GetGuildAsync(BaseDiscordClient client, | public static async Task<RestGuild> GetGuildAsync(BaseDiscordClient client, | ||||
ulong id, bool withCounts, RequestOptions options) | ulong id, bool withCounts, RequestOptions options) | ||||
{ | { | ||||
@@ -69,14 +69,6 @@ namespace Discord.Rest | |||||
return RestGuild.Create(client, model); | return RestGuild.Create(client, model); | ||||
return null; | return null; | ||||
} | } | ||||
public static async Task<RestGuildEmbed?> GetGuildEmbedAsync(BaseDiscordClient client, | |||||
ulong id, RequestOptions options) | |||||
{ | |||||
var model = await client.ApiClient.GetGuildEmbedAsync(id, options).ConfigureAwait(false); | |||||
if (model != null) | |||||
return RestGuildEmbed.Create(model); | |||||
return null; | |||||
} | |||||
public static async Task<RestGuildWidget?> GetGuildWidgetAsync(BaseDiscordClient client, | public static async Task<RestGuildWidget?> GetGuildWidgetAsync(BaseDiscordClient client, | ||||
ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
{ | { | ||||
@@ -85,7 +77,7 @@ namespace Discord.Rest | |||||
return RestGuildWidget.Create(model); | return RestGuildWidget.Create(model); | ||||
return null; | return null; | ||||
} | } | ||||
public static IAsyncEnumerable<IReadOnlyCollection<RestUserGuild>> GetGuildSummariesAsync(BaseDiscordClient client, | |||||
public static IAsyncEnumerable<IReadOnlyCollection<RestUserGuild>> GetGuildSummariesAsync(BaseDiscordClient client, | |||||
ulong? fromGuildId, int? limit, RequestOptions options) | ulong? fromGuildId, int? limit, RequestOptions options) | ||||
{ | { | ||||
return new PagedAsyncEnumerable<RestUserGuild>( | return new PagedAsyncEnumerable<RestUserGuild>( | ||||
@@ -136,7 +128,7 @@ namespace Discord.Rest | |||||
var model = await client.ApiClient.CreateGuildAsync(args, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateGuildAsync(args, options).ConfigureAwait(false); | ||||
return RestGuild.Create(client, model); | return RestGuild.Create(client, model); | ||||
} | } | ||||
public static async Task<RestUser> GetUserAsync(BaseDiscordClient client, | public static async Task<RestUser> GetUserAsync(BaseDiscordClient client, | ||||
ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
{ | { | ||||
@@ -221,5 +213,11 @@ namespace Discord.Rest | |||||
return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); | return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); | ||||
} | } | ||||
public static Task AddRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) | |||||
=> client.ApiClient.AddRoleAsync(guildId, userId, roleId, options); | |||||
public static Task RemoveRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) | |||||
=> client.ApiClient.RemoveRoleAsync(guildId, userId, roleId, options); | |||||
} | } | ||||
} | } |
@@ -45,19 +45,17 @@ namespace Discord.API | |||||
internal string AuthToken { get; private set; } | internal string AuthToken { get; private set; } | ||||
internal IRestClient RestClient { get; private set; } | internal IRestClient RestClient { get; private set; } | ||||
internal ulong? CurrentUserId { get; set; } | internal ulong? CurrentUserId { get; set; } | ||||
public RateLimitPrecision RateLimitPrecision { get; private set; } | |||||
internal bool UseSystemClock { get; set; } | internal bool UseSystemClock { get; set; } | ||||
internal JsonSerializer Serializer => _serializer; | internal JsonSerializer Serializer => _serializer; | ||||
/// <exception cref="ArgumentException">Unknown OAuth token type.</exception> | /// <exception cref="ArgumentException">Unknown OAuth token type.</exception> | ||||
public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, | public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry, | ||||
JsonSerializer serializer = null, RateLimitPrecision rateLimitPrecision = RateLimitPrecision.Second, bool useSystemClock = true) | |||||
JsonSerializer serializer = null, bool useSystemClock = true) | |||||
{ | { | ||||
_restClientProvider = restClientProvider; | _restClientProvider = restClientProvider; | ||||
UserAgent = userAgent; | UserAgent = userAgent; | ||||
DefaultRetryMode = defaultRetryMode; | DefaultRetryMode = defaultRetryMode; | ||||
_serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() }; | _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() }; | ||||
RateLimitPrecision = rateLimitPrecision; | |||||
UseSystemClock = useSystemClock; | UseSystemClock = useSystemClock; | ||||
RequestQueue = new RequestQueue(); | RequestQueue = new RequestQueue(); | ||||
@@ -74,14 +72,12 @@ namespace Discord.API | |||||
RestClient.SetHeader("accept", "*/*"); | RestClient.SetHeader("accept", "*/*"); | ||||
RestClient.SetHeader("user-agent", UserAgent); | RestClient.SetHeader("user-agent", UserAgent); | ||||
RestClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, AuthToken)); | RestClient.SetHeader("authorization", GetPrefixedToken(AuthTokenType, AuthToken)); | ||||
RestClient.SetHeader("X-RateLimit-Precision", RateLimitPrecision.ToString().ToLower()); | |||||
} | } | ||||
/// <exception cref="ArgumentException">Unknown OAuth token type.</exception> | /// <exception cref="ArgumentException">Unknown OAuth token type.</exception> | ||||
internal static string GetPrefixedToken(TokenType tokenType, string token) | internal static string GetPrefixedToken(TokenType tokenType, string token) | ||||
{ | { | ||||
return tokenType switch | return tokenType switch | ||||
{ | { | ||||
default(TokenType) => token, | |||||
TokenType.Bot => $"Bot {token}", | TokenType.Bot => $"Bot {token}", | ||||
TokenType.Bearer => $"Bearer {token}", | TokenType.Bearer => $"Bearer {token}", | ||||
_ => throw new ArgumentException(message: "Unknown OAuth token type.", paramName: nameof(tokenType)), | _ => throw new ArgumentException(message: "Unknown OAuth token type.", paramName: nameof(tokenType)), | ||||
@@ -522,6 +518,43 @@ namespace Discord.API | |||||
var ids = new BucketIds(webhookId: webhookId); | var ids = new BucketIds(webhookId: webhookId); | ||||
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | ||||
} | } | ||||
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||||
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||||
public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null) | |||||
{ | |||||
if (AuthTokenType != TokenType.Webhook) | |||||
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||||
Preconditions.NotNull(args, nameof(args)); | |||||
Preconditions.NotEqual(webhookId, 0, nameof(webhookId)); | |||||
Preconditions.NotEqual(messageId, 0, nameof(messageId)); | |||||
if (args.Embeds.IsSpecified) | |||||
Preconditions.AtMost(args.Embeds.Value.Length, 10, nameof(args.Embeds), "A max of 10 Embeds are allowed."); | |||||
if (args.Content.IsSpecified && args.Content.Value.Length > DiscordConfig.MaxMessageSize) | |||||
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(webhookId: webhookId); | |||||
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||||
} | |||||
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||||
public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null) | |||||
{ | |||||
if (AuthTokenType != TokenType.Webhook) | |||||
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||||
Preconditions.NotEqual(webhookId, 0, nameof(webhookId)); | |||||
Preconditions.NotEqual(messageId, 0, nameof(messageId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(webhookId: webhookId); | |||||
await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", ids, options: options).ConfigureAwait(false); | |||||
} | |||||
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | ||||
public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null) | public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null) | ||||
{ | { | ||||
@@ -607,16 +640,6 @@ namespace Discord.API | |||||
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | ||||
} | } | ||||
public async Task SuppressEmbedAsync(ulong channelId, ulong messageId, Rest.SuppressEmbedParams args, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||||
Preconditions.NotEqual(messageId, 0, nameof(messageId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(channelId: channelId); | |||||
await SendJsonAsync("POST", () => $"channels/{channelId}/messages/{messageId}/suppress-embeds", args, ids, options: options).ConfigureAwait(false); | |||||
} | |||||
public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) | public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) | ||||
{ | { | ||||
Preconditions.NotEqual(channelId, 0, nameof(channelId)); | Preconditions.NotEqual(channelId, 0, nameof(channelId)); | ||||
@@ -1170,7 +1193,7 @@ namespace Discord.API | |||||
var ids = new BucketIds(guildId: guildId); | var ids = new BucketIds(guildId: guildId); | ||||
string reason = string.IsNullOrWhiteSpace(args.Reason) ? "" : $"&reason={Uri.EscapeDataString(args.Reason)}"; | string reason = string.IsNullOrWhiteSpace(args.Reason) ? "" : $"&reason={Uri.EscapeDataString(args.Reason)}"; | ||||
await SendAsync("PUT", () => $"guilds/{guildId}/bans/{userId}?delete-message-days={args.DeleteMessageDays}{reason}", ids, options: options).ConfigureAwait(false); | |||||
await SendAsync("PUT", () => $"guilds/{guildId}/bans/{userId}?delete_message_days={args.DeleteMessageDays}{reason}", ids, options: options).ConfigureAwait(false); | |||||
} | } | ||||
/// <exception cref="ArgumentException"><paramref name="guildId"/> and <paramref name="userId"/> must not be equal to zero.</exception> | /// <exception cref="ArgumentException"><paramref name="guildId"/> and <paramref name="userId"/> must not be equal to zero.</exception> | ||||
public async Task RemoveGuildBanAsync(ulong guildId, ulong userId, RequestOptions options = null) | public async Task RemoveGuildBanAsync(ulong guildId, ulong userId, RequestOptions options = null) | ||||
@@ -1183,32 +1206,6 @@ namespace Discord.API | |||||
await SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); | await SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); | ||||
} | } | ||||
//Guild Embeds | |||||
/// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> | |||||
public async Task<GuildEmbed> GetGuildEmbedAsync(ulong guildId, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
try | |||||
{ | |||||
var ids = new BucketIds(guildId: guildId); | |||||
return await SendAsync<GuildEmbed>("GET", () => $"guilds/{guildId}/embed", ids, options: options).ConfigureAwait(false); | |||||
} | |||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } | |||||
} | |||||
/// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="args"/> must not be <see langword="null"/>.</exception> | |||||
public async Task<GuildEmbed> ModifyGuildEmbedAsync(ulong guildId, Rest.ModifyGuildEmbedParams args, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotNull(args, nameof(args)); | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(guildId: guildId); | |||||
return await SendJsonAsync<GuildEmbed>("PATCH", () => $"guilds/{guildId}/embed", args, ids, options: options).ConfigureAwait(false); | |||||
} | |||||
//Guild Widget | //Guild Widget | ||||
/// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> | /// <exception cref="ArgumentException"><paramref name="guildId"/> must not be equal to zero.</exception> | ||||
public async Task<GuildWidget> GetGuildWidgetAsync(ulong guildId, RequestOptions options = null) | public async Task<GuildWidget> GetGuildWidgetAsync(ulong guildId, RequestOptions options = null) | ||||
@@ -1514,6 +1511,15 @@ namespace Discord.API | |||||
} | } | ||||
//Guild emoji | //Guild emoji | ||||
public async Task<IReadOnlyCollection<Emoji>> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(guildId: guildId); | |||||
return await SendAsync<IReadOnlyCollection<Emoji>>("GET", () => $"guilds/{guildId}/emojis", ids, options: options).ConfigureAwait(false); | |||||
} | |||||
public async Task<Emoji> GetGuildEmoteAsync(ulong guildId, ulong emoteId, RequestOptions options = null) | public async Task<Emoji> GetGuildEmoteAsync(ulong guildId, ulong emoteId, RequestOptions options = null) | ||||
{ | { | ||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | Preconditions.NotEqual(guildId, 0, nameof(guildId)); | ||||
@@ -29,10 +29,7 @@ namespace Discord.Rest | |||||
internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { } | internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { } | ||||
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) | private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) | ||||
=> new API.DiscordRestApiClient(config.RestClientProvider, | |||||
DiscordRestConfig.UserAgent, | |||||
rateLimitPrecision: config.RateLimitPrecision, | |||||
useSystemClock: config.UseSystemClock); | |||||
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, useSystemClock: config.UseSystemClock); | |||||
internal override void Dispose(bool disposing) | internal override void Dispose(bool disposing) | ||||
{ | { | ||||
@@ -80,9 +77,6 @@ namespace Discord.Rest | |||||
=> ClientHelper.GetGuildAsync(this, id, false, options); | => ClientHelper.GetGuildAsync(this, id, false, options); | ||||
public Task<RestGuild> GetGuildAsync(ulong id, bool withCounts, RequestOptions options = null) | public Task<RestGuild> GetGuildAsync(ulong id, bool withCounts, RequestOptions options = null) | ||||
=> ClientHelper.GetGuildAsync(this, id, withCounts, options); | => ClientHelper.GetGuildAsync(this, id, withCounts, options); | ||||
[Obsolete("This endpoint is deprecated, use GetGuildWidgetAsync instead.")] | |||||
public Task<RestGuildEmbed?> GetGuildEmbedAsync(ulong id, RequestOptions options = null) | |||||
=> ClientHelper.GetGuildEmbedAsync(this, id, options); | |||||
public Task<RestGuildWidget?> GetGuildWidgetAsync(ulong id, RequestOptions options = null) | public Task<RestGuildWidget?> GetGuildWidgetAsync(ulong id, RequestOptions options = null) | ||||
=> ClientHelper.GetGuildWidgetAsync(this, id, options); | => ClientHelper.GetGuildWidgetAsync(this, id, options); | ||||
public IAsyncEnumerable<IReadOnlyCollection<RestUserGuild>> GetGuildSummariesAsync(RequestOptions options = null) | public IAsyncEnumerable<IReadOnlyCollection<RestUserGuild>> GetGuildSummariesAsync(RequestOptions options = null) | ||||
@@ -119,7 +113,19 @@ namespace Discord.Rest | |||||
=> ClientHelper.GetGlobalApplicationCommands(this, options); | => ClientHelper.GetGlobalApplicationCommands(this, options); | ||||
public Task<IReadOnlyCollection<RestGuildCommand>> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null) | public Task<IReadOnlyCollection<RestGuildCommand>> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null) | ||||
=> ClientHelper.GetGuildApplicationCommands(this, guildId, options); | => ClientHelper.GetGuildApplicationCommands(this, guildId, options); | ||||
public Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId) | |||||
=> ClientHelper.AddRoleAsync(this, guildId, userId, roleId); | |||||
public Task RemoveRoleAsync(ulong guildId, ulong userId, ulong roleId) | |||||
=> ClientHelper.RemoveRoleAsync(this, guildId, userId, roleId); | |||||
public Task AddReactionAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null) | |||||
=> MessageHelper.AddReactionAsync(channelId, messageId, emote, this, options); | |||||
public Task RemoveReactionAsync(ulong channelId, ulong messageId, ulong userId, IEmote emote, RequestOptions options = null) | |||||
=> MessageHelper.RemoveReactionAsync(channelId, messageId, userId, emote, this, options); | |||||
public Task RemoveAllReactionsAsync(ulong channelId, ulong messageId, RequestOptions options = null) | |||||
=> MessageHelper.RemoveAllReactionsAsync(channelId, messageId, this, options); | |||||
public Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null) | |||||
=> MessageHelper.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote, this, options); | |||||
//IDiscordClient | //IDiscordClient | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) | async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) | ||||
@@ -5,13 +5,14 @@ namespace Discord.Rest | |||||
/// </summary> | /// </summary> | ||||
public struct ChannelInfo | 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; | Name = name; | ||||
Topic = topic; | Topic = topic; | ||||
SlowModeInterval = rateLimit; | SlowModeInterval = rateLimit; | ||||
IsNsfw = nsfw; | IsNsfw = nsfw; | ||||
Bitrate = bitrate; | Bitrate = bitrate; | ||||
ChannelType = type; | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -53,5 +54,12 @@ namespace Discord.Rest | |||||
/// <c>null</c> if this is not mentioned in this entry. | /// <c>null</c> if this is not mentioned in this entry. | ||||
/// </returns> | /// </returns> | ||||
public int? Bitrate { get; } | 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; } | |||||
} | } | ||||
} | } |
@@ -26,6 +26,7 @@ namespace Discord.Rest | |||||
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user"); | var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user"); | ||||
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw"); | var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw"); | ||||
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate"); | 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), | string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer), | ||||
newName = nameModel?.NewValue?.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); | newNsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer); | ||||
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer), | int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer), | ||||
newBitrate = bitrateModel?.NewValue?.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); | return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after); | ||||
} | } | ||||
@@ -19,8 +19,14 @@ namespace Discord.Rest | |||||
internal static MessagePinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) | 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> | /// <summary> | ||||
@@ -38,10 +44,10 @@ namespace Discord.Rest | |||||
/// </returns> | /// </returns> | ||||
public ulong ChannelId { get; } | public ulong ChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the user of the message that was pinned. | |||||
/// Gets the user of the message that was pinned if available. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <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> | /// </returns> | ||||
public IUser Target { get; } | public IUser Target { get; } | ||||
} | } | ||||
@@ -19,8 +19,14 @@ namespace Discord.Rest | |||||
internal static MessageUnpinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) | 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> | /// <summary> | ||||
@@ -38,10 +44,10 @@ namespace Discord.Rest | |||||
/// </returns> | /// </returns> | ||||
public ulong ChannelId { get; } | public ulong ChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the user of the message that was unpinned. | |||||
/// Gets the user of the message that was unpinned if available. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <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> | /// </returns> | ||||
public IUser Target { get; } | public IUser Target { get; } | ||||
} | } | ||||
@@ -22,7 +22,7 @@ namespace Discord.Rest | |||||
internal static RestAuditLogEntry Create(BaseDiscordClient discord, Model fullLog, EntryModel model) | 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; | IUser user = null; | ||||
if (userInfo != null) | if (userInfo != null) | ||||
user = RestUser.Create(discord, userInfo); | user = RestUser.Create(discord, userInfo); | ||||
@@ -33,8 +33,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -59,8 +59,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -84,8 +84,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -286,6 +286,13 @@ namespace Discord.Rest | |||||
return RestUserMessage.Create(client, channel, client.CurrentUser, model); | return RestUserMessage.Create(client, channel, client.CurrentUser, model); | ||||
} | } | ||||
public static async Task<RestUserMessage> ModifyMessageAsync(IMessageChannel channel, ulong messageId, Action<MessageProperties> func, | |||||
BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
var msgModel = await MessageHelper.ModifyAsync(channel.Id, messageId, client, func, options).ConfigureAwait(false); | |||||
return RestUserMessage.Create(client, channel, msgModel.Author.IsSpecified ? RestUser.Create(client, msgModel.Author.Value) : client.CurrentUser, msgModel); | |||||
} | |||||
public static Task DeleteMessageAsync(IMessageChannel channel, ulong messageId, BaseDiscordClient client, | public static Task DeleteMessageAsync(IMessageChannel channel, ulong messageId, BaseDiscordClient client, | ||||
RequestOptions options) | RequestOptions options) | ||||
=> MessageHelper.DeleteAsync(channel.Id, messageId, client, options); | => MessageHelper.DeleteAsync(channel.Id, messageId, client, options); | ||||
@@ -321,13 +328,13 @@ namespace Discord.Rest | |||||
public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
IUser user, OverwritePermissions perms, RequestOptions options) | IUser user, OverwritePermissions perms, RequestOptions options) | ||||
{ | { | ||||
var args = new ModifyChannelPermissionsParams("member", perms.AllowValue, perms.DenyValue); | |||||
var args = new ModifyChannelPermissionsParams((int)PermissionTarget.User, perms.AllowValue.ToString(), perms.DenyValue.ToString()); | |||||
await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, user.Id, args, options).ConfigureAwait(false); | await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, user.Id, args, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
IRole role, OverwritePermissions perms, RequestOptions options) | IRole role, OverwritePermissions perms, RequestOptions options) | ||||
{ | { | ||||
var args = new ModifyChannelPermissionsParams("role", perms.AllowValue, perms.DenyValue); | |||||
var args = new ModifyChannelPermissionsParams((int)PermissionTarget.Role, perms.AllowValue.ToString(), perms.DenyValue.ToString()); | |||||
await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, role.Id, args, options).ConfigureAwait(false); | await client.ApiClient.ModifyChannelPermissionsAsync(channel.Id, role.Id, args, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, | ||||
@@ -443,8 +450,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
}; | }; | ||||
await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
@@ -135,6 +135,10 @@ namespace Discord.Rest | |||||
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | ||||
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | => ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | ||||
/// <inheritdoc /> | |||||
public async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||||
=> await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task TriggerTypingAsync(RequestOptions options = null) | public Task TriggerTypingAsync(RequestOptions options = null) | ||||
=> ChannelHelper.TriggerTypingAsync(this, Discord, options); | => ChannelHelper.TriggerTypingAsync(this, Discord, options); | ||||
@@ -93,6 +93,10 @@ namespace Discord.Rest | |||||
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | ||||
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | => ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | ||||
/// <inheritdoc /> | |||||
public async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||||
=> await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | ||||
public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null) | public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null) | ||||
@@ -152,6 +152,10 @@ namespace Discord.Rest | |||||
public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | ||||
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options); | => ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options); | ||||
/// <inheritdoc /> | |||||
public async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||||
=> await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task TriggerTypingAsync(RequestOptions options = null) | public Task TriggerTypingAsync(RequestOptions options = null) | ||||
=> ChannelHelper.TriggerTypingAsync(this, Discord, options); | => ChannelHelper.TriggerTypingAsync(this, Discord, options); | ||||
@@ -4,7 +4,6 @@ using System.Collections.Generic; | |||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using EmbedModel = Discord.API.GuildEmbed; | |||||
using WidgetModel = Discord.API.GuildWidget; | using WidgetModel = Discord.API.GuildWidget; | ||||
using Model = Discord.API.Guild; | using Model = Discord.API.Guild; | ||||
using RoleModel = Discord.API.Role; | using RoleModel = Discord.API.Role; | ||||
@@ -81,26 +80,6 @@ namespace Discord.Rest | |||||
return await client.ApiClient.ModifyGuildAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <c>null</c>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="func"/> is <c>null</c>.</exception> | ||||
public static async Task<EmbedModel> ModifyEmbedAsync(IGuild guild, BaseDiscordClient client, | |||||
Action<GuildEmbedProperties> func, RequestOptions options) | |||||
{ | |||||
if (func == null) throw new ArgumentNullException(nameof(func)); | |||||
var args = new GuildEmbedProperties(); | |||||
func(args); | |||||
var apiArgs = new API.Rest.ModifyGuildEmbedParams | |||||
{ | |||||
Enabled = args.Enabled | |||||
}; | |||||
if (args.Channel.IsSpecified) | |||||
apiArgs.ChannelId = args.Channel.Value?.Id; | |||||
else if (args.ChannelId.IsSpecified) | |||||
apiArgs.ChannelId = args.ChannelId.Value; | |||||
return await client.ApiClient.ModifyGuildEmbedAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | |||||
} | |||||
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <c>null</c>.</exception> | |||||
public static async Task<WidgetModel> ModifyWidgetAsync(IGuild guild, BaseDiscordClient client, | public static async Task<WidgetModel> ModifyWidgetAsync(IGuild guild, BaseDiscordClient client, | ||||
Action<GuildWidgetProperties> func, RequestOptions options) | Action<GuildWidgetProperties> func, RequestOptions options) | ||||
{ | { | ||||
@@ -205,8 +184,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -233,8 +212,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -258,8 +237,8 @@ namespace Discord.Rest | |||||
{ | { | ||||
TargetId = overwrite.TargetId, | TargetId = overwrite.TargetId, | ||||
TargetType = overwrite.TargetType, | TargetType = overwrite.TargetType, | ||||
Allow = overwrite.Permissions.AllowValue, | |||||
Deny = overwrite.Permissions.DenyValue | |||||
Allow = overwrite.Permissions.AllowValue.ToString(), | |||||
Deny = overwrite.Permissions.DenyValue.ToString() | |||||
}).ToArray() | }).ToArray() | ||||
: Optional.Create<API.Overwrite[]>(), | : Optional.Create<API.Overwrite[]>(), | ||||
}; | }; | ||||
@@ -304,6 +283,7 @@ namespace Discord.Rest | |||||
var vanityModel = await client.ApiClient.GetVanityInviteAsync(guild.Id, options).ConfigureAwait(false); | var vanityModel = await client.ApiClient.GetVanityInviteAsync(guild.Id, options).ConfigureAwait(false); | ||||
if (vanityModel == null) throw new InvalidOperationException("This guild does not have a vanity URL."); | if (vanityModel == null) throw new InvalidOperationException("This guild does not have a vanity URL."); | ||||
var inviteModel = await client.ApiClient.GetInviteAsync(vanityModel.Code, options).ConfigureAwait(false); | var inviteModel = await client.ApiClient.GetInviteAsync(vanityModel.Code, options).ConfigureAwait(false); | ||||
inviteModel.Uses = vanityModel.Uses; | |||||
return RestInviteMetadata.Create(client, guild, null, inviteModel); | return RestInviteMetadata.Create(client, guild, null, inviteModel); | ||||
} | } | ||||
@@ -320,7 +300,7 @@ namespace Discord.Rest | |||||
Hoist = isHoisted, | Hoist = isHoisted, | ||||
Mentionable = isMentionable, | Mentionable = isMentionable, | ||||
Name = name, | Name = name, | ||||
Permissions = permissions?.RawValue ?? Optional.Create<ulong>() | |||||
Permissions = permissions?.RawValue.ToString() ?? Optional.Create<string>() | |||||
}; | }; | ||||
var model = await client.ApiClient.CreateGuildRoleAsync(guild.Id, createGuildRoleParams, options).ConfigureAwait(false); | var model = await client.ApiClient.CreateGuildRoleAsync(guild.Id, createGuildRoleParams, options).ConfigureAwait(false); | ||||
@@ -496,6 +476,11 @@ namespace Discord.Rest | |||||
} | } | ||||
//Emotes | //Emotes | ||||
public static async Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
var models = await client.ApiClient.GetGuildEmotesAsync(guild.Id, options).ConfigureAwait(false); | |||||
return models.Select(x => x.ToEntity()).ToImmutableArray(); | |||||
} | |||||
public static async Task<GuildEmote> GetEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) | public static async Task<GuildEmote> GetEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) | ||||
{ | { | ||||
var emote = await client.ApiClient.GetGuildEmoteAsync(guild.Id, id, options).ConfigureAwait(false); | var emote = await client.ApiClient.GetGuildEmoteAsync(guild.Id, id, options).ConfigureAwait(false); | ||||
@@ -6,7 +6,6 @@ using System.Diagnostics; | |||||
using System.Globalization; | using System.Globalization; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using EmbedModel = Discord.API.GuildEmbed; | |||||
using WidgetModel = Discord.API.GuildWidget; | using WidgetModel = Discord.API.GuildWidget; | ||||
using Model = Discord.API.Guild; | using Model = Discord.API.Guild; | ||||
@@ -27,8 +26,6 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public int AFKTimeout { get; private set; } | public int AFKTimeout { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public bool IsEmbeddable { get; private set; } | |||||
/// <inheritdoc /> | |||||
public bool IsWidgetEnabled { get; private set; } | public bool IsWidgetEnabled { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public VerificationLevel VerificationLevel { get; private set; } | public VerificationLevel VerificationLevel { get; private set; } | ||||
@@ -42,8 +39,6 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong? AFKChannelId { get; private set; } | public ulong? AFKChannelId { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong? EmbedChannelId { get; private set; } | |||||
/// <inheritdoc /> | |||||
public ulong? WidgetChannelId { get; private set; } | public ulong? WidgetChannelId { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong? SystemChannelId { get; private set; } | public ulong? SystemChannelId { get; private set; } | ||||
@@ -95,8 +90,6 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | ||||
[Obsolete("DefaultChannelId is deprecated, use GetDefaultChannelAsync")] | |||||
public ulong DefaultChannelId => Id; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string IconUrl => CDN.GetGuildIconUrl(Id, IconId); | public string IconUrl => CDN.GetGuildIconUrl(Id, IconId); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -133,16 +126,12 @@ namespace Discord.Rest | |||||
internal void Update(Model model) | internal void Update(Model model) | ||||
{ | { | ||||
AFKChannelId = model.AFKChannelId; | AFKChannelId = model.AFKChannelId; | ||||
if (model.EmbedChannelId.IsSpecified) | |||||
EmbedChannelId = model.EmbedChannelId.Value; | |||||
if (model.WidgetChannelId.IsSpecified) | if (model.WidgetChannelId.IsSpecified) | ||||
WidgetChannelId = model.WidgetChannelId.Value; | WidgetChannelId = model.WidgetChannelId.Value; | ||||
SystemChannelId = model.SystemChannelId; | SystemChannelId = model.SystemChannelId; | ||||
RulesChannelId = model.RulesChannelId; | RulesChannelId = model.RulesChannelId; | ||||
PublicUpdatesChannelId = model.PublicUpdatesChannelId; | PublicUpdatesChannelId = model.PublicUpdatesChannelId; | ||||
AFKTimeout = model.AFKTimeout; | AFKTimeout = model.AFKTimeout; | ||||
if (model.EmbedEnabled.IsSpecified) | |||||
IsEmbeddable = model.EmbedEnabled.Value; | |||||
if (model.WidgetEnabled.IsSpecified) | if (model.WidgetEnabled.IsSpecified) | ||||
IsWidgetEnabled = model.WidgetEnabled.Value; | IsWidgetEnabled = model.WidgetEnabled.Value; | ||||
IconId = model.Icon; | IconId = model.Icon; | ||||
@@ -200,11 +189,6 @@ namespace Discord.Rest | |||||
Available = true; | Available = true; | ||||
} | } | ||||
internal void Update(EmbedModel model) | |||||
{ | |||||
EmbedChannelId = model.ChannelId; | |||||
IsEmbeddable = model.Enabled; | |||||
} | |||||
internal void Update(WidgetModel model) | internal void Update(WidgetModel model) | ||||
{ | { | ||||
WidgetChannelId = model.ChannelId; | WidgetChannelId = model.ChannelId; | ||||
@@ -241,15 +225,6 @@ namespace Discord.Rest | |||||
Update(model); | Update(model); | ||||
} | } | ||||
/// <inheritdoc /> | |||||
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception> | |||||
[Obsolete("This endpoint is deprecated, use ModifyWidgetAsync instead.")] | |||||
public async Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null) | |||||
{ | |||||
var model = await GuildHelper.ModifyEmbedAsync(this, Discord, func, options).ConfigureAwait(false); | |||||
Update(model); | |||||
} | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception> | /// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception> | ||||
public async Task ModifyWidgetAsync(Action<GuildWidgetProperties> func, RequestOptions options = null) | public async Task ModifyWidgetAsync(Action<GuildWidgetProperties> func, RequestOptions options = null) | ||||
@@ -463,23 +438,6 @@ namespace Discord.Rest | |||||
.FirstOrDefault(); | .FirstOrDefault(); | ||||
} | } | ||||
/// <summary> | |||||
/// Gets the embed channel (i.e. the channel set in the guild's widget settings) in this guild. | |||||
/// </summary> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A task that represents the asynchronous get operation. The task result contains the embed channel set | |||||
/// within the server's widget settings; <see langword="null"/> if none is set. | |||||
/// </returns> | |||||
[Obsolete("This endpoint is deprecated, use GetWidgetChannelAsync instead.")] | |||||
public async Task<RestGuildChannel> GetEmbedChannelAsync(RequestOptions options = null) | |||||
{ | |||||
var embedId = EmbedChannelId; | |||||
if (embedId.HasValue) | |||||
return await GuildHelper.GetChannelAsync(this, Discord, embedId.Value, options).ConfigureAwait(false); | |||||
return null; | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Gets the widget channel (i.e. the channel set in the guild's widget settings) in this guild. | /// Gets the widget channel (i.e. the channel set in the guild's widget settings) in this guild. | ||||
/// </summary> | /// </summary> | ||||
@@ -828,6 +786,9 @@ namespace Discord.Rest | |||||
//Emotes | //Emotes | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task<IReadOnlyCollection<GuildEmote>> GetEmotesAsync(RequestOptions options = null) | |||||
=> GuildHelper.GetEmotesAsync(this, Discord, options); | |||||
/// <inheritdoc /> | |||||
public Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null) | public Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null) | ||||
=> GuildHelper.GetEmoteAsync(this, Discord, id, options); | => GuildHelper.GetEmoteAsync(this, Discord, id, options); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -934,15 +895,6 @@ namespace Discord.Rest | |||||
return null; | return null; | ||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
[Obsolete("This endpoint is deprecated, use GetWidgetChannelAsync instead.")] | |||||
async Task<IGuildChannel> IGuild.GetEmbedChannelAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
if (mode == CacheMode.AllowDownload) | |||||
return await GetEmbedChannelAsync(options).ConfigureAwait(false); | |||||
else | |||||
return null; | |||||
} | |||||
/// <inheritdoc /> | |||||
async Task<IGuildChannel> IGuild.GetWidgetChannelAsync(CacheMode mode, RequestOptions options) | async Task<IGuildChannel> IGuild.GetWidgetChannelAsync(CacheMode mode, RequestOptions options) | ||||
{ | { | ||||
if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
@@ -1,25 +0,0 @@ | |||||
using System.Diagnostics; | |||||
using Model = Discord.API.GuildEmbed; | |||||
namespace Discord.Rest | |||||
{ | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public struct RestGuildEmbed | |||||
{ | |||||
public bool IsEnabled { get; private set; } | |||||
public ulong? ChannelId { get; private set; } | |||||
internal RestGuildEmbed(bool isEnabled, ulong? channelId) | |||||
{ | |||||
ChannelId = channelId; | |||||
IsEnabled = isEnabled; | |||||
} | |||||
internal static RestGuildEmbed Create(Model model) | |||||
{ | |||||
return new RestGuildEmbed(model.Enabled, model.ChannelId); | |||||
} | |||||
public override string ToString() => ChannelId?.ToString() ?? "Unknown"; | |||||
private string DebuggerDisplay => $"{ChannelId} ({(IsEnabled ? "Enabled" : "Disabled")})"; | |||||
} | |||||
} |
@@ -21,6 +21,12 @@ namespace Discord.Rest | |||||
public ulong ChannelId { get; private set; } | public ulong ChannelId { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong? GuildId { get; private set; } | public ulong? GuildId { get; private set; } | ||||
/// <inheritdoc /> | |||||
public IUser Inviter { get; private set; } | |||||
/// <inheritdoc /> | |||||
public IUser TargetUser { get; private set; } | |||||
/// <inheritdoc /> | |||||
public TargetUserType TargetUserType { get; private set; } | |||||
internal IChannel Channel { get; } | internal IChannel Channel { get; } | ||||
internal IGuild Guild { get; } | internal IGuild Guild { get; } | ||||
@@ -50,6 +56,9 @@ namespace Discord.Rest | |||||
MemberCount = model.MemberCount.IsSpecified ? model.MemberCount.Value : null; | MemberCount = model.MemberCount.IsSpecified ? model.MemberCount.Value : null; | ||||
PresenceCount = model.PresenceCount.IsSpecified ? model.PresenceCount.Value : null; | PresenceCount = model.PresenceCount.IsSpecified ? model.PresenceCount.Value : null; | ||||
ChannelType = (ChannelType)model.Channel.Type; | ChannelType = (ChannelType)model.Channel.Type; | ||||
Inviter = model.Inviter.IsSpecified ? RestUser.Create(Discord, model.Inviter.Value) : null; | |||||
TargetUser = model.TargetUser.IsSpecified ? RestUser.Create(Discord, model.TargetUser.Value) : null; | |||||
TargetUserType = model.TargetUserType.IsSpecified ? model.TargetUserType.Value : TargetUserType.Undefined; | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -6,10 +6,8 @@ namespace Discord.Rest | |||||
/// <summary> Represents additional information regarding the REST-based invite object. </summary> | /// <summary> Represents additional information regarding the REST-based invite object. </summary> | ||||
public class RestInviteMetadata : RestInvite, IInviteMetadata | public class RestInviteMetadata : RestInvite, IInviteMetadata | ||||
{ | { | ||||
private long? _createdAtTicks; | |||||
private long _createdAtTicks; | |||||
/// <inheritdoc /> | |||||
public bool IsRevoked { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public bool IsTemporary { get; private set; } | public bool IsTemporary { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -18,10 +16,6 @@ namespace Discord.Rest | |||||
public int? MaxUses { get; private set; } | public int? MaxUses { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public int? Uses { get; private set; } | public int? Uses { get; private set; } | ||||
/// <summary> | |||||
/// Gets the user that created this invite. | |||||
/// </summary> | |||||
public RestUser Inviter { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset? CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); | public DateTimeOffset? CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); | ||||
@@ -39,16 +33,11 @@ namespace Discord.Rest | |||||
internal void Update(Model model) | internal void Update(Model model) | ||||
{ | { | ||||
base.Update(model); | base.Update(model); | ||||
Inviter = model.Inviter != null ? RestUser.Create(Discord, model.Inviter) : null; | |||||
IsRevoked = model.Revoked; | |||||
IsTemporary = model.Temporary; | IsTemporary = model.Temporary; | ||||
MaxAge = model.MaxAge.IsSpecified ? model.MaxAge.Value : (int?)null; | |||||
MaxUses = model.MaxUses.IsSpecified ? model.MaxUses.Value : (int?)null; | |||||
Uses = model.Uses.IsSpecified ? model.Uses.Value : (int?)null; | |||||
_createdAtTicks = model.CreatedAt.IsSpecified ? model.CreatedAt.Value.UtcTicks : (long?)null; | |||||
MaxAge = model.MaxAge; | |||||
MaxUses = model.MaxUses; | |||||
Uses = model.Uses; | |||||
_createdAtTicks = model.CreatedAt.UtcTicks; | |||||
} | } | ||||
/// <inheritdoc /> | |||||
IUser IInviteMetadata.Inviter => Inviter; | |||||
} | } | ||||
} | } |
@@ -27,26 +27,93 @@ namespace Discord.Rest | |||||
public static async Task<Model> ModifyAsync(IMessage msg, BaseDiscordClient client, Action<MessageProperties> func, | public static async Task<Model> ModifyAsync(IMessage msg, BaseDiscordClient client, Action<MessageProperties> func, | ||||
RequestOptions options) | 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(); | var args = new MessageProperties(); | ||||
func(args); | 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 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(); | bool hasEmbed = args.Embed.IsSpecified ? args.Embed.Value != null : msg.Embeds.Any(); | ||||
if (!hasText && !hasEmbed) | if (!hasText && !hasEmbed) | ||||
Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | 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 | var apiArgs = new API.Rest.ModifyMessageParams | ||||
{ | { | ||||
Content = args.Content, | 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>(), | ||||
Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified | Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified | ||||
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); | return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task<Model> ModifyAsync(ulong channelId, ulong msgId, BaseDiscordClient client, Action<MessageProperties> func, | |||||
RequestOptions options) | |||||
{ | |||||
var args = new MessageProperties(); | |||||
func(args); | |||||
if ((args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value)) && (args.Embed.IsSpecified && args.Embed.Value == null)) | |||||
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>(), | |||||
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(channelId, msgId, apiArgs, options).ConfigureAwait(false); | |||||
} | |||||
public static Task DeleteAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) | public static Task DeleteAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) | ||||
=> DeleteAsync(msg.Channel.Id, msg.Id, client, options); | => DeleteAsync(msg.Channel.Id, msg.Id, client, options); | ||||
@@ -56,13 +123,14 @@ namespace Discord.Rest | |||||
await client.ApiClient.DeleteMessageAsync(channelId, msgId, options).ConfigureAwait(false); | await client.ApiClient.DeleteMessageAsync(channelId, msgId, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task SuppressEmbedsAsync(IMessage msg, BaseDiscordClient client, bool suppress, RequestOptions options) | |||||
public static async Task AddReactionAsync(ulong channelId, ulong messageId, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||||
{ | { | ||||
var apiArgs = new API.Rest.SuppressEmbedParams | |||||
{ | |||||
Suppressed = suppress | |||||
}; | |||||
await client.ApiClient.SuppressEmbedAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); | |||||
await client.ApiClient.AddReactionAsync(channelId, messageId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | |||||
} | |||||
public static async Task AddReactionAsync(ulong channelId, ulong messageId, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
await client.ApiClient.AddReactionAsync(channelId, messageId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | |||||
} | } | ||||
public static async Task AddReactionAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options) | public static async Task AddReactionAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options) | ||||
@@ -70,16 +138,31 @@ namespace Discord.Rest | |||||
await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task RemoveReactionAsync(ulong channelId, ulong messageId, ulong userId, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
await client.ApiClient.RemoveReactionAsync(channelId, messageId, userId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | |||||
} | |||||
public static async Task RemoveReactionAsync(IMessage msg, ulong userId, IEmote emote, BaseDiscordClient client, RequestOptions options) | public static async Task RemoveReactionAsync(IMessage msg, ulong userId, IEmote emote, BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, userId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, userId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task RemoveAllReactionsAsync(ulong channelId, ulong messageId, BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
await client.ApiClient.RemoveAllReactionsAsync(channelId, messageId, options).ConfigureAwait(false); | |||||
} | |||||
public static async Task RemoveAllReactionsAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) | public static async Task RemoveAllReactionsAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false); | await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false); | ||||
} | } | ||||
public static async Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, BaseDiscordClient client, RequestOptions options) | |||||
{ | |||||
await client.ApiClient.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | |||||
} | |||||
public static async Task RemoveAllReactionsForEmoteAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options) | public static async Task RemoveAllReactionsForEmoteAsync(IMessage msg, IEmote emote, BaseDiscordClient client, RequestOptions options) | ||||
{ | { | ||||
await client.ApiClient.RemoveAllReactionsForEmoteAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | await client.ApiClient.RemoveAllReactionsForEmoteAsync(msg.Channel.Id, msg.Id, emote is Emote e ? $"{e.Name}:{e.Id}" : UrlEncode(emote.Name), options).ConfigureAwait(false); | ||||
@@ -58,6 +58,8 @@ namespace Discord.Rest | |||||
public virtual IReadOnlyCollection<RestUser> MentionedUsers => ImmutableArray.Create<RestUser>(); | public virtual IReadOnlyCollection<RestUser> MentionedUsers => ImmutableArray.Create<RestUser>(); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | public virtual IReadOnlyCollection<ITag> Tags => ImmutableArray.Create<ITag>(); | ||||
/// <inheritdoc /> | |||||
public virtual IReadOnlyCollection<Sticker> Stickers => ImmutableArray.Create<Sticker>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); | ||||
@@ -67,6 +69,8 @@ namespace Discord.Rest | |||||
public MessageApplication Application { get; private set; } | public MessageApplication Application { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public MessageReference Reference { get; private set; } | public MessageReference Reference { get; private set; } | ||||
/// <inheritdoc /> | |||||
public MessageFlags? Flags { get; private set; } | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public IReadOnlyCollection<ActionRowComponent> Components { get; private set; } | public IReadOnlyCollection<ActionRowComponent> Components { get; private set; } | ||||
@@ -143,6 +147,9 @@ namespace Discord.Rest | |||||
else | else | ||||
Components = new List<ActionRowComponent>(); | Components = new List<ActionRowComponent>(); | ||||
if (model.Flags.IsSpecified) | |||||
Flags = model.Flags.Value; | |||||
if (model.Reactions.IsSpecified) | if (model.Reactions.IsSpecified) | ||||
{ | { | ||||
var value = model.Reactions.Value; | var value = model.Reactions.Value; | ||||
@@ -187,8 +194,13 @@ namespace Discord.Rest | |||||
IReadOnlyCollection<IEmbed> IMessage.Embeds => Embeds; | IReadOnlyCollection<IEmbed> IMessage.Embeds => Embeds; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
IReadOnlyCollection<ulong> IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); | IReadOnlyCollection<ulong> IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | IReadOnlyCollection<IMessageComponent> IMessage.Components => Components; | ||||
/// <inheritdoc /> | |||||
IReadOnlyCollection<ISticker> IMessage.Stickers => Stickers; | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); | ||||
@@ -13,7 +13,7 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestUserMessage : RestMessage, IUserMessage | public class RestUserMessage : RestMessage, IUserMessage | ||||
{ | { | ||||
private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed; | |||||
private bool _isMentioningEveryone, _isTTS, _isPinned; | |||||
private long? _editedTimestampTicks; | private long? _editedTimestampTicks; | ||||
private IUserMessage _referencedMessage; | private IUserMessage _referencedMessage; | ||||
private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>(); | private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>(); | ||||
@@ -21,13 +21,14 @@ namespace Discord.Rest | |||||
private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | private ImmutableArray<ITag> _tags = ImmutableArray.Create<ITag>(); | ||||
private ImmutableArray<ulong> _roleMentionIds = ImmutableArray.Create<ulong>(); | private ImmutableArray<ulong> _roleMentionIds = ImmutableArray.Create<ulong>(); | ||||
private ImmutableArray<RestUser> _userMentions = ImmutableArray.Create<RestUser>(); | private ImmutableArray<RestUser> _userMentions = ImmutableArray.Create<RestUser>(); | ||||
private ImmutableArray<Sticker> _stickers = ImmutableArray.Create<Sticker>(); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsTTS => _isTTS; | public override bool IsTTS => _isTTS; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsPinned => _isPinned; | public override bool IsPinned => _isPinned; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsSuppressed => _isSuppressed; | |||||
public override bool IsSuppressed => Flags.HasValue && Flags.Value.HasFlag(MessageFlags.SuppressEmbeds); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -45,6 +46,8 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<ITag> Tags => _tags; | public override IReadOnlyCollection<ITag> Tags => _tags; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override IReadOnlyCollection<Sticker> Stickers => _stickers; | |||||
/// <inheritdoc /> | |||||
public IUserMessage ReferencedMessage => _referencedMessage; | public IUserMessage ReferencedMessage => _referencedMessage; | ||||
internal RestUserMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | internal RestUserMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | ||||
@@ -70,10 +73,6 @@ namespace Discord.Rest | |||||
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks; | _editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks; | ||||
if (model.MentionEveryone.IsSpecified) | if (model.MentionEveryone.IsSpecified) | ||||
_isMentioningEveryone = model.MentionEveryone.Value; | _isMentioningEveryone = model.MentionEveryone.Value; | ||||
if (model.Flags.IsSpecified) | |||||
{ | |||||
_isSuppressed = model.Flags.Value.HasFlag(API.MessageFlags.Suppressed); | |||||
} | |||||
if (model.RoleMentions.IsSpecified) | if (model.RoleMentions.IsSpecified) | ||||
_roleMentionIds = model.RoleMentions.Value.ToImmutableArray(); | _roleMentionIds = model.RoleMentions.Value.ToImmutableArray(); | ||||
@@ -136,6 +135,20 @@ namespace Discord.Rest | |||||
IUser refMsgAuthor = MessageHelper.GetAuthor(Discord, guild, refMsg.Author.Value, refMsg.WebhookId.ToNullable()); | IUser refMsgAuthor = MessageHelper.GetAuthor(Discord, guild, refMsg.Author.Value, refMsg.WebhookId.ToNullable()); | ||||
_referencedMessage = RestUserMessage.Create(Discord, Channel, refMsgAuthor, refMsg); | _referencedMessage = RestUserMessage.Create(Discord, Channel, refMsgAuthor, refMsg); | ||||
} | } | ||||
if (model.Stickers.IsSpecified) | |||||
{ | |||||
var value = model.Stickers.Value; | |||||
if (value.Length > 0) | |||||
{ | |||||
var stickers = ImmutableArray.CreateBuilder<Sticker>(value.Length); | |||||
for (int i = 0; i < value.Length; i++) | |||||
stickers.Add(Sticker.Create(value[i])); | |||||
_stickers = stickers.ToImmutable(); | |||||
} | |||||
else | |||||
_stickers = ImmutableArray.Create<Sticker>(); | |||||
} | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -151,9 +164,6 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task UnpinAsync(RequestOptions options = null) | public Task UnpinAsync(RequestOptions options = null) | ||||
=> MessageHelper.UnpinAsync(this, Discord, options); | => MessageHelper.UnpinAsync(this, Discord, options); | ||||
/// <inheritdoc /> | |||||
public Task ModifySuppressionAsync(bool suppressEmbeds, RequestOptions options = null) | |||||
=> MessageHelper.SuppressEmbedsAsync(this, Discord, suppressEmbeds, options); | |||||
public string Resolve(int startIndex, TagHandling userHandling = TagHandling.Name, TagHandling channelHandling = TagHandling.Name, | public string Resolve(int startIndex, TagHandling userHandling = TagHandling.Name, TagHandling channelHandling = TagHandling.Name, | ||||
TagHandling roleHandling = TagHandling.Name, TagHandling everyoneHandling = TagHandling.Ignore, TagHandling emojiHandling = TagHandling.Name) | TagHandling roleHandling = TagHandling.Name, TagHandling everyoneHandling = TagHandling.Ignore, TagHandling emojiHandling = TagHandling.Name) | ||||
@@ -0,0 +1,48 @@ | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using Model = Discord.API.Sticker; | |||||
namespace Discord | |||||
{ | |||||
/// <inheritdoc cref="ISticker"/> | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
public class Sticker : ISticker | |||||
{ | |||||
/// <inheritdoc /> | |||||
public ulong Id { get; } | |||||
/// <inheritdoc /> | |||||
public ulong PackId { get; } | |||||
/// <inheritdoc /> | |||||
public string Name { get; } | |||||
/// <inheritdoc /> | |||||
public string Description { get; } | |||||
/// <inheritdoc /> | |||||
public IReadOnlyCollection<string> Tags { get; } | |||||
/// <inheritdoc /> | |||||
public string Asset { get; } | |||||
/// <inheritdoc /> | |||||
public string PreviewAsset { get; } | |||||
/// <inheritdoc /> | |||||
public StickerFormatType FormatType { get; } | |||||
internal Sticker(ulong id, ulong packId, string name, string description, string[] tags, string asset, string previewAsset, StickerFormatType formatType) | |||||
{ | |||||
Id = id; | |||||
PackId = packId; | |||||
Name = name; | |||||
Description = description; | |||||
Tags = tags.ToReadOnlyCollection(); | |||||
Asset = asset; | |||||
PreviewAsset = previewAsset; | |||||
FormatType = formatType; | |||||
} | |||||
internal static Sticker Create(Model model) | |||||
{ | |||||
return new Sticker(model.Id, model.PackId, model.Name, model.Desription, | |||||
model.Tags.IsSpecified ? model.Tags.Value.Split(',') : new string[0], | |||||
model.Asset, model.PreviewAsset, model.FormatType); | |||||
} | |||||
private string DebuggerDisplay => $"{Name} ({Id})"; | |||||
} | |||||
} |
@@ -26,6 +26,8 @@ namespace Discord.Rest | |||||
public GuildPermissions Permissions { get; private set; } | public GuildPermissions Permissions { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public int Position { get; private set; } | public int Position { get; private set; } | ||||
/// <inheritdoc /> | |||||
public RoleTags Tags { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | ||||
@@ -56,6 +58,8 @@ namespace Discord.Rest | |||||
Position = model.Position; | Position = model.Position; | ||||
Color = new Color(model.Color); | Color = new Color(model.Color); | ||||
Permissions = new GuildPermissions(model.Permissions); | Permissions = new GuildPermissions(model.Permissions); | ||||
if (model.Tags.IsSpecified) | |||||
Tags = model.Tags.Value.ToEntity(); | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -1,4 +1,4 @@ | |||||
using System; | |||||
using System; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Model = Discord.API.Role; | using Model = Discord.API.Role; | ||||
using BulkParams = Discord.API.Rest.ModifyGuildRolesParams; | using BulkParams = Discord.API.Rest.ModifyGuildRolesParams; | ||||
@@ -24,7 +24,7 @@ namespace Discord.Rest | |||||
Hoist = args.Hoist, | Hoist = args.Hoist, | ||||
Mentionable = args.Mentionable, | Mentionable = args.Mentionable, | ||||
Name = args.Name, | Name = args.Name, | ||||
Permissions = args.Permissions.IsSpecified ? args.Permissions.Value.RawValue : Optional.Create<ulong>() | |||||
Permissions = args.Permissions.IsSpecified ? args.Permissions.Value.RawValue.ToString() : Optional.Create<string>() | |||||
}; | }; | ||||
var model = await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, apiArgs, options).ConfigureAwait(false); | var model = await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, apiArgs, options).ConfigureAwait(false); | ||||
@@ -29,6 +29,8 @@ namespace Discord.Rest | |||||
public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks); | public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public ulong GuildId => Guild.Id; | public ulong GuildId => Guild.Id; | ||||
/// <inheritdoc /> | |||||
public bool? IsPending { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
/// <exception cref="InvalidOperationException" accessor="get">Resolving permissions requires the parent guild to be downloaded.</exception> | /// <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); | UpdateRoles(model.Roles.Value); | ||||
if (model.PremiumSince.IsSpecified) | if (model.PremiumSince.IsSpecified) | ||||
_premiumSinceTicks = model.PremiumSince.Value?.UtcTicks; | _premiumSinceTicks = model.PremiumSince.Value?.UtcTicks; | ||||
if (model.Pending.IsSpecified) | |||||
IsPending = model.Pending.Value; | |||||
} | } | ||||
private void UpdateRoles(ulong[] roleIds) | private void UpdateRoles(ulong[] roleIds) | ||||
{ | { | ||||
@@ -108,17 +112,29 @@ namespace Discord.Rest | |||||
public Task KickAsync(string reason = null, RequestOptions options = null) | public Task KickAsync(string reason = null, RequestOptions options = null) | ||||
=> UserHelper.KickAsync(this, Discord, reason, options); | => UserHelper.KickAsync(this, Discord, reason, options); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task AddRoleAsync(ulong roleId, RequestOptions options = null) | |||||
=> AddRolesAsync(new[] { roleId }, options); | |||||
/// <inheritdoc /> | |||||
public Task AddRoleAsync(IRole role, RequestOptions options = null) | public Task AddRoleAsync(IRole role, RequestOptions options = null) | ||||
=> AddRolesAsync(new[] { role }, options); | |||||
=> AddRoleAsync(role.Id, options); | |||||
/// <inheritdoc /> | |||||
public Task AddRolesAsync(IEnumerable<ulong> roleIds, RequestOptions options = null) | |||||
=> UserHelper.AddRolesAsync(this, Discord, roleIds, options); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null) | public Task AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null) | ||||
=> UserHelper.AddRolesAsync(this, Discord, roles, options); | |||||
=> AddRolesAsync(roles.Select(x => x.Id), options); | |||||
/// <inheritdoc /> | |||||
public Task RemoveRoleAsync(ulong roleId, RequestOptions options = null) | |||||
=> RemoveRolesAsync(new[] { roleId }, options); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task RemoveRoleAsync(IRole role, RequestOptions options = null) | public Task RemoveRoleAsync(IRole role, RequestOptions options = null) | ||||
=> RemoveRolesAsync(new[] { role }, options); | |||||
=> RemoveRoleAsync(role.Id, options); | |||||
/// <inheritdoc /> | |||||
public Task RemoveRolesAsync(IEnumerable<ulong> roleIds, RequestOptions options = null) | |||||
=> UserHelper.RemoveRolesAsync(this, Discord, roleIds, options); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null) | public Task RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options = null) | ||||
=> UserHelper.RemoveRolesAsync(this, Discord, roles, options); | |||||
=> RemoveRolesAsync(roles.Select(x => x.Id)); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
/// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | /// <exception cref="InvalidOperationException">Resolving permissions requires the parent guild to be downloaded.</exception> | ||||
@@ -21,6 +21,8 @@ namespace Discord.Rest | |||||
public ushort DiscriminatorValue { get; private set; } | public ushort DiscriminatorValue { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string AvatarId { get; private set; } | public string AvatarId { get; private set; } | ||||
/// <inheritdoc /> | |||||
public UserProperties? PublicFlags { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); | ||||
@@ -65,6 +67,8 @@ namespace Discord.Rest | |||||
IsBot = model.Bot.Value; | IsBot = model.Bot.Value; | ||||
if (model.Username.IsSpecified) | if (model.Username.IsSpecified) | ||||
Username = model.Username.Value; | Username = model.Username.Value; | ||||
if (model.PublicFlags.IsSpecified) | |||||
PublicFlags = model.PublicFlags.Value; | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -75,13 +79,13 @@ namespace Discord.Rest | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Returns a direct message channel to this user, or create one if it does not already exist. | |||||
/// Creates a direct message channel to this user. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="options">The options to be used when sending the request.</param> | /// <param name="options">The options to be used when sending the request.</param> | ||||
/// <returns> | /// <returns> | ||||
/// A task that represents the asynchronous get operation. The task result contains a rest DM channel where the user is the recipient. | /// A task that represents the asynchronous get operation. The task result contains a rest DM channel where the user is the recipient. | ||||
/// </returns> | /// </returns> | ||||
public Task<RestDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null) | |||||
public Task<RestDMChannel> CreateDMChannelAsync(RequestOptions options = null) | |||||
=> UserHelper.CreateDMChannelAsync(this, Discord, options); | => UserHelper.CreateDMChannelAsync(this, Discord, options); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -103,7 +107,7 @@ namespace Discord.Rest | |||||
//IUser | //IUser | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options) | |||||
=> await GetOrCreateDMChannelAsync(options).ConfigureAwait(false); | |||||
async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) | |||||
=> await CreateDMChannelAsync(options).ConfigureAwait(false); | |||||
} | } | ||||
} | } |
@@ -52,32 +52,42 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
string IGuildUser.Nickname => null; | string IGuildUser.Nickname => null; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
bool? IGuildUser.IsPending => null; | |||||
/// <inheritdoc /> | |||||
GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook; | GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook; | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
ChannelPermissions IGuildUser.GetPermissions(IGuildChannel channel) => Permissions.ToChannelPerms(channel, GuildPermissions.Webhook.RawValue); | ChannelPermissions IGuildUser.GetPermissions(IGuildChannel channel) => Permissions.ToChannelPerms(channel, GuildPermissions.Webhook.RawValue); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.KickAsync(string reason, RequestOptions options) => | |||||
Task IGuildUser.KickAsync(string reason, RequestOptions options) => | |||||
throw new NotSupportedException("Webhook users cannot be kicked."); | throw new NotSupportedException("Webhook users cannot be kicked."); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options) => | |||||
Task IGuildUser.ModifyAsync(Action<GuildUserProperties> func, RequestOptions options) => | |||||
throw new NotSupportedException("Webhook users cannot be modified."); | throw new NotSupportedException("Webhook users cannot be modified."); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options) => | |||||
Task IGuildUser.AddRoleAsync(ulong role, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | throw new NotSupportedException("Roles are not supported on webhook users."); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options) => | |||||
Task IGuildUser.AddRoleAsync(IRole role, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | throw new NotSupportedException("Roles are not supported on webhook users."); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options) => | |||||
Task IGuildUser.AddRolesAsync(IEnumerable<ulong> roles, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | |||||
/// <inheritdoc /> | |||||
Task IGuildUser.AddRolesAsync(IEnumerable<IRole> roles, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | |||||
/// <inheritdoc /> | |||||
Task IGuildUser.RemoveRoleAsync(ulong role, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | |||||
/// <inheritdoc /> | |||||
Task IGuildUser.RemoveRoleAsync(IRole role, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | |||||
/// <inheritdoc /> | |||||
Task IGuildUser.RemoveRolesAsync(IEnumerable<ulong> roles, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | throw new NotSupportedException("Roles are not supported on webhook users."); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options) => | |||||
Task IGuildUser.RemoveRolesAsync(IEnumerable<IRole> roles, RequestOptions options) => | |||||
throw new NotSupportedException("Roles are not supported on webhook users."); | throw new NotSupportedException("Roles are not supported on webhook users."); | ||||
//IVoiceState | //IVoiceState | ||||
@@ -73,16 +73,16 @@ namespace Discord.Rest | |||||
return RestDMChannel.Create(client, await client.ApiClient.CreateDMChannelAsync(args, options).ConfigureAwait(false)); | return RestDMChannel.Create(client, await client.ApiClient.CreateDMChannelAsync(args, options).ConfigureAwait(false)); | ||||
} | } | ||||
public static async Task AddRolesAsync(IGuildUser user, BaseDiscordClient client, IEnumerable<IRole> roles, RequestOptions options) | |||||
public static async Task AddRolesAsync(IGuildUser user, BaseDiscordClient client, IEnumerable<ulong> roleIds, RequestOptions options) | |||||
{ | { | ||||
foreach (var role in roles) | |||||
await client.ApiClient.AddRoleAsync(user.Guild.Id, user.Id, role.Id, options).ConfigureAwait(false); | |||||
foreach (var roleId in roleIds) | |||||
await client.ApiClient.AddRoleAsync(user.Guild.Id, user.Id, roleId, options).ConfigureAwait(false); | |||||
} | } | ||||
public static async Task RemoveRolesAsync(IGuildUser user, BaseDiscordClient client, IEnumerable<IRole> roles, RequestOptions options) | |||||
public static async Task RemoveRolesAsync(IGuildUser user, BaseDiscordClient client, IEnumerable<ulong> roleIds, RequestOptions options) | |||||
{ | { | ||||
foreach (var role in roles) | |||||
await client.ApiClient.RemoveRoleAsync(user.Guild.Id, user.Id, role.Id, options).ConfigureAwait(false); | |||||
foreach (var roleId in roleIds) | |||||
await client.ApiClient.RemoveRoleAsync(user.Guild.Id, user.Id, roleId, options).ConfigureAwait(false); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -11,11 +11,11 @@ namespace Discord.Rest | |||||
internal IGuild Guild { get; private set; } | internal IGuild Guild { get; private set; } | ||||
internal ITextChannel Channel { get; private set; } | internal ITextChannel Channel { get; private set; } | ||||
/// <inheritdoc /> | |||||
public ulong ChannelId { get; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string Token { get; } | public string Token { get; } | ||||
/// <inheritdoc /> | |||||
public ulong ChannelId { get; private set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public string Name { get; private set; } | public string Name { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -56,6 +56,8 @@ namespace Discord.Rest | |||||
internal void Update(Model model) | internal void Update(Model model) | ||||
{ | { | ||||
if (ChannelId != model.ChannelId) | |||||
ChannelId = model.ChannelId; | |||||
if (model.Avatar.IsSpecified) | if (model.Avatar.IsSpecified) | ||||
AvatarId = model.Avatar.Value; | AvatarId = model.Avatar.Value; | ||||
if (model.Creator.IsSpecified) | if (model.Creator.IsSpecified) | ||||
@@ -34,6 +34,13 @@ namespace Discord.Rest | |||||
model.Thumbnail.IsSpecified ? model.Thumbnail.Value.ToEntity() : (EmbedThumbnail?)null, | model.Thumbnail.IsSpecified ? model.Thumbnail.Value.ToEntity() : (EmbedThumbnail?)null, | ||||
model.Fields.IsSpecified ? model.Fields.Value.Select(x => x.ToEntity()).ToImmutableArray() : ImmutableArray.Create<EmbedField>()); | 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) | public static API.Embed ToModel(this Embed entity) | ||||
{ | { | ||||
if (entity == null) return null; | if (entity == null) return null; | ||||
@@ -73,8 +73,6 @@ namespace Discord.Net.Converters | |||||
} | } | ||||
//Enums | //Enums | ||||
if (type == typeof(PermissionTarget)) | |||||
return PermissionTargetConverter.Instance; | |||||
if (type == typeof(UserStatus)) | if (type == typeof(UserStatus)) | ||||
return UserStatusConverter.Instance; | return UserStatusConverter.Instance; | ||||
if (type == typeof(EmbedType)) | if (type == typeof(EmbedType)) | ||||
@@ -1,44 +0,0 @@ | |||||
using Newtonsoft.Json; | |||||
using System; | |||||
namespace Discord.Net.Converters | |||||
{ | |||||
internal class PermissionTargetConverter : JsonConverter | |||||
{ | |||||
public static readonly PermissionTargetConverter Instance = new PermissionTargetConverter(); | |||||
public override bool CanConvert(Type objectType) => true; | |||||
public override bool CanRead => true; | |||||
public override bool CanWrite => true; | |||||
/// <exception cref="JsonSerializationException">Unknown permission target.</exception> | |||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |||||
{ | |||||
switch ((string)reader.Value) | |||||
{ | |||||
case "member": | |||||
return PermissionTarget.User; | |||||
case "role": | |||||
return PermissionTarget.Role; | |||||
default: | |||||
throw new JsonSerializationException("Unknown permission target."); | |||||
} | |||||
} | |||||
/// <exception cref="JsonSerializationException">Invalid permission target.</exception> | |||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |||||
{ | |||||
switch ((PermissionTarget)value) | |||||
{ | |||||
case PermissionTarget.User: | |||||
writer.WriteValue("member"); | |||||
break; | |||||
case PermissionTarget.Role: | |||||
writer.WriteValue("role"); | |||||
break; | |||||
default: | |||||
throw new JsonSerializationException("Invalid permission target."); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -17,8 +17,6 @@ namespace Discord.API.Gateway | |||||
public Optional<int[]> ShardingParams { get; set; } | public Optional<int[]> ShardingParams { get; set; } | ||||
[JsonProperty("presence")] | [JsonProperty("presence")] | ||||
public Optional<StatusUpdateParams> Presence { get; set; } | public Optional<StatusUpdateParams> Presence { get; set; } | ||||
[JsonProperty("guild_subscriptions")] | |||||
public Optional<bool> GuildSubscriptions { get; set; } | |||||
[JsonProperty("intents")] | [JsonProperty("intents")] | ||||
public Optional<int> Intents { get; set; } | public Optional<int> Intents { get; set; } | ||||
} | } | ||||