diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 2c9503db1..d8072f94f 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -12,7 +12,7 @@ namespace Discord /// Gets the parent (category) ID of this channel in the guild's channel list. /// /// - /// A representing the snowflake identifier of the parent of this channel; + /// A representing the snowflake identifier of the parent of this channel; /// null if none is set. /// ulong? CategoryId { get; } @@ -56,6 +56,50 @@ namespace Discord /// metadata object containing information for the created invite. /// Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the embedded application to open for this invite + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the user whose stream to display for this invite + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToStreamAsync(IUser user, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); /// /// Gets a collection of all invites to this channel. /// B diff --git a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs index 74263b888..e1818d7a9 100644 --- a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs +++ b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs @@ -9,6 +9,10 @@ namespace Discord /// /// The invite is for a Go Live stream. /// - Stream = 1 + Stream = 1, + /// + /// The invite is for embedded application. + /// + EmbeddedApplication = 2 } } diff --git a/src/Discord.Net.Core/Entities/Teams/ITeam.cs b/src/Discord.Net.Core/Entities/Teams/ITeam.cs index 5ef3e4253..b6e3d987b 100644 --- a/src/Discord.Net.Core/Entities/Teams/ITeam.cs +++ b/src/Discord.Net.Core/Entities/Teams/ITeam.cs @@ -20,6 +20,10 @@ namespace Discord /// IReadOnlyList TeamMembers { get; } /// + /// Gets the name of this team. + /// + string Name { get; } + /// /// Gets the user identifier that owns this team. /// ulong OwnerUserId { get; } diff --git a/src/Discord.Net.Rest/API/Common/Team.cs b/src/Discord.Net.Rest/API/Common/Team.cs index 4910f43f7..852368522 100644 --- a/src/Discord.Net.Rest/API/Common/Team.cs +++ b/src/Discord.Net.Rest/API/Common/Team.cs @@ -11,6 +11,8 @@ namespace Discord.API public ulong Id { get; set; } [JsonProperty("members")] public TeamMember[] TeamMembers { get; set; } + [JsonProperty("name")] + public string Name { get; set; } [JsonProperty("owner_user_id")] public ulong OwnerUserId { get; set; } } diff --git a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs index db79bc314..06a47f1a8 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs @@ -14,5 +14,11 @@ namespace Discord.API.Rest public Optional IsTemporary { get; set; } [JsonProperty("unique")] public Optional IsUnique { get; set; } + [JsonProperty("target_type")] + public Optional TargetType { get; set; } + [JsonProperty("target_user_id")] + public Optional TargetUserId { get; set; } + [JsonProperty("target_application_id")] + public Optional TargetApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 115e3baa5..36259b01a 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1294,6 +1294,12 @@ namespace Discord.API Preconditions.AtLeast(args.MaxUses, 0, nameof(args.MaxUses)); Preconditions.AtMost(args.MaxAge, 86400, nameof(args.MaxAge), "The maximum age of an invite must be less than or equal to a day (86400 seconds)."); + if (args.TargetType.IsSpecified) + { + Preconditions.NotEqual((int)args.TargetType.Value, (int)TargetUserType.Undefined, nameof(args.TargetType)); + if (args.TargetType.Value == TargetUserType.Stream) Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId)); + if (args.TargetType.Value == TargetUserType.EmbeddedApplication) Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId)); + } options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(channelId: channelId); diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index f52174675..f69c010f2 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -120,6 +120,54 @@ namespace Discord.Rest return RestInviteMetadata.Create(client, null, channel, model); } + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToStreamAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, IUser user, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.Stream, + TargetUserId = user.Id + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToApplicationAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, ulong applicationId, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.EmbeddedApplication, + TargetApplicationId = applicationId + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + //Messages public static async Task GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, ulong id, RequestOptions options) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index 800ee1d8d..f12977d62 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -17,7 +17,7 @@ namespace Discord.Rest /// public string Topic { get; private set; } /// - public virtual int SlowModeInterval { get; private set; } + public virtual int SlowModeInterval { get; private set; } /// public ulong? CategoryId { get; private set; } @@ -78,7 +78,7 @@ namespace Discord.Rest /// /// /// A paged collection containing a collection of guild users that can access this channel. Flattening the - /// paginated response into a collection of users with + /// paginated response into a collection of users with /// is required if you wish to access the users. /// public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) @@ -215,6 +215,10 @@ namespace Discord.Rest /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 3f3aa96c6..b551c7f8f 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -60,12 +60,18 @@ namespace Discord.Rest /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); - + //Invites /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs b/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs index 2343f8b5d..43c9417cc 100644 --- a/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs +++ b/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs @@ -12,6 +12,8 @@ namespace Discord.Rest /// public IReadOnlyList TeamMembers { get; private set; } /// + public string Name { get; private set; } + /// public ulong OwnerUserId { get; private set; } private string _iconId; @@ -30,6 +32,7 @@ namespace Discord.Rest { if (model.Icon.IsSpecified) _iconId = model.Icon.Value; + Name = model.Name; OwnerUserId = model.OwnerUserId; TeamMembers = model.TeamMembers.Select(x => new RestTeamMember(Discord, x)).ToImmutableArray(); } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index c0badd557..de896be81 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -258,6 +258,12 @@ namespace Discord.WebSocket public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index bf4a63c9f..7dded5fa2 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -90,6 +90,12 @@ namespace Discord.WebSocket public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs index 6cfdc83b2..da21afee1 100644 --- a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs +++ b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs @@ -126,7 +126,7 @@ namespace Discord { IEnumerable GetInvalid() { - yield return new string('a', 2049); + yield return new string('a', 4097); } foreach (var description in GetInvalid()) { @@ -149,7 +149,7 @@ namespace Discord { yield return string.Empty; yield return null; - yield return new string('a', 2048); + yield return new string('a', 4096); } foreach (var description in GetValid()) { diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs index b01fac3b0..0bde9d1e0 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs @@ -46,6 +46,10 @@ namespace Discord { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) { diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs index eb617125d..7c3d00fdd 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs @@ -47,6 +47,10 @@ namespace Discord { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task DeleteAsync(RequestOptions options = null) {