Skip to content

Commit

Permalink
Added support for modifying template message
Browse files Browse the repository at this point in the history
  • Loading branch information
gehongyan committed Nov 12, 2024
1 parent c475ec6 commit 786162e
Show file tree
Hide file tree
Showing 18 changed files with 300 additions and 22 deletions.
23 changes: 20 additions & 3 deletions samples/Kook.Net.Samples.TextCommands/Modules/PublicModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,31 @@ public class PublicModule : ModuleBase<SocketCommandContext>
public Task PingAsync() =>
ReplyTextAsync("pong!");

[Command("template")]
public Task TemplateAsync() =>
ReplyCardsAsync(62419125, new
[Command("template", RunMode = RunMode.Async)]
public async Task TemplateAsync()
{
Cacheable<IUserMessage, Guid> msgInfo = await ReplyCardsAsync(62419125, new
{
guildname = "KOOK开发者中心",
username = "开发者",
roles = new[] { "role1", "role2", "role3" }
});
IUserMessage? msg = await msgInfo.GetOrDownloadAsync();
if (msg is not null)
{
await Task.Delay(TimeSpan.FromSeconds(1));
await msg.ModifyAsync(x =>
{
x.TemplateId = 62419125;
x.Parameters = new
{
guildname = "KOOK开发者中心111",
username = "开发者111",
roles = new[] { "role21", "role22", "role23" }
};
});
}
}

[Command("cat")]
public async Task CatAsync()
Expand Down
11 changes: 11 additions & 0 deletions src/Kook.Net.Core/Entities/Channels/IMessageChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,16 @@ IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage refere
/// <seealso cref="Kook.MessageProperties"/>
Task ModifyMessageAsync(Guid messageId, Action<MessageProperties> func, RequestOptions? options = null);

/// <summary>
/// 修改一条消息。
/// </summary>
/// <param name="messageId"> 要修改的消息的 ID。 </param>
/// <param name="func"> 一个包含修改消息属性的委托。 </param>
/// <param name="options"> 发送请求时要使用的选项。 </param>
/// <typeparam name="T"> 模板参数的类型。 </typeparam>
/// <returns> 一个表示异步修改操作的任务。 </returns>
/// <seealso cref="Kook.MessageProperties"/>
Task ModifyMessageAsync<T>(Guid messageId, Action<MessageProperties<T>> func, RequestOptions? options = null);

#endregion
}
10 changes: 10 additions & 0 deletions src/Kook.Net.Core/Entities/Messages/IUserMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ public interface IUserMessage : IMessage
/// <seealso cref="Kook.MessageProperties"/>
Task ModifyAsync(Action<MessageProperties> func, RequestOptions? options = null);

/// <summary>
/// 修改此消息。
/// </summary>
/// <param name="func"> 一个包含修改消息属性的委托。 </param>
/// <param name="options"> 发送请求时要使用的选项。 </param>
/// <typeparam name="T"> 消息的内容类型。 </typeparam>
/// <returns> 一个表示异步修改操作的任务。 </returns>
/// <seealso cref="Kook.MessageProperties"/>
Task ModifyAsync<T>(Action<MessageProperties<T>> func, RequestOptions? options = null);

/// <summary>
/// 转换消息文本中的提及与表情符号为可读形式。
/// </summary>
Expand Down
50 changes: 50 additions & 0 deletions src/Kook.Net.Core/Entities/Messages/MessageProperties.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Text.Json;

namespace Kook;

/// <summary>
Expand Down Expand Up @@ -41,4 +43,52 @@ public class MessageProperties
/// </note>
/// </remarks>
public IUser? EphemeralUser { get; set; }

/// <summary>
/// 获取或设置要为更新此消息生成内容时使用的模板的 ID。
/// </summary>
/// <remarks>
/// Kook.Net 无法通过网关或 API 获知消息是否使用了模板,无法获取消息的模板 ID。
/// 因此如果要让新编辑的内容也使用模板,请在修改消息时手动设置此属性,且应重新为此属性赋值,不要尝试直接修改此属性中的成员。
/// </remarks>
public int? TemplateId { get; set; }

/// <summary>
/// 获取或设置要为更新此消息生成内容时使用的模板参数。
/// </summary>
/// <remarks>
/// Kook.Net 无法通过网关或 API 获知消息是否使用了模板,无法获取消息的模板参数。
/// 因此在修改消息时,请重新为此属性赋值,不要尝试直接修改此属性中的成员。
/// </remarks>
public object? Parameters { get; set; }

