| @@ -336,7 +336,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(channelId: channelId); | |||
| return await SendAsync<Channel>("DELETE", () => $"channels/{channelId}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyGuildChannelParams args, RequestOptions options = null) | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, Rest.ModifyGuildChannelParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| @@ -347,7 +347,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(channelId: channelId); | |||
| return await SendJsonAsync<Channel>("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyTextChannelParams args, RequestOptions options = null) | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, Rest.ModifyTextChannelParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| @@ -358,11 +358,11 @@ namespace Discord.API | |||
| var ids = new BucketIds(channelId: channelId); | |||
| return await SendJsonAsync<Channel>("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, ModifyVoiceChannelParams args, RequestOptions options = null) | |||
| public async Task<Channel> ModifyGuildChannelAsync(ulong channelId, Rest.ModifyVoiceChannelParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(channelId, 0, nameof(channelId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate)); | |||
| Preconditions.GreaterThan(args.Bitrate, 8000, nameof(args.Bitrate)); | |||
| Preconditions.AtLeast(args.UserLimit, 0, nameof(args.Bitrate)); | |||
| Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); | |||
| Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); | |||
| @@ -371,7 +371,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(channelId: channelId); | |||
| return await SendJsonAsync<Channel>("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task ModifyGuildChannelsAsync(ulong guildId, IEnumerable<ModifyGuildChannelsParams> args, RequestOptions options = null) | |||
| public async Task ModifyGuildChannelsAsync(ulong guildId, IEnumerable<Rest.ModifyGuildChannelsParams> args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| @@ -383,7 +383,7 @@ namespace Discord.API | |||
| case 0: | |||
| return; | |||
| case 1: | |||
| await ModifyGuildChannelAsync(channels[0].Id, new ModifyGuildChannelParams { Position = channels[0].Position }).ConfigureAwait(false); | |||
| await ModifyGuildChannelAsync(channels[0].Id, new Rest.ModifyGuildChannelParams { Position = channels[0].Position }).ConfigureAwait(false); | |||
| break; | |||
| default: | |||
| var ids = new BucketIds(guildId: guildId); | |||
| @@ -700,7 +700,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(guildId: guildId); | |||
| return await SendAsync<Guild>("DELETE", () => $"users/@me/guilds/{guildId}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Guild> ModifyGuildAsync(ulong guildId, ModifyGuildParams args, RequestOptions options = null) | |||
| public async Task<Guild> ModifyGuildAsync(ulong guildId, Rest.ModifyGuildParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| @@ -778,7 +778,7 @@ namespace Discord.API | |||
| } | |||
| catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } | |||
| } | |||
| public async Task<GuildEmbed> ModifyGuildEmbedAsync(ulong guildId, ModifyGuildEmbedParams args, RequestOptions options = null) | |||
| public async Task<GuildEmbed> ModifyGuildEmbedAsync(ulong guildId, Rest.ModifyGuildEmbedParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| @@ -816,7 +816,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(guildId: guildId); | |||
| return await SendAsync<Integration>("DELETE", () => $"guilds/{guildId}/integrations/{integrationId}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Integration> ModifyGuildIntegrationAsync(ulong guildId, ulong integrationId, ModifyGuildIntegrationParams args, RequestOptions options = null) | |||
| public async Task<Integration> ModifyGuildIntegrationAsync(ulong guildId, ulong integrationId, Rest.ModifyGuildIntegrationParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotEqual(integrationId, 0, nameof(integrationId)); | |||
| @@ -939,7 +939,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(guildId: guildId); | |||
| await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task ModifyGuildMemberAsync(ulong guildId, ulong userId, ModifyGuildMemberParams args, RequestOptions options = null) | |||
| public async Task ModifyGuildMemberAsync(ulong guildId, ulong userId, Rest.ModifyGuildMemberParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotEqual(userId, 0, nameof(userId)); | |||
| @@ -950,7 +950,7 @@ namespace Discord.API | |||
| if (isCurrentUser && args.Nickname.IsSpecified) | |||
| { | |||
| var nickArgs = new ModifyCurrentUserNickParams(args.Nickname.Value ?? ""); | |||
| var nickArgs = new Rest.ModifyCurrentUserNickParams(args.Nickname.Value ?? ""); | |||
| await ModifyMyNickAsync(guildId, nickArgs).ConfigureAwait(false); | |||
| args.Nickname = Optional.Create<string>(); //Remove | |||
| } | |||
| @@ -987,7 +987,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(guildId: guildId); | |||
| await SendAsync("DELETE", () => $"guilds/{guildId}/roles/{roleId}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Role> ModifyGuildRoleAsync(ulong guildId, ulong roleId, ModifyGuildRoleParams args, RequestOptions options = null) | |||
| public async Task<Role> ModifyGuildRoleAsync(ulong guildId, ulong roleId, Rest.ModifyGuildRoleParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotEqual(roleId, 0, nameof(roleId)); | |||
| @@ -1000,7 +1000,7 @@ namespace Discord.API | |||
| var ids = new BucketIds(guildId: guildId); | |||
| return await SendJsonAsync<Role>("PATCH", () => $"guilds/{guildId}/roles/{roleId}", args, ids, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<IReadOnlyCollection<Role>> ModifyGuildRolesAsync(ulong guildId, IEnumerable<ModifyGuildRolesParams> args, RequestOptions options = null) | |||
| public async Task<IReadOnlyCollection<Role>> ModifyGuildRolesAsync(ulong guildId, IEnumerable<Rest.ModifyGuildRolesParams> args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| @@ -1058,7 +1058,7 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| return await SendAsync<Application>("GET", () => "oauth2/applications/@me", new BucketIds(), options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<User> ModifySelfAsync(ModifyCurrentUserParams args, RequestOptions options = null) | |||
| public async Task<User> ModifySelfAsync(Rest.ModifyCurrentUserParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| Preconditions.NotNullOrEmpty(args.Username, nameof(args.Username)); | |||
| @@ -1066,7 +1066,7 @@ namespace Discord.API | |||
| return await SendJsonAsync<User>("PATCH", () => "users/@me", args, new BucketIds(), options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task ModifyMyNickAsync(ulong guildId, ModifyCurrentUserNickParams args, RequestOptions options = null) | |||
| public async Task ModifyMyNickAsync(ulong guildId, Rest.ModifyCurrentUserNickParams args, RequestOptions options = null) | |||
| { | |||
| Preconditions.NotNull(args, nameof(args)); | |||
| Preconditions.NotNull(args.Nickname, nameof(args.Nickname)); | |||
| @@ -17,5 +17,17 @@ namespace Discord.API | |||
| Stream = null; | |||
| Hash = hash; | |||
| } | |||
| internal static Image Create(Discord.Image image) | |||
| { | |||
| return new Image(image.Stream); | |||
| } | |||
| internal static Image? Create(Discord.Image? image) | |||
| { | |||
| if (image.HasValue) | |||
| return new Image(image.Value.Stream); | |||
| else | |||
| return null; | |||
| } | |||
| } | |||
| } | |||
| @@ -9,6 +9,6 @@ namespace Discord.API.Rest | |||
| [JsonProperty("username")] | |||
| public Optional<string> Username { get; set; } | |||
| [JsonProperty("avatar")] | |||
| public Optional<Image> Avatar { get; set; } | |||
| public Optional<Image?> Avatar { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify an IGuildChannel with the specified changes. | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// await (Context.Channel as ITextChannel)?.ModifyAsync(x => | |||
| /// { | |||
| /// x.Name = "do-not-enter"; | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| public class ModifyGuildChannelParams | |||
| { | |||
| /// <summary> | |||
| /// Set the channel to this name | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// When modifying an ITextChannel, the Name MUST be alphanumeric with dashes. | |||
| /// It must match the following RegEx: [a-z0-9-_]{2,100} | |||
| /// </remarks> | |||
| /// <exception cref="Net.HttpException">A BadRequest will be thrown if the name does not match the above RegEx.</exception> | |||
| public Optional<string> Name { get; set; } | |||
| /// <summary> | |||
| /// Move the channel to the following position. This is 0-based! | |||
| /// </summary> | |||
| public Optional<int> Position { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| namespace Discord | |||
| { | |||
| public class ModifyGuildChannelsParams | |||
| { | |||
| /// <summary> | |||
| /// The id of the channel to apply this position to. | |||
| /// </summary> | |||
| public ulong Id { get; set; } | |||
| /// <summary> | |||
| /// The new zero-based position of this channel. | |||
| /// </summary> | |||
| public int Position { get; set; } | |||
| public ModifyGuildChannelsParams(ulong id, int position) | |||
| { | |||
| Id = id; | |||
| Position = position; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| namespace Discord | |||
| { | |||
| /// <inheritdoc /> | |||
| public class ModifyTextChannelParams : ModifyGuildChannelParams | |||
| { | |||
| /// <summary> | |||
| /// What the topic of the channel should be set to. | |||
| /// </summary> | |||
| public Optional<string> Topic { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| namespace Discord | |||
| { | |||
| /// <inheritdoc /> | |||
| public class ModifyVoiceChannelParams : ModifyGuildChannelParams | |||
| { | |||
| /// <summary> | |||
| /// The bitrate of the voice connections in this channel. Must be greater than 8000 | |||
| /// </summary> | |||
| public Optional<int> Bitrate { get; set; } | |||
| /// <summary> | |||
| /// The maximum number of users that can be present in a channel. | |||
| /// </summary> | |||
| public Optional<int> UserLimit { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify the widget of an IGuild with the specified parameters | |||
| /// </summary> | |||
| public class ModifyGuildEmbedParams | |||
| { | |||
| /// <summary> | |||
| /// Should the widget be enabled? | |||
| /// </summary> | |||
| public Optional<bool> Enabled { get; set; } | |||
| /// <summary> | |||
| /// What channel should the invite place users in, if not null. | |||
| /// </summary> | |||
| public Optional<IChannel> Channel { get; set; } | |||
| /// <summary> | |||
| /// What channel should the invite place users in, if not null. | |||
| /// </summary> | |||
| public Optional<ulong?> ChannelId { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| namespace Discord | |||
| { | |||
| public class ModifyGuildIntegrationParams | |||
| { | |||
| public Optional<int> ExpireBehavior { get; set; } | |||
| public Optional<int> ExpireGracePeriod { get; set; } | |||
| public Optional<bool> EnableEmoticons { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,71 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify an IGuild with the specified changes | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// await Context.Guild.ModifyAsync(async x => | |||
| /// { | |||
| /// x.Name = "aaaaaah"; | |||
| /// x.RegionId = (await Context.Client.GetOptimalVoiceRegionAsync()).Id; | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| /// <see cref="IGuild"/> | |||
| public class ModifyGuildParams | |||
| { | |||
| public Optional<string> Username { get; set; } | |||
| /// <summary> | |||
| /// The name of the Guild | |||
| /// </summary> | |||
| public Optional<string> Name { get; set; } | |||
| /// <summary> | |||
| /// The region for the Guild's voice connections | |||
| /// </summary> | |||
| public Optional<IVoiceRegion> Region { get; set; } | |||
| /// <summary> | |||
| /// The ID of the region for the Guild's voice connections | |||
| /// </summary> | |||
| public Optional<string> RegionId { get; set; } | |||
| /// <summary> | |||
| /// What verification level new users need to achieve before speaking | |||
| /// </summary> | |||
| public Optional<VerificationLevel> VerificationLevel { get; set; } | |||
| /// <summary> | |||
| /// The default message notification state for the guild | |||
| /// </summary> | |||
| public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; } | |||
| /// <summary> | |||
| /// How many seconds before a user is sent to AFK. This value MUST be one of: (60, 300, 900, 1800, 3600). | |||
| /// </summary> | |||
| public Optional<int> AfkTimeout { get; set; } | |||
| /// <summary> | |||
| /// The icon of the guild | |||
| /// </summary> | |||
| public Optional<Image?> Icon { get; set; } | |||
| /// <summary> | |||
| /// The guild's splash image | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// The guild must be partnered for this value to have any effect. | |||
| /// </remarks> | |||
| public Optional<Image?> Splash { get; set; } | |||
| /// <summary> | |||
| /// The IVoiceChannel where AFK users should be sent. | |||
| /// </summary> | |||
| public Optional<IVoiceChannel> AfkChannel { get; set; } | |||
| /// <summary> | |||
| /// The ID of the IVoiceChannel where AFK users should be sent. | |||
| /// </summary> | |||
| public Optional<ulong?> AfkChannelId { get; set; } | |||
| /// <summary> | |||
| /// The owner of this guild. | |||
| /// </summary> | |||
| public Optional<IUser> Owner { get; set; } | |||
| /// <summary> | |||
| /// The ID of the owner of this guild. | |||
| /// </summary> | |||
| public Optional<ulong> OwnerId { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| using System.IO; | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// An image that will be uploaded to Discord. | |||
| /// </summary> | |||
| public struct Image | |||
| { | |||
| public Stream Stream { get; } | |||
| /// <summary> | |||
| /// Create the image with a Stream. | |||
| /// </summary> | |||
| /// <param name="stream">This must be some type of stream with the contents of a file in it.</param> | |||
| /// <seealso cref="File.OpenRead(string)"/> | |||
| public Image(Stream stream) | |||
| { | |||
| Stream = stream; | |||
| } | |||
| #if NETSTANDARD1_3 | |||
| /// <summary> | |||
| /// Create the image from a file path. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/> | |||
| /// </remarks> | |||
| /// <param name="path">The path to the file.</param> | |||
| public Image(string path) | |||
| { | |||
| Stream = File.OpenRead(path); | |||
| } | |||
| #endif | |||
| } | |||
| } | |||
| @@ -5,7 +5,7 @@ using Field = Discord.API.EmbedField; | |||
| using Author = Discord.API.EmbedAuthor; | |||
| using Footer = Discord.API.EmbedFooter; | |||
| using Thumbnail = Discord.API.EmbedThumbnail; | |||
| using Image = Discord.API.EmbedImage; | |||
| using ImageEmbed = Discord.API.EmbedImage; | |||
| namespace Discord | |||
| { | |||
| @@ -110,7 +110,7 @@ namespace Discord | |||
| _model.Footer = Footer?.ToModel(); | |||
| _model.Timestamp = Timestamp?.ToUniversalTime(); | |||
| _model.Thumbnail = ThumbnailUrl != null ? new Thumbnail { Url = ThumbnailUrl } : null; | |||
| _model.Image = ImageUrl != null ? new Image { Url = ImageUrl } : null; | |||
| _model.Image = ImageUrl != null ? new ImageEmbed { Url = ImageUrl } : null; | |||
| _model.Fields = _fields.ToArray(); | |||
| return _model; | |||
| } | |||
| @@ -1,12 +1,37 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| namespace Discord | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify a message with the specified parameters. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// The content of a message can be cleared with String.Empty; if and only if an Embed is present. | |||
| /// </remarks> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// var message = await ReplyAsync("abc"); | |||
| /// await message.ModifyAsync(x => | |||
| /// { | |||
| /// x.Content = ""; | |||
| /// x.Embed = new EmbedBuilder() | |||
| /// .WithColor(new Color(40, 40, 120)) | |||
| /// .WithAuthor(a => a.Name = "foxbot") | |||
| /// .WithTitle("Embed!") | |||
| /// .WithDescription("This is an embed."); | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| public class ModifyMessageParams | |||
| { | |||
| /// <summary> | |||
| /// The content of the message | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// This must be less than 2000 characters. | |||
| /// </remarks> | |||
| public Optional<string> Content { get; set; } | |||
| /// <summary> | |||
| /// The embed the message should display | |||
| /// </summary> | |||
| public Optional<EmbedBuilder> Embed { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,51 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify an IRole with the specified parameters | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// await role.ModifyAsync(x => | |||
| /// { | |||
| /// x.Color = new Color(180, 15, 40); | |||
| /// x.Hoist = true; | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| /// <seealso cref="IRole"/> | |||
| public class ModifyGuildRoleParams | |||
| { | |||
| /// <summary> | |||
| /// The name of the role | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this role is the EveryoneRole, this value may not be set. | |||
| /// </remarks> | |||
| public Optional<string> Name { get; set; } | |||
| /// <summary> | |||
| /// The role's GuildPermissions | |||
| /// </summary> | |||
| public Optional<GuildPermissions> Permissions { get; set; } | |||
| /// <summary> | |||
| /// The position of the role. This is 0-based! | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this role is the EveryoneRole, this value may not be set. | |||
| /// </remarks> | |||
| public Optional<int> Position { get; set; } | |||
| /// <summary> | |||
| /// The color of the Role. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this role is the EveryoneRole, this value may not be set. | |||
| /// </remarks> | |||
| public Optional<Color> Color { get; set; } | |||
| /// <summary> | |||
| /// Whether or not this role should be displayed independently in the userlist. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this role is the EveryoneRole, this value may not be set. | |||
| /// </remarks> | |||
| public Optional<bool> Hoist { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| namespace Discord | |||
| { | |||
| public class ModifyGuildRolesParams : ModifyGuildRoleParams | |||
| { | |||
| /// <summary> | |||
| /// The id of the role to be edited | |||
| /// </summary> | |||
| public ulong Id { get; } | |||
| public ModifyGuildRolesParams(ulong id) | |||
| { | |||
| Id = id; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| namespace Discord | |||
| { | |||
| public class ModifyCurrentUserNickParams | |||
| { | |||
| public string Nickname { get; } | |||
| public ModifyCurrentUserNickParams(string nickname) | |||
| { | |||
| Nickname = nickname; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify the current user with the specified arguments | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// await Context.Client.CurrentUser.ModifyAsync(x => | |||
| /// { | |||
| /// x.Avatar = new Image(File.OpenRead("avatar.jpg")); | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| /// <seealso cref="ISelfUser"/> | |||
| public class ModifyCurrentUserParams | |||
| { | |||
| /// <summary> | |||
| /// Your username | |||
| /// </summary> | |||
| public Optional<string> Username { get; set; } | |||
| /// <summary> | |||
| /// Your avatar | |||
| /// </summary> | |||
| public Optional<Image> Avatar { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,64 @@ | |||
| using System.Collections.Generic; | |||
| namespace Discord | |||
| { | |||
| /// <summary> | |||
| /// Modify an IGuildUser with the following parameters. | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code language="c#"> | |||
| /// await (Context.User as IGuildUser)?.ModifyAsync(x => | |||
| /// { | |||
| /// x.Nickname = $"festive {Context.User.Username}"; | |||
| /// }); | |||
| /// </code> | |||
| /// </example> | |||
| /// <seealso cref="IGuildUser"/> | |||
| public class ModifyGuildMemberParams | |||
| { | |||
| /// <summary> | |||
| /// Should the user be guild-muted in a voice channel? | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this value is set to true, no user will be able to hear this user speak in the guild. | |||
| /// </remarks> | |||
| public Optional<bool> Mute { get; set; } | |||
| /// <summary> | |||
| /// Should the user be guild-deafened in a voice channel? | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// If this value is set to true, this user will not be able to hear anyone speak in the guild. | |||
| /// </remarks> | |||
| public Optional<bool> Deaf { get; set; } | |||
| /// <summary> | |||
| /// Should the user have a nickname set? | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// To clear the user's nickname, this value can be set to null. | |||
| /// </remarks> | |||
| public Optional<string> Nickname { get; set; } | |||
| /// <summary> | |||
| /// What roles should the user have? | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// To add a role to a user: <see cref="GuildUserExtensions.AddRolesAsync(IGuildUser, IRole[])"/> | |||
| /// To remove a role from a user: <see cref="GuildUserExtensions.RemoveRolesAsync(IGuildUser, IRole[])"/> | |||
| /// </remarks> | |||
| public Optional<IEnumerable<IRole>> Roles { get; set; } | |||
| /// <summary> | |||
| /// What roles should the user have? | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// To add a role to a user: <see cref="GuildUserExtensions.AddRolesAsync(IGuildUser, IRole[])"/> | |||
| /// To remove a role from a user: <see cref="GuildUserExtensions.RemoveRolesAsync(IGuildUser, IRole[])"/> | |||
| /// </remarks> | |||
| public Optional<IEnumerable<ulong>> RoleIds { get; set; } | |||
| /// <summary> | |||
| /// Move a user to a voice channel. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// This user MUST already be in a Voice Channel for this to work. | |||
| /// </remarks> | |||
| public Optional<IVoiceChannel> Channel { get; set; } | |||
| } | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| using Discord.API; | |||
| using Newtonsoft.Json; | |||
| using System; | |||
| using Model = Discord.API.Image; | |||
| namespace Discord.Net.Converters | |||
| { | |||
| @@ -19,7 +20,7 @@ namespace Discord.Net.Converters | |||
| public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |||
| { | |||
| var image = (Image)value; | |||
| var image = (Model)value; | |||
| if (image.Stream != null) | |||
| { | |||
| @@ -1,4 +1,5 @@ | |||
| using System; | |||
| using System.Linq; | |||
| namespace Discord | |||
| { | |||
| @@ -24,7 +24,12 @@ namespace Discord.Rest | |||
| { | |||
| var args = new ModifyGuildChannelParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyGuildChannelParams | |||
| { | |||
| Name = args.Name, | |||
| Position = args.Position | |||
| }; | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task<Model> ModifyAsync(ITextChannel channel, BaseDiscordClient client, | |||
| Action<ModifyTextChannelParams> func, | |||
| @@ -32,7 +37,13 @@ namespace Discord.Rest | |||
| { | |||
| var args = new ModifyTextChannelParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyTextChannelParams | |||
| { | |||
| Name = args.Name, | |||
| Position = args.Position, | |||
| Topic = args.Topic | |||
| }; | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task<Model> ModifyAsync(IVoiceChannel channel, BaseDiscordClient client, | |||
| Action<ModifyVoiceChannelParams> func, | |||
| @@ -40,7 +51,14 @@ namespace Discord.Rest | |||
| { | |||
| var args = new ModifyVoiceChannelParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyVoiceChannelParams | |||
| { | |||
| Bitrate = args.Bitrate, | |||
| Name = args.Name, | |||
| Position = args.Position, | |||
| UserLimit = args.UserLimit | |||
| }; | |||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| //Invites | |||
| @@ -7,6 +7,7 @@ using System.Threading.Tasks; | |||
| using EmbedModel = Discord.API.GuildEmbed; | |||
| using Model = Discord.API.Guild; | |||
| using RoleModel = Discord.API.Role; | |||
| using ImageModel = Discord.API.Image; | |||
| namespace Discord.Rest | |||
| { | |||
| @@ -21,12 +22,39 @@ namespace Discord.Rest | |||
| var args = new ModifyGuildParams(); | |||
| func(args); | |||
| if (args.Splash.IsSpecified && guild.SplashId != null) | |||
| args.Splash = new API.Image(guild.SplashId); | |||
| if (args.Icon.IsSpecified && guild.IconId != null) | |||
| args.Icon = new API.Image(guild.IconId); | |||
| var apiArgs = new API.Rest.ModifyGuildParams | |||
| { | |||
| AfkChannelId = args.AfkChannelId, | |||
| AfkTimeout = args.AfkTimeout, | |||
| DefaultMessageNotifications = args.DefaultMessageNotifications, | |||
| Icon = args.Icon.IsSpecified ? ImageModel.Create(args.Icon.Value) : Optional.Create<ImageModel?>(), | |||
| Name = args.Name, | |||
| Splash = args.Splash.IsSpecified ? ImageModel.Create(args.Splash.Value) : Optional.Create<ImageModel?>(), | |||
| Username = args.Username, | |||
| VerificationLevel = args.VerificationLevel | |||
| }; | |||
| if (args.AfkChannel.IsSpecified) | |||
| apiArgs.AfkChannelId = args.AfkChannel.Value.Id; | |||
| else if (args.AfkChannelId.IsSpecified) | |||
| apiArgs.AfkChannelId = args.AfkChannelId.Value; | |||
| if (args.Owner.IsSpecified) | |||
| apiArgs.OwnerId = args.Owner.Value.Id; | |||
| else if (args.OwnerId.IsSpecified) | |||
| apiArgs.OwnerId = args.OwnerId.Value; | |||
| return await client.ApiClient.ModifyGuildAsync(guild.Id, args, options).ConfigureAwait(false); | |||
| if (args.Region.IsSpecified) | |||
| apiArgs.RegionId = args.Region.Value.Id; | |||
| else if (args.RegionId.IsSpecified) | |||
| apiArgs.RegionId = args.RegionId.Value; | |||
| if (!apiArgs.Splash.IsSpecified && guild.SplashId != null) | |||
| apiArgs.Splash = new ImageModel(guild.SplashId); | |||
| if (!apiArgs.Icon.IsSpecified && guild.IconId != null) | |||
| apiArgs.Icon = new ImageModel(guild.IconId); | |||
| return await client.ApiClient.ModifyGuildAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task<EmbedModel> ModifyEmbedAsync(IGuild guild, BaseDiscordClient client, | |||
| Action<ModifyGuildEmbedParams> func, RequestOptions options) | |||
| @@ -35,44 +63,63 @@ namespace Discord.Rest | |||
| var args = new ModifyGuildEmbedParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifyGuildEmbedAsync(guild.Id, args, options).ConfigureAwait(false); | |||
| 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); | |||
| } | |||
| public static async Task ModifyChannelsAsync(IGuild guild, BaseDiscordClient client, | |||
| IEnumerable<ModifyGuildChannelsParams> args, RequestOptions options) | |||
| { | |||
| await client.ApiClient.ModifyGuildChannelsAsync(guild.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = args.Select(x => new API.Rest.ModifyGuildChannelsParams(x.Id, x.Position)); | |||
| await client.ApiClient.ModifyGuildChannelsAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task<IReadOnlyCollection<RoleModel>> ModifyRolesAsync(IGuild guild, BaseDiscordClient client, | |||
| IEnumerable<ModifyGuildRolesParams> args, RequestOptions options) | |||
| { | |||
| return await client.ApiClient.ModifyGuildRolesAsync(guild.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = args.Select(x => new API.Rest.ModifyGuildRolesParams(x.Id) | |||
| { | |||
| Color = x.Color.IsSpecified ? x.Color.Value.RawValue : Optional.Create<uint>(), | |||
| Hoist = x.Hoist, | |||
| Name = x.Name, | |||
| Permissions = x.Permissions.IsSpecified ? x.Permissions.Value.RawValue : Optional.Create<ulong>(), | |||
| Position = x.Position | |||
| }); | |||
| return await client.ApiClient.ModifyGuildRolesAsync(guild.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task LeaveAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task LeaveAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| await client.ApiClient.LeaveGuildAsync(guild.Id, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task DeleteAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task DeleteAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| await client.ApiClient.DeleteGuildAsync(guild.Id, options).ConfigureAwait(false); | |||
| } | |||
| //Bans | |||
| public static async Task<IReadOnlyCollection<RestBan>> GetBansAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task<IReadOnlyCollection<RestBan>> GetBansAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| var models = await client.ApiClient.GetGuildBansAsync(guild.Id, options).ConfigureAwait(false); | |||
| return models.Select(x => RestBan.Create(client, x)).ToImmutableArray(); | |||
| } | |||
| public static async Task AddBanAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task AddBanAsync(IGuild guild, BaseDiscordClient client, | |||
| ulong userId, int pruneDays, RequestOptions options) | |||
| { | |||
| var args = new CreateGuildBanParams { DeleteMessageDays = pruneDays }; | |||
| await client.ApiClient.CreateGuildBanAsync(guild.Id, userId, args, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task RemoveBanAsync(IGuild guild, BaseDiscordClient client, | |||
| } | |||
| public static async Task RemoveBanAsync(IGuild guild, BaseDiscordClient client, | |||
| ulong userId, RequestOptions options) | |||
| { | |||
| await client.ApiClient.RemoveGuildBanAsync(guild.Id, userId, options).ConfigureAwait(false); | |||
| @@ -87,7 +134,7 @@ namespace Discord.Rest | |||
| return RestGuildChannel.Create(client, guild, model); | |||
| return null; | |||
| } | |||
| public static async Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| var models = await client.ApiClient.GetGuildChannelsAsync(guild.Id, options).ConfigureAwait(false); | |||
| @@ -113,7 +160,7 @@ namespace Discord.Rest | |||
| } | |||
| //Integrations | |||
| public static async Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task<IReadOnlyCollection<RestGuildIntegration>> GetIntegrationsAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| var models = await client.ApiClient.GetGuildIntegrationsAsync(guild.Id, options).ConfigureAwait(false); | |||
| @@ -128,7 +175,7 @@ namespace Discord.Rest | |||
| } | |||
| //Invites | |||
| public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| var models = await client.ApiClient.GetGuildInvitesAsync(guild.Id, options).ConfigureAwait(false); | |||
| @@ -147,8 +194,8 @@ namespace Discord.Rest | |||
| await role.ModifyAsync(x => | |||
| { | |||
| x.Name = name; | |||
| x.Permissions = (permissions ?? role.Permissions).RawValue; | |||
| x.Color = (color ?? Color.Default).RawValue; | |||
| x.Permissions = (permissions ?? role.Permissions); | |||
| x.Color = (color ?? Color.Default); | |||
| x.Hoist = isHoisted; | |||
| }, options).ConfigureAwait(false); | |||
| @@ -164,7 +211,7 @@ namespace Discord.Rest | |||
| return RestGuildUser.Create(client, guild, model); | |||
| return null; | |||
| } | |||
| public static async Task<RestGuildUser> GetCurrentUserAsync(IGuild guild, BaseDiscordClient client, | |||
| public static async Task<RestGuildUser> GetCurrentUserAsync(IGuild guild, BaseDiscordClient client, | |||
| RequestOptions options) | |||
| { | |||
| return await GetUserAsync(guild, client, client.CurrentUser.Id, options).ConfigureAwait(false); | |||
| @@ -61,7 +61,13 @@ namespace Discord.Rest | |||
| var args = new ModifyGuildIntegrationParams(); | |||
| func(args); | |||
| var model = await Discord.ApiClient.ModifyGuildIntegrationAsync(GuildId, Id, args).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyGuildIntegrationParams | |||
| { | |||
| EnableEmoticons = args.EnableEmoticons, | |||
| ExpireBehavior = args.ExpireBehavior, | |||
| ExpireGracePeriod = args.ExpireGracePeriod | |||
| }; | |||
| var model = await Discord.ApiClient.ModifyGuildIntegrationAsync(GuildId, Id, apiArgs).ConfigureAwait(false); | |||
| Update(model); | |||
| } | |||
| @@ -18,7 +18,15 @@ namespace Discord.Rest | |||
| { | |||
| var args = new ModifyGuildRoleParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyGuildRoleParams | |||
| { | |||
| Color = args.Color.IsSpecified ? args.Color.Value.RawValue : Optional.Create<uint>(), | |||
| Hoist = args.Hoist, | |||
| Name = args.Name, | |||
| Permissions = args.Permissions.IsSpecified ? args.Permissions.Value.RawValue : Optional.Create<ulong>(), | |||
| Position = args.Position | |||
| }; | |||
| return await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| } | |||
| } | |||
| @@ -3,6 +3,7 @@ using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.GuildMember; | |||
| @@ -30,7 +31,7 @@ namespace Discord.Rest | |||
| } | |||
| } | |||
| public IReadOnlyCollection<ulong> RoleIds => _roleIds; | |||
| public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); | |||
| internal RestGuildUser(BaseDiscordClient discord, IGuild guild, ulong id) | |||
| @@ -61,21 +62,25 @@ namespace Discord.Rest | |||
| roles.Add(roleIds[i]); | |||
| _roleIds = roles.ToImmutable(); | |||
| } | |||
| public override async Task UpdateAsync(RequestOptions options = null) | |||
| { | |||
| var model = await Discord.ApiClient.GetGuildMemberAsync(GuildId, Id, options).ConfigureAwait(false); | |||
| Update(model); | |||
| } | |||
| public async Task ModifyAsync(Action<ModifyGuildMemberParams> func, RequestOptions options = null) | |||
| { | |||
| { | |||
| var args = await UserHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); | |||
| if (args.Deaf.IsSpecified) | |||
| IsDeafened = args.Deaf.Value; | |||
| if (args.Mute.IsSpecified) | |||
| IsMuted = args.Mute.Value; | |||
| if (args.RoleIds.IsSpecified) | |||
| UpdateRoles(args.RoleIds.Value); | |||
| if (args.Nickname.IsSpecified) | |||
| Nickname = args.Nickname.Value; | |||
| if (args.Roles.IsSpecified) | |||
| UpdateRoles(args.Roles.Value.Select(x => x.Id).ToArray()); | |||
| else if (args.RoleIds.IsSpecified) | |||
| UpdateRoles(args.RoleIds.Value.ToArray()); | |||
| } | |||
| public Task KickAsync(RequestOptions options = null) | |||
| => UserHelper.KickAsync(this, Discord, options); | |||
| @@ -2,6 +2,8 @@ | |||
| using System; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.User; | |||
| using ImageModel = Discord.API.Image; | |||
| using System.Linq; | |||
| namespace Discord.Rest | |||
| { | |||
| @@ -12,14 +14,36 @@ namespace Discord.Rest | |||
| { | |||
| var args = new ModifyCurrentUserParams(); | |||
| func(args); | |||
| return await client.ApiClient.ModifySelfAsync(args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyCurrentUserParams | |||
| { | |||
| Avatar = args.Avatar.IsSpecified ? ImageModel.Create(args.Avatar.Value) : Optional.Create<ImageModel?>(), | |||
| Username = args.Username | |||
| }; | |||
| if (!apiArgs.Avatar.IsSpecified && user.AvatarId != null) | |||
| apiArgs.Avatar = new ImageModel(user.AvatarId); | |||
| return await client.ApiClient.ModifySelfAsync(apiArgs, options).ConfigureAwait(false); | |||
| } | |||
| public static async Task<ModifyGuildMemberParams> ModifyAsync(IGuildUser user, BaseDiscordClient client, Action<ModifyGuildMemberParams> func, | |||
| RequestOptions options) | |||
| { | |||
| var args = new ModifyGuildMemberParams(); | |||
| func(args); | |||
| await client.ApiClient.ModifyGuildMemberAsync(user.GuildId, user.Id, args, options).ConfigureAwait(false); | |||
| var apiArgs = new API.Rest.ModifyGuildMemberParams | |||
| { | |||
| ChannelId = args.Channel.IsSpecified ? args.Channel.Value.Id : Optional.Create<ulong>(), | |||
| Deaf = args.Deaf, | |||
| Mute = args.Mute, | |||
| Nickname = args.Nickname | |||
| }; | |||
| if (args.Roles.IsSpecified) | |||
| apiArgs.RoleIds = args.Roles.Value.Select(x => x.Id).ToArray(); | |||
| else if (args.RoleIds.IsSpecified) | |||
| apiArgs.RoleIds = args.RoleIds.Value.ToArray(); | |||
| await client.ApiClient.ModifyGuildMemberAsync(user.GuildId, user.Id, apiArgs, options).ConfigureAwait(false); | |||
| return args; | |||
| } | |||