/// <summary> /// Modifies an existing webhook. /// </summary> /// <exception cref="ArgumentException">Thrown if the token is empty or only contains whitespace characters.</exception> /// <exception cref="ArgumentNullException">Thrown if token is null.</exception> /// <exception cref="DiscordHttpApiException"></exception> public async Task ModifyWebhookWithToken(Snowflake webhookId, string token, string name = null, DiscordImageData avatar = null) { if (token == null) { throw new ArgumentNullException(nameof(token)); } if (string.IsNullOrWhiteSpace(token)) { throw new ArgumentException("Token cannot be empty or only contain whitespace characters.", nameof(token)); } DiscordApiData postData = DiscordApiData.CreateContainer(); if (name != null) { postData.Set("name", name); } if (avatar != null) { postData.Set("avatar", avatar); } await rest.Patch($"webhooks/{webhookId}/{token}", postData, $"webhooks/{webhookId}/token").ConfigureAwait(false); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("content", Content); data.Set("tts", TextToSpeech); data.SetSnowflake("nonce", Nonce); if (Embed != null) { data.Set("embed", Embed.Build()); } if (AllowedMentions != null) { data.Set("allowed_mentions", AllowedMentions.Build()); } if (MessageReference != null) { data.Set("message_reference", MessageReference.Build()); } return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Name != null) { data.Set("name", Name); } if (Position.HasValue) { data.Set("position", Position.Value); } if (PermissionOverwrites != null) { DiscordApiData permissionOverwritesArray = new DiscordApiData(DiscordApiDataType.Array); foreach (OverwriteOptions overwriteParam in PermissionOverwrites) { permissionOverwritesArray.Values.Add(overwriteParam.Build()); } data.Set("permission_overwrites", permissionOverwritesArray); } return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Nickname != null) { data.Set("nick", Nickname); } if (IsServerMute.HasValue) { data.Set("mute", IsServerMute); } if (IsServerDeaf.HasValue) { data.Set("deaf", IsServerDeaf); } if (ChannelId.HasValue) { data.SetSnowflake("channel_id", ChannelId); } if (RoleIds != null) { DiscordApiData rolesArray = new DiscordApiData(DiscordApiDataType.Array); foreach (Snowflake roleId in RoleIds) { rolesArray.Values.Add(new DiscordApiData(roleId)); } data.Set("roles", rolesArray); } return(data); }
/// <summary> /// Edits an existing message in a text channel. /// <para>Note: only messages created by the current bot can be edited.</para> /// </summary> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="DiscordHttpApiException"></exception> public async Task <DiscordMessage> EditMessage(Snowflake channelId, Snowflake messageId, EditMessageOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } DiscordApiData requestData = new DiscordApiData(DiscordApiDataType.Container); requestData.Set("content", options.Content); if (options.Embed != null) { requestData.Set("embed", options.Embed.Build()); } if (options.AllowedMentions != null) { requestData.Set("allowed_mentions", options.AllowedMentions.Build()); } if (options.Flags != null) { requestData.Set("flags", (int)options.Flags); } DiscordApiData returnData = await rest.Patch($"channels/{channelId}/messages/{messageId}", requestData, $"channels/{channelId}/messages/message").ConfigureAwait(false); return(new DiscordMessage(this, returnData)); }
/// <summary> /// Creates a new invite for the specified guild channel. /// <para>Requires <see cref="DiscordPermission.CreateInstantInvite"/>.</para> /// </summary> /// <param name="channelId">The ID of the guild channel.</param> /// <param name="maxAge">The duration of invite before expiry, or 0 or null for never.</param> /// <param name="maxUses">The max number of uses or 0 or null for unlimited.</param> /// <param name="temporary">Whether this invite only grants temporary membership.</param> /// <param name="unique"> /// If true, don't try to reuse a similar invite /// (useful for creating many unique one time use invites). /// </param> /// <exception cref="DiscordHttpApiException"></exception> public async Task <DiscordInvite> CreateChannelInvite(Snowflake channelId, TimeSpan?maxAge = null, int?maxUses = null, bool?temporary = null, bool?unique = null) { DiscordApiData requestData = new DiscordApiData(DiscordApiDataType.Container); if (maxAge.HasValue) { requestData.Set("max_age", maxAge.Value.Seconds); } if (maxUses.HasValue) { requestData.Set("max_uses", maxUses.Value); } if (temporary.HasValue) { requestData.Set("temporary", temporary.Value); } if (unique.HasValue) { requestData.Set("unique", unique.Value); } DiscordApiData returnData = await rest.Post($"channels/{channelId}/invites", requestData, $"channels/{channelId}/invites").ConfigureAwait(false); return(new DiscordInvite(this, returnData)); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Name != null) { data.Set("name", Name); } if (Permissions.HasValue) { data.Set("permissions", (long)Permissions.Value); } if (Color.HasValue) { data.Set("color", Color.Value.ToHexadecimal()); } if (IsHoisted.HasValue) { data.Set("hoist", IsHoisted); } if (IsMentionable.HasValue) { data.Set("mentionable", IsMentionable); } return(data); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public async Task SendIdentifyPayload(string token, int largeThreshold, int shardId, int totalShards) { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("token", token); data.Set("compress", true); data.Set("large_threshold", largeThreshold); if (totalShards > 1) { DiscordApiData shardData = new DiscordApiData(DiscordApiDataType.Array); shardData.Values.Add(new DiscordApiData(shardId)); shardData.Values.Add(new DiscordApiData(totalShards)); data.Set("shard", shardData); } DiscordApiData props = data.Set("properties", new DiscordApiData(DiscordApiDataType.Container)); props.Set("$os", RuntimeInformation.OSDescription); props.Set("$browser", "discore"); props.Set("$device", "discore"); log.LogVerbose("[Identify] Sending payload..."); // Make sure we don't send IDENTIFY's too quickly await identifyRateLimiter.Invoke(CancellationToken.None).ConfigureAwait(false); // Send IDENTIFY await SendPayload(GatewayOPCode.Identify, data).ConfigureAwait(false); }
/// <summary> /// Begins a member prune operation, /// kicking every member that has been offline for the specified number of days. /// <para>Requires <see cref="DiscordPermission.KickMembers"/>.</para> /// </summary> /// <param name="days">The number of days to prune (1-30).</param> /// <param name="includeRoles"> /// By default, prune will not remove users with roles. You can optionally include specific /// roles in your prune by providing the <paramref name="includeRoles"/> parameter. Any inactive /// user that has a subset of the provided role(s) will be counted in the prune and users with /// additional roles will not. /// </param> /// <param name="computePruneCount"> /// For large guilds it's recommended to set this to false. When false, this method will always return 0. /// </param> /// <exception cref="DiscordHttpApiException"></exception> public async Task <int> BeginGuildPrune( Snowflake guildId, int?days = null, IEnumerable <Snowflake> includeRoles = null, bool?computePruneCount = null) { DiscordApiData requestData = new DiscordApiData(DiscordApiDataType.Container); if (days != null) { requestData.Set("days", days); } if (includeRoles != null) { requestData.Set("include_roles", includeRoles.Select(r => r.ToString()).ToArray()); } if (computePruneCount != null) { requestData.Set("compute_prune_count", computePruneCount.Value); } DiscordApiData data = await rest.Post($"guilds/{guildId}/prune", requestData, $"guilds/{guildId}/prune").ConfigureAwait(false); return(data.GetInteger("pruned") ?? 0); }
internal virtual DiscordApiData Build() { DiscordApiData data = new DiscordApiData(); data.Set("name", Name); if (Permissions.HasValue) { data.Set("permissions", (int)Permissions.Value); } if (Color.HasValue) { data.Set("color", Color.Value.ToHexadecimal()); } if (IsHoisted.HasValue) { data.Set("hoist", IsHoisted); } if (IsMentionable.HasValue) { data.Set("mentionable", IsMentionable); } return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (UsernameOverride != null) { data.Set("username", UsernameOverride); } if (AvatarUrl != null) { data.Set("avatar_url", AvatarUrl); } if (TextToSpeech.HasValue) { data.Set("tts", TextToSpeech.Value); } if (Content != null) { data.Set("content", Content); } if (Embeds != null) { DiscordApiData embedArray = new DiscordApiData(DiscordApiDataType.Array); foreach (EmbedOptions builder in Embeds) { embedArray.Values.Add(builder.Build()); } data.Set("embeds", embedArray); } return(data); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> /// <exception cref="JsonWriterException">Thrown if the given data cannot be serialized as JSON.</exception> Task SendPayload(VoiceOPCode op, DiscordApiData data) { DiscordApiData payload = new DiscordApiData(); payload.Set("op", (int)op); payload.Set("d", data); return(SendAsync(payload)); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("name", Name); data.Set("image", Image.ToDataUriScheme()); return(data); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendSpeakingPayload(bool speaking, int ssrc) { DiscordApiData data = new DiscordApiData(); data.Set("speaking", speaking); data.Set("delay", value: 0); data.Set("ssrc", ssrc); return(SendPayload(VoiceOPCode.Speaking, data)); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendRequestGuildMembersPayload(Snowflake guildId, string query, int limit) { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.SetSnowflake("guild_id", guildId); data.Set("query", query); data.Set("limit", limit); return(SendPayload(GatewayOPCode.RequestGuildMembers, data)); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("expire_behavior", ExpireBehavior); data.Set("expire_grace_period", ExpireGracePeriod); data.Set("enable_emoticons", EnableEmoticons); return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.SetSnowflake("id", Id); data.Set("type", Type.ToString().ToLower()); data.Set("allow", (int)Allow); data.Set("deny", (int)Deny); return(data); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendResumePayload(Snowflake serverId, string sessionId, string token) { DiscordApiData data = new DiscordApiData(); data.SetSnowflake("server_id", serverId); data.Set("session_id", sessionId); data.Set("token", token); log.LogVerbose("[Resume] Sending payload..."); return(SendPayload(VoiceOPCode.Resume, data)); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendVoiceStateUpdatePayload(Snowflake guildId, Snowflake?channelId, bool isMute, bool isDeaf) { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.SetSnowflake("guild_id", guildId); data.SetSnowflake("channel_id", channelId); data.Set("self_mute", isMute); data.Set("self_deaf", isDeaf); return(SendPayload(GatewayOPCode.VoiceStateUpdate, data)); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendResumePayload(string token, string sessionId, int sequence) { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("token", token); data.Set("session_id", sessionId); data.Set("seq", sequence); log.LogVerbose("[Resume] Sending payload..."); return(SendPayload(GatewayOPCode.Resume, data)); }
/// <summary> /// Edits a guild channel permission overwrite for a user or role. /// <para>Requires <see cref="DiscordPermission.ManageRoles"/>.</para> /// </summary> /// <exception cref="DiscordHttpApiException"></exception> public async Task EditChannelPermissions(Snowflake channelId, Snowflake overwriteId, DiscordPermission allow, DiscordPermission deny, DiscordOverwriteType type) { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("allow", (int)allow); data.Set("deny", (int)deny); data.Set("type", type.ToString().ToLower()); await rest.Put($"channels/{channelId}/permissions/{overwriteId}", data, $"channels/{channelId}/permissions/permission").ConfigureAwait(false); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> /// <exception cref="JsonWriterException">Thrown if the given data cannot be serialized as JSON.</exception> async Task SendPayload(GatewayOPCode op, DiscordApiData data) { DiscordApiData payload = new DiscordApiData(DiscordApiDataType.Container); payload.Set("op", (int)op); payload.Set("d", data); // Check with the payload rate limiter await outboundPayloadRateLimiter.Invoke().ConfigureAwait(false); // Send payload await SendAsync(payload).ConfigureAwait(false); }
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception> public Task SendSelectProtocolPayload(string ip, int port, string encryptionMode) { DiscordApiData selectProtocol = new DiscordApiData(); selectProtocol.Set("protocol", "udp"); DiscordApiData data = selectProtocol.Set("data", DiscordApiData.CreateContainer()); data.Set("address", ip); data.Set("port", port); data.Set("mode", encryptionMode); log.LogVerbose($"[SelectProtocol] Sending to {ip}:{port}..."); return(SendPayload(VoiceOPCode.SelectProtocol, selectProtocol)); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Text != null) { data.Set("text", Text); } if (IconUrl != null) { data.Set("icon_url", IconUrl); } return(data); }
/// <summary> /// Deletes a group of messages all at once from a text channel. /// This is much faster than calling DeleteMessage for each message. /// <para>Requires <see cref="DiscordPermission.ManageMessages"/>.</para> /// </summary> /// <param name="filterTooOldMessages">Whether to ignore deleting messages that are older than 2 weeks (this causes an API error).</param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="DiscordHttpApiException"></exception> public async Task BulkDeleteMessages(Snowflake channelId, IEnumerable <Snowflake> messageIds, bool filterTooOldMessages = true) { if (messageIds == null) { throw new ArgumentNullException(nameof(messageIds)); } DiscordApiData requestData = new DiscordApiData(DiscordApiDataType.Container); DiscordApiData messages = requestData.Set("messages", new DiscordApiData(DiscordApiDataType.Array)); ulong minimumAllowedSnowflake = 0; if (filterTooOldMessages) { // See https://github.com/hammerandchisel/discord-api-docs/issues/208 ulong secondsSinceUnixEpoch = (ulong)DateTimeOffset.Now.ToUnixTimeSeconds(); minimumAllowedSnowflake = (secondsSinceUnixEpoch - 14 * 24 * 60 * 60) * 1000 - 1420070400000L << 22; } foreach (Snowflake messageId in messageIds) { if (!filterTooOldMessages && messageId.Id < minimumAllowedSnowflake) { continue; } messages.Values.Add(new DiscordApiData(messageId)); } await rest.Post($"channels/{channelId}/messages/bulk-delete", requestData, $"channels/{channelId}/messages/message/delete/bulk").ConfigureAwait(false); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Name != null) { data.Set("name", Name); } if (Value != null) { data.Set("value", Value); } data.Set("inline", IsInline); return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.Set("enabled", Enabled); data.SetSnowflake("channel_id", ChannelId); return data; }
/// <summary> /// Modifies the current bot's user object. /// Parameters left null will leave the properties unchanged. /// </summary> /// <exception cref="DiscordHttpApiException"></exception> public async Task <DiscordUser> ModifyCurrentUser(string username = null, DiscordImageData avatar = null) { DiscordApiData requestData = new DiscordApiData(DiscordApiDataType.Container); if (username != null) { requestData.Set("username", username); } if (avatar != null) { requestData.Set("avatar", avatar.ToDataUriScheme()); } DiscordApiData returnData = await rest.Patch("users/@me", requestData, "users/@me").ConfigureAwait(false); return(returnData.IsNull ? null : new DiscordUser(false, returnData)); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); if (Name != null) { data.Set("name", Name); } if (Position.HasValue) { data.Set("position", Position.Value); } if (Topic != null) { data.Set("topic", Topic); } if (Nsfw.HasValue) { data.Set("nsfw", Nsfw.Value); } if (ParentId.HasValue) { if (ParentId.Value == Snowflake.None) { data.SetSnowflake("parent_id", null); } else { data.SetSnowflake("parent_id", ParentId.Value); } } if (PermissionOverwrites != null) { DiscordApiData permissionOverwritesArray = new DiscordApiData(DiscordApiDataType.Array); foreach (OverwriteOptions overwriteParam in PermissionOverwrites) { permissionOverwritesArray.Values.Add(overwriteParam.Build()); } data.Set("permission_overwrites", permissionOverwritesArray); } return(data); }
internal DiscordApiData Build() { DiscordApiData data = new DiscordApiData(DiscordApiDataType.Container); data.SetSnowflake("id", Id); data.Set("position", Position); return(data); }