/// <summary>
/// 获取或设置要为更新此消息序列化模板参数时使用的选项。
/// </summary>
/// <remarks>
/// Kook.Net 无法通过网关或 API 获知消息是否使用了模板,无法获取消息的模板参数。
/// 因此在修改消息时,请重新为此属性赋值,不要尝试直接修改此属性中的成员。
/// </remarks>
public JsonSerializerOptions? JsonSerializerOptions { get; set; }
}

/// <summary>
/// 提供用于修改 <see cref="Kook.IUserMessage"/> 的属性。
/// </summary>
/// <typeparam name="T"> 模板参数的类型。 </typeparam>
/// <seealso cref="Kook.IUserMessage.ModifyAsync{T}(System.Action{Kook.MessageProperties{T}},Kook.RequestOptions)"/>
public class MessageProperties<T> : MessageProperties
{
/// <summary>
/// 获取或设置要为更新此消息生成内容时使用的模板参数。
/// </summary>
/// <remarks>
/// Kook.Net 无法通过网关或 API 获知消息是否使用了模板,无法获取消息的模板参数。
/// 因此在修改消息时,请重新为此属性赋值,不要尝试直接修改此属性中的成员。
/// </remarks>
public new T? Parameters
{
get => (T?)base.Parameters;
set => base.Parameters = value;
}
}
15 changes: 15 additions & 0 deletions src/Kook.Net.Core/Utils/Preconditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ public static void NotNull<T>([NotNull] T? obj, string name, string? msg = null)
private static ArgumentNullException CreateNotNullException(string name, string? msg) =>
new(paramName: name, message: msg);

public static void EnsureMessageProperties<T>(MessageProperties<T> properties)
{
if (properties is null)
throw new ArgumentNullException(nameof(properties));
bool contentSet = !string.IsNullOrEmpty(properties.Content);
bool cardsSet = properties.Cards?.Count > 0;
bool templateSet = properties.TemplateId.HasValue;
if (contentSet && cardsSet)
throw new ArgumentException("Content and Cards cannot be set at the same time.");
if (!contentSet && !cardsSet && !templateSet)
throw new ArgumentException("If neither Content nor Cards are set, TemplateId must be set.");
if (templateSet && properties.Parameters is null)
throw new ArgumentException("When TemplateId is set, Parameters must also be set.");
}

#endregion

#region Strings
Expand Down
4 changes: 4 additions & 0 deletions src/Kook.Net.Rest/API/Rest/ModifyDirectMessageParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ internal class ModifyDirectMessageParams
[JsonPropertyName("msg_id")]
public required Guid MessageId { get; set; }

