Browse Source

feature: Webhook message edit & delete functionality (#1753)

* feature: Webhook message edit & delete functionality

* PR fixes: Rename Edit* to Modify*; Add more detailed docstrings; Small validation fixes

* Fix spacing around docstrings

* Make ModifyWebhookMessageParams.Content Optional<string>

* Change the Webhook message edit functionality to use a object delegate method instead providing the all parameters

Co-authored-by: Desmont <desmont@users.noreply.github.com>
tags/2.4.0
Desmont GitHub 4 years ago
parent
commit
f67cd8ea55
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 161 additions and 1 deletions
  1. +16
    -0
      src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs
  2. +37
    -0
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  3. +29
    -0
      src/Discord.Net.Webhook/DiscordWebhookClient.cs
  4. +26
    -0
      src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs
  5. +53
    -1
      src/Discord.Net.Webhook/WebhookClientHelper.cs

+ 16
- 0
src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs View File

@@ -0,0 +1,16 @@
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
internal class ModifyWebhookMessageParams
{
[JsonProperty("content")]
public Optional<string> Content { get; set; }
[JsonProperty("embeds")]
public Optional<Embed[]> Embeds { get; set; }
[JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; }
}
}

+ 37
- 0
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -523,6 +523,43 @@ namespace Discord.API
var ids = new BucketIds(webhookId: webhookId);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");

Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(webhookId, 0, nameof(webhookId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));

if (args.Embeds.IsSpecified)
Preconditions.AtMost(args.Embeds.Value.Length, 10, nameof(args.Embeds), "A max of 10 Embeds are allowed.");
if (args.Content.IsSpecified && args.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
}

/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null)
{
if (AuthTokenType != TokenType.Webhook)
throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token.");

Preconditions.NotEqual(webhookId, 0, nameof(webhookId));
Preconditions.NotEqual(messageId, 0, nameof(messageId));

options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", ids, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null)
{


+ 29
- 0
src/Discord.Net.Webhook/DiscordWebhookClient.cs View File

@@ -91,6 +91,35 @@ namespace Discord.Webhook
string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null)
=> WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options);

/// <summary>
/// Modifies a message posted using this webhook.
/// </summary>
/// <remarks>
/// This method can only modify messages that were sent using the same webhook.
/// </remarks>
/// <param name="messageId">ID of the modified message.</param>
/// <param name="func">A delegate containing the properties to modify the message with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties> func, RequestOptions options = null)
=> WebhookClientHelper.ModifyMessageAsync(this, messageId, func, options);

/// <summary>
/// Deletes a message posted using this webhook.
/// </summary>
/// <remarks>
/// This method can only delete messages that were sent using the same webhook.
/// </remarks>
/// <param name="messageId">ID of the deleted message.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous deletion operation.
/// </returns>
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> WebhookClientHelper.DeleteMessageAsync(this, messageId, options);

/// <summary> Sends a message to the channel for this webhook with an attachment. </summary>
/// <returns> Returns the ID of the created message. </returns>
public Task<ulong> SendFileAsync(string filePath, string text, bool isTTS = false,


+ 26
- 0
src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;

namespace Discord.Webhook
{
/// <summary>
/// Properties that are used to modify an Webhook message with the specified changes.
/// </summary>
public class WebhookMessageProperties
{
/// <summary>
/// Gets or sets the content of the message.
/// </summary>
/// <remarks>
/// This must be less than the constant defined by <see cref="DiscordConfig.MaxMessageSize"/>.
/// </remarks>
public Optional<string> Content { get; set; }
/// <summary>
/// Gets or sets the embed array that the message should display.
/// </summary>
public Optional<IEnumerable<Embed>> Embeds { get; set; }
/// <summary>
/// Gets or sets the allowed mentions of the message.
/// </summary>
public Optional<AllowedMentions> AllowedMentions { get; set; }
}
}

+ 53
- 1
src/Discord.Net.Webhook/WebhookClientHelper.cs View File

@@ -36,7 +36,59 @@ namespace Discord.Webhook
var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false);
return model.Id;
}
public static async Task<ulong> SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS,
public static async Task ModifyMessageAsync(DiscordWebhookClient client, ulong messageId,
Action<WebhookMessageProperties> func, RequestOptions options)
{
var args = new WebhookMessageProperties();
func(args);

if (args.AllowedMentions.IsSpecified)
{
var allowedMentions = args.AllowedMentions.Value;
Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds),
"A max of 100 role Ids are allowed.");
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds),
"A max of 100 user Ids are allowed.");

// check that user flag and user Id list are exclusive, same with role flag and role Id list
if (allowedMentions?.AllowedTypes != null)
{
if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) &&
allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0)
{
throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.",
nameof(allowedMentions));
}

if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) &&
allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0)
{
throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.",
nameof(allowedMentions));
}
}
}

var apiArgs = new ModifyWebhookMessageParams
{
Content = args.Content.IsSpecified ? args.Content.Value : Optional.Create<string>(),
Embeds =
args.Embeds.IsSpecified
? args.Embeds.Value.Select(embed => embed.ToModel()).ToArray()
: Optional.Create<API.Embed[]>(),
AllowedMentions = args.AllowedMentions.IsSpecified
? args.AllowedMentions.Value.ToModel()
: Optional.Create<API.AllowedMentions>()
};

await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options)
.ConfigureAwait(false);
}
public static async Task DeleteMessageAsync(DiscordWebhookClient client, ulong messageId, RequestOptions options)
{
await client.ApiClient.DeleteWebhookMessageAsync(client.Webhook.Id, messageId, options).ConfigureAwait(false);
}
public static async Task<ulong> SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS,
IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler)
{
string filename = Path.GetFileName(filePath);


Loading…
Cancel
Save