* Mark guild as optional for invite * Mark partial InviteMetadata members as Optional<T> * Some of them aren't sent when requesting through the general GET invite endpoint * Remove GetInviteParams * It was kinda stupid in the first place, might as well always get the count instead of having to ask the user whether they want the two fields filled or not. * Add ChannelType property * Add vanity invite supportpull/1103/head
@@ -120,6 +120,15 @@ namespace Discord | |||||
/// <summary> Gets a collection of all invites to this guild. </summary> | /// <summary> Gets a collection of all invites to this guild. </summary> | ||||
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | ||||
/// <summary> | |||||
/// Gets the vanity invite URL of this guild. | |||||
/// </summary> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// An awaitable <see cref="Task"/> containing the partial metadata of the vanity invite found within | |||||
/// this guild. | |||||
/// </returns> | |||||
Task<IInviteMetadata> GetVanityInviteAsync(RequestOptions options = null); | |||||
/// <summary> Gets the role in this guild with the provided id, or null if not found. </summary> | /// <summary> Gets the role in this guild with the provided id, or null if not found. </summary> | ||||
IRole GetRole(ulong id); | IRole GetRole(ulong id); | ||||
@@ -1,5 +1,3 @@ | |||||
using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
public interface IInvite : IEntity<string>, IDeletable | public interface IInvite : IEntity<string>, IDeletable | ||||
@@ -11,6 +9,8 @@ namespace Discord | |||||
/// <summary> Gets the channel this invite is linked to. </summary> | /// <summary> Gets the channel this invite is linked to. </summary> | ||||
IChannel Channel { get; } | IChannel Channel { get; } | ||||
/// <summary> Gets the type of the channel this invite is linked to. </summary> | |||||
ChannelType ChannelType { get; } | |||||
/// <summary> Gets the id of the channel this invite is linked to. </summary> | /// <summary> Gets the id of the channel this invite is linked to. </summary> | ||||
ulong ChannelId { get; } | ulong ChannelId { get; } | ||||
/// <summary> Gets the name of the channel this invite is linked to. </summary> | /// <summary> Gets the name of the channel this invite is linked to. </summary> | ||||
@@ -19,7 +19,7 @@ namespace Discord | |||||
/// <summary> Gets the guild this invite is linked to. </summary> | /// <summary> Gets the guild this invite is linked to. </summary> | ||||
IGuild Guild { get; } | IGuild Guild { get; } | ||||
/// <summary> Gets the id of the guild this invite is linked to. </summary> | /// <summary> Gets the id of the guild this invite is linked to. </summary> | ||||
ulong GuildId { get; } | |||||
ulong? GuildId { get; } | |||||
/// <summary> Gets the name of the guild this invite is linked to. </summary> | /// <summary> Gets the name of the guild this invite is linked to. </summary> | ||||
string GuildName { get; } | string GuildName { get; } | ||||
/// <summary> Gets the approximated count of online members in the guild. </summary> | /// <summary> Gets the approximated count of online members in the guild. </summary> | ||||
@@ -1,4 +1,4 @@ | |||||
using System; | |||||
using System; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -15,8 +15,8 @@ namespace Discord | |||||
/// <summary> Gets the max amount of times this invite may be used, or null if there is no limit. </summary> | /// <summary> Gets the max amount of times this invite may be used, or null if there is no limit. </summary> | ||||
int? MaxUses { get; } | int? MaxUses { get; } | ||||
/// <summary> Gets the amount of times this invite has been used. </summary> | /// <summary> Gets the amount of times this invite has been used. </summary> | ||||
int Uses { get; } | |||||
int? Uses { get; } | |||||
/// <summary> Gets when this invite was created. </summary> | /// <summary> Gets when this invite was created. </summary> | ||||
DateTimeOffset CreatedAt { get; } | |||||
DateTimeOffset? CreatedAt { get; } | |||||
} | } | ||||
} | |||||
} |
@@ -8,7 +8,7 @@ namespace Discord.API | |||||
[JsonProperty("code")] | [JsonProperty("code")] | ||||
public string Code { get; set; } | public string Code { get; set; } | ||||
[JsonProperty("guild")] | [JsonProperty("guild")] | ||||
public 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("approximate_presence_count")] | [JsonProperty("approximate_presence_count")] | ||||
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API | namespace Discord.API | ||||
@@ -10,6 +10,6 @@ namespace Discord.API | |||||
[JsonProperty("name")] | [JsonProperty("name")] | ||||
public string Name { get; set; } | public string Name { get; set; } | ||||
[JsonProperty("type")] | [JsonProperty("type")] | ||||
public string Type { get; set; } | |||||
public int Type { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System; | using System; | ||||
@@ -9,15 +9,15 @@ namespace Discord.API | |||||
[JsonProperty("inviter")] | [JsonProperty("inviter")] | ||||
public User Inviter { get; set; } | public User Inviter { get; set; } | ||||
[JsonProperty("uses")] | [JsonProperty("uses")] | ||||
public int Uses { get; set; } | |||||
public Optional<int> Uses { get; set; } | |||||
[JsonProperty("max_uses")] | [JsonProperty("max_uses")] | ||||
public int MaxUses { get; set; } | |||||
public Optional<int> MaxUses { get; set; } | |||||
[JsonProperty("max_age")] | [JsonProperty("max_age")] | ||||
public int MaxAge { get; set; } | |||||
public Optional<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 DateTimeOffset CreatedAt { get; set; } | |||||
public Optional<DateTimeOffset> CreatedAt { get; set; } | |||||
[JsonProperty("revoked")] | [JsonProperty("revoked")] | ||||
public bool Revoked { get; set; } | public bool Revoked { get; set; } | ||||
} | } | ||||
@@ -1,7 +0,0 @@ | |||||
namespace Discord.API.Rest | |||||
{ | |||||
internal class GetInviteParams | |||||
{ | |||||
public Optional<bool?> WithCounts { get; set; } | |||||
} | |||||
} |
@@ -51,13 +51,9 @@ namespace Discord.Rest | |||||
} | } | ||||
public static async Task<RestInviteMetadata> GetInviteAsync(BaseDiscordClient client, | public static async Task<RestInviteMetadata> GetInviteAsync(BaseDiscordClient client, | ||||
string inviteId, bool withCount, RequestOptions options) | |||||
string inviteId, RequestOptions options) | |||||
{ | { | ||||
var args = new GetInviteParams | |||||
{ | |||||
WithCounts = withCount | |||||
}; | |||||
var model = await client.ApiClient.GetInviteAsync(inviteId, args, options).ConfigureAwait(false); | |||||
var model = await client.ApiClient.GetInviteAsync(inviteId, options).ConfigureAwait(false); | |||||
if (model != null) | if (model != null) | ||||
return RestInviteMetadata.Create(client, null, null, model); | return RestInviteMetadata.Create(client, null, null, model); | ||||
return null; | return null; | ||||
@@ -906,7 +906,7 @@ namespace Discord.API | |||||
} | } | ||||
//Guild Invites | //Guild Invites | ||||
public async Task<InviteMetadata> GetInviteAsync(string inviteId, GetInviteParams args, RequestOptions options = null) | |||||
public async Task<InviteMetadata> GetInviteAsync(string inviteId, RequestOptions options = null) | |||||
{ | { | ||||
Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); | Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); | ||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
@@ -919,14 +919,20 @@ namespace Discord.API | |||||
if (index >= 0) | if (index >= 0) | ||||
inviteId = inviteId.Substring(index + 1); | inviteId = inviteId.Substring(index + 1); | ||||
var withCounts = args.WithCounts.GetValueOrDefault(false); | |||||
try | try | ||||
{ | { | ||||
return await SendAsync<InviteMetadata>("GET", () => $"invites/{inviteId}?with_counts={withCounts}", new BucketIds(), options: options).ConfigureAwait(false); | |||||
return await SendAsync<InviteMetadata>("GET", () => $"invites/{inviteId}?with_counts=true", new BucketIds(), options: options).ConfigureAwait(false); | |||||
} | } | ||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } | catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } | ||||
} | } | ||||
public async Task<InviteMetadata> GetVanityInviteAsync(ulong guildId, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(guildId: guildId); | |||||
return await SendAsync<InviteMetadata>("GET", () => $"guilds/{guildId}/vanity-url", ids, options: options).ConfigureAwait(false); | |||||
} | |||||
public async Task<IReadOnlyCollection<InviteMetadata>> GetGuildInvitesAsync(ulong guildId, RequestOptions options = null) | public async Task<IReadOnlyCollection<InviteMetadata>> GetGuildInvitesAsync(ulong guildId, RequestOptions options = null) | ||||
{ | { | ||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | Preconditions.NotEqual(guildId, 0, nameof(guildId)); | ||||
@@ -57,7 +57,7 @@ namespace Discord.Rest | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task<RestInviteMetadata> GetInviteAsync(string inviteId, bool withCount = false, RequestOptions options = null) | public Task<RestInviteMetadata> GetInviteAsync(string inviteId, bool withCount = false, RequestOptions options = null) | ||||
=> ClientHelper.GetInviteAsync(this, inviteId, withCount, options); | |||||
=> ClientHelper.GetInviteAsync(this, inviteId, options); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task<RestGuild> GetGuildAsync(ulong id, RequestOptions options = null) | public Task<RestGuild> GetGuildAsync(ulong id, RequestOptions options = null) | ||||
@@ -210,6 +210,12 @@ namespace Discord.Rest | |||||
var models = await client.ApiClient.GetGuildInvitesAsync(guild.Id, options).ConfigureAwait(false); | var models = await client.ApiClient.GetGuildInvitesAsync(guild.Id, options).ConfigureAwait(false); | ||||
return models.Select(x => RestInviteMetadata.Create(client, guild, null, x)).ToImmutableArray(); | return models.Select(x => RestInviteMetadata.Create(client, guild, null, x)).ToImmutableArray(); | ||||
} | } | ||||
public static async Task<RestInviteMetadata> GetVanityInviteAsync(IGuild guild, BaseDiscordClient client, | |||||
RequestOptions options) | |||||
{ | |||||
var model = await client.ApiClient.GetVanityInviteAsync(guild.Id, options).ConfigureAwait(false); | |||||
return RestInviteMetadata.Create(client, guild, null, model); | |||||
} | |||||
//Roles | //Roles | ||||
public static async Task<RestRole> CreateRoleAsync(IGuild guild, BaseDiscordClient client, | public static async Task<RestRole> CreateRoleAsync(IGuild guild, BaseDiscordClient client, | ||||
@@ -238,6 +238,15 @@ namespace Discord.Rest | |||||
//Invites | //Invites | ||||
public Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | ||||
=> GuildHelper.GetInvitesAsync(this, Discord, options); | => GuildHelper.GetInvitesAsync(this, Discord, options); | ||||
/// <summary> | |||||
/// Gets the vanity invite URL of this guild. | |||||
/// </summary> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A partial metadata of the vanity invite found within this guild. | |||||
/// </returns> | |||||
public Task<RestInviteMetadata> GetVanityInviteAsync(RequestOptions options = null) | |||||
=> GuildHelper.GetVanityInviteAsync(this, Discord, options); | |||||
//Roles | //Roles | ||||
public RestRole GetRole(ulong id) | public RestRole GetRole(ulong id) | ||||
@@ -397,6 +406,9 @@ namespace Discord.Rest | |||||
async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | ||||
=> await GetInvitesAsync(options).ConfigureAwait(false); | => await GetInvitesAsync(options).ConfigureAwait(false); | ||||
/// <inheritdoc /> | |||||
async Task<IInviteMetadata> IGuild.GetVanityInviteAsync(RequestOptions options) | |||||
=> await GetVanityInviteAsync(options).ConfigureAwait(false); | |||||
IRole IGuild.GetRole(ulong id) | IRole IGuild.GetRole(ulong id) | ||||
=> GetRole(id); | => GetRole(id); | ||||
@@ -1,7 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Discord.API.Rest; | |||||
using Model = Discord.API.Invite; | using Model = Discord.API.Invite; | ||||
namespace Discord.Rest | namespace Discord.Rest | ||||
@@ -9,14 +8,15 @@ namespace Discord.Rest | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RestInvite : RestEntity<string>, IInvite, IUpdateable | public class RestInvite : RestEntity<string>, IInvite, IUpdateable | ||||
{ | { | ||||
public ChannelType ChannelType { get; private set; } | |||||
public string ChannelName { get; private set; } | public string ChannelName { get; private set; } | ||||
public string GuildName { get; private set; } | public string GuildName { get; private set; } | ||||
public int? PresenceCount { get; private set; } | public int? PresenceCount { get; private set; } | ||||
public int? MemberCount { get; private set; } | public int? MemberCount { get; private set; } | ||||
public ulong ChannelId { get; private set; } | public ulong ChannelId { get; private set; } | ||||
public ulong GuildId { get; private set; } | |||||
internal IChannel Channel { get; private set; } | |||||
internal IGuild Guild { get; private set; } | |||||
public ulong? GuildId { get; private set; } | |||||
internal IChannel Channel { get; } | |||||
internal IGuild Guild { get; } | |||||
public string Code => Id; | public string Code => Id; | ||||
public string Url => $"{DiscordConfig.InviteUrl}{Code}"; | public string Url => $"{DiscordConfig.InviteUrl}{Code}"; | ||||
@@ -35,20 +35,18 @@ namespace Discord.Rest | |||||
} | } | ||||
internal void Update(Model model) | internal void Update(Model model) | ||||
{ | { | ||||
GuildId = model.Guild.Id; | |||||
GuildId = model.Guild.IsSpecified ? model.Guild.Value.Id : default(ulong?); | |||||
ChannelId = model.Channel.Id; | ChannelId = model.Channel.Id; | ||||
GuildName = model.Guild.Name; | |||||
GuildName = model.Guild.IsSpecified ? model.Guild.Value.Name : null; | |||||
ChannelName = model.Channel.Name; | ChannelName = model.Channel.Name; | ||||
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; | |||||
} | } | ||||
public async Task UpdateAsync(RequestOptions options = null) | public async Task UpdateAsync(RequestOptions options = null) | ||||
{ | { | ||||
var args = new GetInviteParams(); | |||||
if (MemberCount != null || PresenceCount != null) | |||||
args.WithCounts = true; | |||||
var model = await Discord.ApiClient.GetInviteAsync(Code, args, options).ConfigureAwait(false); | |||||
var model = await Discord.ApiClient.GetInviteAsync(Code, options).ConfigureAwait(false); | |||||
Update(model); | Update(model); | ||||
} | } | ||||
public Task DeleteAsync(RequestOptions options = null) | public Task DeleteAsync(RequestOptions options = null) | ||||
@@ -1,20 +1,20 @@ | |||||
using System; | |||||
using System; | |||||
using Model = Discord.API.InviteMetadata; | using Model = Discord.API.InviteMetadata; | ||||
namespace Discord.Rest | namespace Discord.Rest | ||||
{ | { | ||||
public class RestInviteMetadata : RestInvite, IInviteMetadata | public class RestInviteMetadata : RestInvite, IInviteMetadata | ||||
{ | { | ||||
private long _createdAtTicks; | |||||
private long? _createdAtTicks; | |||||
public bool IsRevoked { get; private set; } | public bool IsRevoked { get; private set; } | ||||
public bool IsTemporary { get; private set; } | public bool IsTemporary { get; private set; } | ||||
public int? MaxAge { get; private set; } | public int? MaxAge { get; private set; } | ||||
public int? MaxUses { get; private set; } | public int? MaxUses { get; private set; } | ||||
public int Uses { get; private set; } | |||||
public int? Uses { get; private set; } | |||||
public RestUser Inviter { get; private set; } | public RestUser Inviter { get; private set; } | ||||
public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); | |||||
public DateTimeOffset? CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); | |||||
internal RestInviteMetadata(BaseDiscordClient discord, IGuild guild, IChannel channel, string id) | internal RestInviteMetadata(BaseDiscordClient discord, IGuild guild, IChannel channel, string id) | ||||
: base(discord, guild, channel, id) | : base(discord, guild, channel, id) | ||||
@@ -32,10 +32,10 @@ namespace Discord.Rest | |||||
Inviter = model.Inviter != null ? RestUser.Create(Discord, model.Inviter) : null; | Inviter = model.Inviter != null ? RestUser.Create(Discord, model.Inviter) : null; | ||||
IsRevoked = model.Revoked; | IsRevoked = model.Revoked; | ||||
IsTemporary = model.Temporary; | IsTemporary = model.Temporary; | ||||
MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null; | |||||
MaxUses = model.MaxUses; | |||||
Uses = model.Uses; | |||||
_createdAtTicks = model.CreatedAt.UtcTicks; | |||||
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; | |||||
} | } | ||||
IUser IInviteMetadata.Inviter => Inviter; | IUser IInviteMetadata.Inviter => Inviter; | ||||
@@ -56,7 +56,7 @@ namespace Discord.WebSocket | |||||
=> ClientHelper.GetConnectionsAsync(this, options ?? RequestOptions.Default); | => ClientHelper.GetConnectionsAsync(this, options ?? RequestOptions.Default); | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task<RestInviteMetadata> GetInviteAsync(string inviteId, bool withCount = false, RequestOptions options = null) | public Task<RestInviteMetadata> GetInviteAsync(string inviteId, bool withCount = false, RequestOptions options = null) | ||||
=> ClientHelper.GetInviteAsync(this, inviteId, withCount, options ?? RequestOptions.Default); | |||||
=> ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); | |||||
// IDiscordClient | // IDiscordClient | ||||
async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) | async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) | ||||
@@ -345,6 +345,15 @@ namespace Discord.WebSocket | |||||
//Invites | //Invites | ||||
public Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | ||||
=> GuildHelper.GetInvitesAsync(this, Discord, options); | => GuildHelper.GetInvitesAsync(this, Discord, options); | ||||
/// <summary> | |||||
/// Gets the vanity invite URL of this guild. | |||||
/// </summary> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// A partial metadata of the vanity invite found within this guild. | |||||
/// </returns> | |||||
public Task<RestInviteMetadata> GetVanityInviteAsync(RequestOptions options = null) | |||||
=> GuildHelper.GetVanityInviteAsync(this, Discord, options); | |||||
//Roles | //Roles | ||||
public SocketRole GetRole(ulong id) | public SocketRole GetRole(ulong id) | ||||
@@ -700,6 +709,9 @@ namespace Discord.WebSocket | |||||
async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | ||||
=> await GetInvitesAsync(options).ConfigureAwait(false); | => await GetInvitesAsync(options).ConfigureAwait(false); | ||||
/// <inheritdoc /> | |||||
async Task<IInviteMetadata> IGuild.GetVanityInviteAsync(RequestOptions options) | |||||
=> await GetVanityInviteAsync(options).ConfigureAwait(false); | |||||
IRole IGuild.GetRole(ulong id) | IRole IGuild.GetRole(ulong id) | ||||
=> GetRole(id); | => GetRole(id); | ||||