[JsonPropertyName("template_id")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? TemplateId { get; set; }

[JsonPropertyName("content")]
public required string Content { get; set; }

Expand Down
4 changes: 4 additions & 0 deletions src/Kook.Net.Rest/API/Rest/ModifyMessageParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ internal class ModifyMessageParams
[JsonPropertyName("msg_id")]
public required Guid MessageId { get; set; }

[JsonPropertyName("template_id")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? TemplateId { get; set; }

[JsonPropertyName("content")]
public required string Content { get; set; }

Expand Down
8 changes: 4 additions & 4 deletions src/Kook.Net.Rest/Entities/Channels/ChannelHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@ public static Task DeleteDirectMessageAsync(IMessageChannel channel,
Guid messageId, BaseKookClient client, RequestOptions? options) =>
MessageHelper.DeleteDirectAsync(messageId, client, options);

public static async Task ModifyMessageAsync(IMessageChannel channel, Guid messageId,
Action<MessageProperties> func, BaseKookClient client, RequestOptions? options) =>
public static async Task ModifyMessageAsync<T>(IMessageChannel channel, Guid messageId,
Action<MessageProperties<T>> func, BaseKookClient client, RequestOptions? options) =>
await MessageHelper.ModifyAsync(messageId, client, func, options).ConfigureAwait(false);

#endregion
Expand Down Expand Up @@ -531,8 +531,8 @@ Task<Cacheable<IUserMessage, Guid>> SendAttachmentAsync(MessageType messageType)
SendDirectMessageAsync(channel, client, messageType, attachment.Uri.OriginalString, quote, options);
}

public static Task ModifyDirectMessageAsync(IDMChannel channel, Guid messageId,
Action<MessageProperties> func, BaseKookClient client, RequestOptions? options) =>
public static Task ModifyDirectMessageAsync<T>(IDMChannel channel, Guid messageId,
Action<MessageProperties<T>> func, BaseKookClient client, RequestOptions? options) =>
MessageHelper.ModifyDirectAsync(messageId, client, func, options);

#endregion
Expand Down
4 changes: 4 additions & 0 deletions src/Kook.Net.Rest/Entities/Channels/RestDMChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ public Task DeleteMessageAsync(IMessage message, RequestOptions? options = null)

/// <inheritdoc />
public Task ModifyMessageAsync(Guid messageId, Action<MessageProperties> func, RequestOptions? options = null) =>
ChannelHelper.ModifyDirectMessageAsync<object>(this, messageId, func, Kook, options);

/// <inheritdoc />
public Task ModifyMessageAsync<T>(Guid messageId, Action<MessageProperties<T>> func, RequestOptions? options = null) =>
ChannelHelper.ModifyDirectMessageAsync(this, messageId, func, Kook, options);

#endregion
Expand Down
5 changes: 5 additions & 0 deletions src/Kook.Net.Rest/Entities/Channels/RestTextChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ public Task DeleteMessageAsync(IMessage message, RequestOptions? options = null)
/// <inheritdoc />
public async Task ModifyMessageAsync(Guid messageId,
Action<MessageProperties> func, RequestOptions? options = null) =>
await ChannelHelper.ModifyMessageAsync<object>(this, messageId, func, Kook, options).ConfigureAwait(false);

/// <inheritdoc />
public async Task ModifyMessageAsync<T>(Guid messageId,
Action<MessageProperties<T>> func, RequestOptions? options = null) =>
await ChannelHelper.ModifyMessageAsync(this, messageId, func, Kook, options).ConfigureAwait(false);

#endregion
Expand Down
127 changes: 114 additions & 13 deletions src/Kook.Net.Rest/Entities/Messages/MessageHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,30 +159,44 @@ public static async Task<IReadOnlyCollection<IUser>> GetDirectMessageReactionUse
return [..models.Select(x => RestUser.Create(client, x))];
}

