diff --git a/locale/Messages.resx b/locale/Messages.resx
index ab821ac..31ed7b3 100644
--- a/locale/Messages.resx
+++ b/locale/Messages.resx
@@ -564,4 +564,10 @@
Boost count
+
+ There are no messages matching your filter!
+
+
+ Cleared {0} messages from {1}
+
diff --git a/locale/Messages.ru.resx b/locale/Messages.ru.resx
index f38032b..cb65749 100644
--- a/locale/Messages.ru.resx
+++ b/locale/Messages.ru.resx
@@ -564,4 +564,10 @@
Количество бустов
+
+ Нет сообщений, которые подходят под твой фильтр!
+
+
+ Очищено {0} сообщений от {1}
+
diff --git a/locale/Messages.tt-ru.resx b/locale/Messages.tt-ru.resx
index 52d6c7e..b5f6ad1 100644
--- a/locale/Messages.tt-ru.resx
+++ b/locale/Messages.tt-ru.resx
@@ -564,4 +564,10 @@
кол-во бустов
+
+ алло а чё мне удалять-то
+
+
+ вырезано {0} забавных сообщений от {1}
+
diff --git a/src/Commands/ClearCommandGroup.cs b/src/Commands/ClearCommandGroup.cs
index a6ac188..714c9de 100644
--- a/src/Commands/ClearCommandGroup.cs
+++ b/src/Commands/ClearCommandGroup.cs
@@ -45,9 +45,10 @@ public class ClearCommandGroup : CommandGroup
}
///
- /// A slash command that clears messages in the channel it was executed.
+ /// A slash command that clears messages in the channel it was executed, optionally filtering by message author.
///
/// The amount of messages to clear.
+ /// The user whose messages will be cleared.
///
/// A feedback sending result which may or may not have succeeded. A successful result does not mean that any messages
/// were cleared and vice-versa.
@@ -62,7 +63,8 @@ public class ClearCommandGroup : CommandGroup
[UsedImplicitly]
public async Task ExecuteClear(
[Description("Number of messages to remove (2-100)")] [MinValue(2)] [MaxValue(100)]
- int amount)
+ int amount,
+ IUser? author = null)
{
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var executorId))
{
@@ -92,11 +94,11 @@ public class ClearCommandGroup : CommandGroup
var data = await _guildData.GetData(guildId, CancellationToken);
Messages.Culture = GuildSettings.Language.Get(data.Settings);
- return await ClearMessagesAsync(executor, amount, data, channelId, messages, bot, CancellationToken);
+ return await ClearMessagesAsync(executor, author, data, channelId, messages, bot, CancellationToken);
}
private async Task ClearMessagesAsync(
- IUser executor, int amount, GuildData data, Snowflake channelId, IReadOnlyList messages, IUser bot,
+ IUser executor, IUser? author, GuildData data, Snowflake channelId, IReadOnlyList messages, IUser bot,
CancellationToken ct = default)
{
var idList = new List(messages.Count);
@@ -104,12 +106,27 @@ public class ClearCommandGroup : CommandGroup
for (var i = messages.Count - 1; i >= 1; i--) // '>= 1' to skip last message ('Octobot is thinking...')
{
var message = messages[i];
+ if (author is not null && message.Author.ID != author.ID)
+ {
+ continue;
+ }
+
idList.Add(message.ID);
builder.AppendLine(string.Format(Messages.MessageFrom, Mention.User(message.Author)));
builder.Append(message.Content.InBlockCode());
}
- var title = string.Format(Messages.MessagesCleared, amount.ToString());
+ if (idList.Count == 0)
+ {
+ var failedEmbed = new EmbedBuilder().WithSmallTitle(Messages.NoMessagesToClear, bot)
+ .WithColour(ColorsList.Red).Build();
+
+ return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct);
+ }
+
+ var title = author is not null
+ ? string.Format(Messages.MessagesClearedFiltered, idList.Count.ToString(), author.GetTag())
+ : string.Format(Messages.MessagesCleared, idList.Count.ToString());
var description = builder.ToString();
var deleteResult = await _channelApi.BulkDeleteMessagesAsync(
diff --git a/src/Data/MemberData.cs b/src/Data/MemberData.cs
index c7ddc27..b63f8ad 100644
--- a/src/Data/MemberData.cs
+++ b/src/Data/MemberData.cs
@@ -5,10 +5,14 @@ namespace Octobot.Data;
///
public sealed class MemberData
{
- public MemberData(ulong id, DateTimeOffset? bannedUntil = null)
+ public MemberData(ulong id, DateTimeOffset? bannedUntil = null, List? reminders = null)
{
Id = id;
BannedUntil = bannedUntil;
+ if (reminders is not null)
+ {
+ Reminders = reminders;
+ }
}
public ulong Id { get; }
diff --git a/src/Data/Reminder.cs b/src/Data/Reminder.cs
index 828fadb..42144f9 100644
--- a/src/Data/Reminder.cs
+++ b/src/Data/Reminder.cs
@@ -2,7 +2,7 @@ namespace Octobot.Data;
public struct Reminder
{
- public DateTimeOffset At;
- public string Text;
- public ulong Channel;
+ public DateTimeOffset At { get; init; }
+ public string Text { get; init; }
+ public ulong Channel { get; init; }
}
diff --git a/src/Messages.Designer.cs b/src/Messages.Designer.cs
index ebf7fec..4a771d0 100644
--- a/src/Messages.Designer.cs
+++ b/src/Messages.Designer.cs
@@ -980,5 +980,21 @@ namespace Octobot {
return ResourceManager.GetString("GuildInfoBoostCount", resourceCulture);
}
}
+
+ internal static string NoMessagesToClear
+ {
+ get
+ {
+ return ResourceManager.GetString("NoMessagesToClear", resourceCulture);
+ }
+ }
+
+ internal static string MessagesClearedFiltered
+ {
+ get
+ {
+ return ResourceManager.GetString("MessagesClearedFiltered", resourceCulture);
+ }
+ }
}
}
diff --git a/src/Services/Update/ScheduledEventUpdateService.cs b/src/Services/Update/ScheduledEventUpdateService.cs
index f97f3bb..f1d3524 100644
--- a/src/Services/Update/ScheduledEventUpdateService.cs
+++ b/src/Services/Update/ScheduledEventUpdateService.cs
@@ -181,6 +181,11 @@ public sealed class ScheduledEventUpdateService : BackgroundService
private async Task SendScheduledEventCreatedMessage(
IGuildScheduledEvent scheduledEvent, JsonNode settings, CancellationToken ct = default)
{
+ if (GuildSettings.EventNotificationChannel.Get(settings).Empty())
+ {
+ return Result.FromSuccess();
+ }
+
if (!scheduledEvent.Creator.IsDefined(out var creator))
{
return new ArgumentNullError(nameof(scheduledEvent.Creator));
@@ -281,6 +286,11 @@ public sealed class ScheduledEventUpdateService : BackgroundService
{
data.ScheduledEvents[scheduledEvent.ID.Value].ActualStartTime = DateTimeOffset.UtcNow;
+ if (GuildSettings.EventNotificationChannel.Get(data.Settings).Empty())
+ {
+ return Result.FromSuccess();
+ }
+
var embedDescriptionResult = scheduledEvent.EntityType switch
{
GuildScheduledEventEntityType.StageInstance or GuildScheduledEventEntityType.Voice =>
@@ -290,7 +300,7 @@ public sealed class ScheduledEventUpdateService : BackgroundService
};
var contentResult = await _utility.GetEventNotificationMentions(
- scheduledEvent, data.Settings, ct);
+ scheduledEvent, data, ct);
if (!contentResult.IsDefined(out var content))
{
return Result.FromError(contentResult);
@@ -417,8 +427,13 @@ public sealed class ScheduledEventUpdateService : BackgroundService
private async Task SendEarlyEventNotificationAsync(
IGuildScheduledEvent scheduledEvent, GuildData data, CancellationToken ct)
{
+ if (GuildSettings.EventNotificationChannel.Get(data.Settings).Empty())
+ {
+ return Result.FromSuccess();
+ }
+
var contentResult = await _utility.GetEventNotificationMentions(
- scheduledEvent, data.Settings, ct);
+ scheduledEvent, data, ct);
if (!contentResult.IsDefined(out var content))
{
return Result.FromError(contentResult);
diff --git a/src/Services/UtilityService.cs b/src/Services/UtilityService.cs
index b144ca7..5bc06ea 100644
--- a/src/Services/UtilityService.cs
+++ b/src/Services/UtilityService.cs
@@ -160,16 +160,16 @@ public sealed class UtilityService : IHostedService
///
/// The scheduled event whose subscribers will be mentioned.
///
- /// The settings of the guild containing the scheduled event
+ /// The data of the guild containing the scheduled event.
/// The cancellation token for this operation.
/// A result containing the string which may or may not have succeeded.
public async Task> GetEventNotificationMentions(
- IGuildScheduledEvent scheduledEvent, JsonNode settings, CancellationToken ct = default)
+ IGuildScheduledEvent scheduledEvent, GuildData data, CancellationToken ct = default)
{
var builder = new StringBuilder();
- var role = GuildSettings.EventNotificationRole.Get(settings);
+ var role = GuildSettings.EventNotificationRole.Get(data.Settings);
var subscribersResult = await _eventApi.GetGuildScheduledEventUsersAsync(
- scheduledEvent.GuildID, scheduledEvent.ID, withMember: true, ct: ct);
+ scheduledEvent.GuildID, scheduledEvent.ID, ct: ct);
if (!subscribersResult.IsDefined(out var subscribers))
{
return Result.FromError(subscribersResult);
@@ -181,7 +181,7 @@ public sealed class UtilityService : IHostedService
}
builder = subscribers.Where(
- subscriber => subscriber.GuildMember.IsDefined(out var member) && !member.Roles.Contains(role))
+ subscriber => !data.GetOrCreateMemberData(subscriber.User.ID).Roles.Contains(role.Value))
.Aggregate(builder, (current, subscriber) => current.Append($"{Mention.User(subscriber.User)} "));
return builder.ToString();
}