public static async Task ModifyAsync(IUserMessage msg, BaseKookClient client, Action<MessageProperties> func,
public static async Task ModifyAsync<T>(IUserMessage msg, BaseKookClient client, Action<MessageProperties<T>> func,
RequestOptions? options)
{
if (msg.Type == MessageType.KMarkdown)
{
MessageProperties args = new()
MessageProperties<T> args = new()
{
Content = msg.Content,
Quote = msg.Quote
};
func(args);
if (args.TemplateId.HasValue)
{
Preconditions.EnsureMessageProperties(args);
await ModifyAsync(msg.Id, client, args.TemplateId.Value, args.Parameters,
args.Quote, args.EphemeralUser, args.JsonSerializerOptions, options);
return;
}
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
await ModifyAsync(msg.Id, client, args.Content, args.Quote, args.EphemeralUser, options);
return;
}

if (msg.Type == MessageType.Card)
{
MessageProperties args = new()
MessageProperties<T> args = new()
{
Cards = [..msg.Cards],
Quote = msg.Quote
};
func(args);
if (args.TemplateId.HasValue)
{
Preconditions.EnsureMessageProperties(args);
await ModifyAsync(msg.Id, client, args.TemplateId.Value, args.Parameters,
args.Quote, args.EphemeralUser, args.JsonSerializerOptions, options);
return;
}
if (args.Cards is null || !args.Cards.Any())
throw new ArgumentNullException(nameof(args.Cards), "CardMessage must contains cards.");
string json = SerializeCards(args.Cards);
Expand All @@ -193,13 +207,19 @@ public static async Task ModifyAsync(IUserMessage msg, BaseKookClient client, Ac
throw new NotSupportedException("Only the modification of KMarkdown and CardMessage are supported.");
}

public static async Task ModifyAsync(Guid msgId, BaseKookClient client,
Action<MessageProperties> func, RequestOptions? options)
public static async Task ModifyAsync<T>(Guid msgId, BaseKookClient client,
Action<MessageProperties<T>> func, RequestOptions? options)
{
MessageProperties properties = new();
MessageProperties<T> properties = new();
func(properties);
if (string.IsNullOrEmpty(properties.Content) ^ (properties.Cards is not null && properties.Cards.Any()))
throw new InvalidOperationException("Only one of arguments can be set between Content and Cards");
Preconditions.EnsureMessageProperties(properties);

if (properties.TemplateId.HasValue)
{
await ModifyAsync(msgId, client, properties.TemplateId.Value, properties.Parameters,
properties.Quote, properties.EphemeralUser, properties.JsonSerializerOptions, options);
return;
}

string content;
if (properties.Content != null && !string.IsNullOrEmpty(properties.Content))
Expand All @@ -225,13 +245,81 @@ public static async Task ModifyAsync(Guid msgId, BaseKookClient client, string c
await client.ApiClient.ModifyMessageAsync(args, options).ConfigureAwait(false);
}

public static async Task ModifyDirectAsync(Guid msgId, BaseKookClient client,
Action<MessageProperties> func, RequestOptions? options)
public static async Task ModifyAsync<T>(Guid msgId, BaseKookClient client, int templateId, T parameters,
IQuote? quote, IUser? ephemeralUser, JsonSerializerOptions? jsonSerializerOptions, RequestOptions? options)
{
MessageProperties properties = new();
ModifyMessageParams args = new()
{
MessageId = msgId,
TemplateId = templateId,
Content = JsonSerializer.Serialize(parameters, jsonSerializerOptions),
QuotedMessageId = quote?.QuotedMessageId,
EphemeralUserId = ephemeralUser?.Id
};
await client.ApiClient.ModifyMessageAsync(args, options).ConfigureAwait(false);
}

public static async Task ModifyDirectAsync<T>(IUserMessage msg, BaseKookClient client, Action<MessageProperties<T>> func,
RequestOptions? options)
{
if (msg.Type == MessageType.KMarkdown)
{
MessageProperties<T> args = new()
{
Content = msg.Content,
Quote = msg.Quote
};
func(args);
if (args.TemplateId.HasValue)
{
Preconditions.EnsureMessageProperties(args);
await ModifyDirectAsync(msg.Id, client, args.TemplateId.Value, args.Parameters,
args.Quote, args.JsonSerializerOptions, options);
return;
}
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
await ModifyDirectAsync(msg.Id, client, args.Content, args.Quote, options);
return;
}

if (msg.Type == MessageType.Card)
{
MessageProperties<T> args = new()
{
Cards = [..msg.Cards],
Quote = msg.Quote
};
func(args);
if (args.TemplateId.HasValue)
{
Preconditions.EnsureMessageProperties(args);
await ModifyDirectAsync(msg.Id, client, args.TemplateId.Value, args.Parameters,
args.Quote, args.JsonSerializerOptions, options);
return;
}
if (args.Cards is null || !args.Cards.Any())
throw new ArgumentNullException(nameof(args.Cards), "CardMessage must contains cards.");
string json = SerializeCards(args.Cards);
await ModifyDirectAsync(msg.Id, client, json, args.Quote, options);
return;
}

throw new NotSupportedException("Only the modification of KMarkdown and CardMessage are supported.");
}

public static async Task ModifyDirectAsync<T>(Guid msgId, BaseKookClient client,
Action<MessageProperties<T>> func, RequestOptions? options)
{
MessageProperties<T> properties = new();
func(properties);
if (string.IsNullOrEmpty(properties.Content) ^ (properties.Cards is not null && properties.Cards.Any()))
throw new InvalidOperationException("Only one of arguments can be set between Content and Cards");
Preconditions.EnsureMessageProperties(properties);

if (properties.TemplateId.HasValue)
{
await ModifyDirectAsync(msgId, client, properties.TemplateId.Value, properties.Parameters,
properties.Quote, properties.JsonSerializerOptions, options);
return;
}

string content;
if (properties.Content != null && !string.IsNullOrEmpty(properties.Content))
Expand All @@ -256,6 +344,19 @@ public static async Task ModifyDirectAsync(Guid msgId, BaseKookClient client,
await client.ApiClient.ModifyDirectMessageAsync(args, options).ConfigureAwait(false);
}

public static async Task ModifyDirectAsync<T>(Guid msgId, BaseKookClient client,
int? templateId, T parameters, IQuote? quote, JsonSerializerOptions? jsonSerializerOptions, RequestOptions? options)
{
ModifyDirectMessageParams args = new()
{
TemplateId = templateId,
MessageId = msgId,
Content = JsonSerializer.Serialize(parameters, jsonSerializerOptions),
QuotedMessageId = quote?.QuotedMessageId
};
await client.ApiClient.ModifyDirectMessageAsync(args, options).ConfigureAwait(false);
}

public static ImmutableArray<ICard> ParseCards(string json)
{
JsonSerializerOptions serializerOptions = new()
Expand Down
Loading

0 comments on commit 786162e

Please sign in to comment.