mirror of
https://github.com/TeamOctolings/Octobot.git
synced 2025-04-19 16:33:36 +03:00
Add /remind command
Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
parent
20ffbbaafb
commit
d46b08df08
18 changed files with 990 additions and 1295 deletions
|
@ -1,6 +1,5 @@
|
|||
using Boyfriend.Commands;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
@ -80,7 +79,8 @@ public class Boyfriend {
|
|||
.WithCommandGroup<ClearCommandGroup>()
|
||||
.WithCommandGroup<KickCommandGroup>()
|
||||
.WithCommandGroup<MuteCommandGroup>()
|
||||
.WithCommandGroup<PingCommandGroup>();
|
||||
.WithCommandGroup<PingCommandGroup>()
|
||||
.WithCommandGroup<RemindCommandGroup>();
|
||||
var responderTypes = typeof(Boyfriend).Assembly
|
||||
.GetExportedTypes()
|
||||
.Where(t => t.IsResponder());
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using System.Drawing;
|
||||
|
||||
// TODO: remove this when all colors are used
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace Boyfriend;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Boyfriend.Services.Data;
|
||||
using Boyfriend.Services;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Boyfriend.Services.Data;
|
||||
using Boyfriend.Services;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using Boyfriend.Services.Data;
|
||||
using Boyfriend.Services;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
|
|
66
Commands/RemindCommandGroup.cs
Normal file
66
Commands/RemindCommandGroup.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System.ComponentModel;
|
||||
using Boyfriend.Data;
|
||||
using Boyfriend.Services;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Discord.Commands.Contexts;
|
||||
using Remora.Discord.Commands.Feedback.Services;
|
||||
using Remora.Discord.Extensions.Embeds;
|
||||
using Remora.Discord.Extensions.Formatting;
|
||||
using Remora.Results;
|
||||
|
||||
// ReSharper disable ClassNeverInstantiated.Global
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace Boyfriend.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the command to manage reminders: /remind
|
||||
/// </summary>
|
||||
public class RemindCommandGroup : CommandGroup {
|
||||
private readonly ICommandContext _context;
|
||||
private readonly GuildDataService _dataService;
|
||||
private readonly FeedbackService _feedbackService;
|
||||
private readonly IDiscordRestUserAPI _userApi;
|
||||
|
||||
public RemindCommandGroup(
|
||||
ICommandContext context, GuildDataService dataService, FeedbackService feedbackService,
|
||||
IDiscordRestUserAPI userApi) {
|
||||
_context = context;
|
||||
_dataService = dataService;
|
||||
_feedbackService = feedbackService;
|
||||
_userApi = userApi;
|
||||
}
|
||||
|
||||
[Command("remind")]
|
||||
[Description("крафтит напоминалки")]
|
||||
public async Task<Result> AddReminderAsync(TimeSpan duration, string text) {
|
||||
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId))
|
||||
return Result.FromError(
|
||||
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));
|
||||
|
||||
var userResult = await _userApi.GetUserAsync(userId.Value, CancellationToken);
|
||||
if (!userResult.IsDefined(out var user))
|
||||
return Result.FromError(userResult);
|
||||
|
||||
var remindAt = DateTimeOffset.UtcNow.Add(duration);
|
||||
|
||||
(await _dataService.GetMemberData(guildId.Value, userId.Value, CancellationToken)).Reminders.Add(
|
||||
new Reminder {
|
||||
RemindAt = remindAt,
|
||||
Channel = channelId.Value,
|
||||
Text = text
|
||||
});
|
||||
|
||||
var embed = new EmbedBuilder().WithSmallTitle(string.Format(Messages.ReminderCreated, user.GetTag()), user)
|
||||
.WithDescription(string.Format(Messages.DescriptionReminderCreated, Markdown.Timestamp(remindAt)))
|
||||
.WithColour(ColorsList.Green)
|
||||
.Build();
|
||||
|
||||
if (!embed.IsDefined(out var built))
|
||||
return Result.FromError(embed);
|
||||
|
||||
return (Result)await _feedbackService.SendContextualEmbedAsync(built, ct: CancellationToken);
|
||||
}
|
||||
}
|
|
@ -14,4 +14,5 @@ public class MemberData {
|
|||
public ulong Id { get; }
|
||||
public DateTimeOffset? BannedUntil { get; set; }
|
||||
public List<Snowflake> Roles { get; set; } = new();
|
||||
public List<Reminder> Reminders { get; } = new();
|
||||
}
|
||||
|
|
9
Data/Reminder.cs
Normal file
9
Data/Reminder.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using Remora.Rest.Core;
|
||||
|
||||
namespace Boyfriend.Data;
|
||||
|
||||
public struct Reminder {
|
||||
public DateTimeOffset RemindAt;
|
||||
public string Text;
|
||||
public Snowflake Channel;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
using Boyfriend.Data;
|
||||
using Boyfriend.Services.Data;
|
||||
using Boyfriend.Services;
|
||||
using DiffPlex.DiffBuilder;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||
|
|
2108
Messages.Designer.cs
generated
2108
Messages.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -456,9 +456,9 @@
|
|||
<data name="MissingReminderText" xml:space="preserve">
|
||||
<value>You need to specify reminder text!</value>
|
||||
</data>
|
||||
<data name="FeedbackReminderAdded" xml:space="preserve">
|
||||
<value>OK, I'll mention you on <t:{0}:f></value>
|
||||
</data>
|
||||
<data name="DescriptionReminderCreated" xml:space="preserve">
|
||||
<value>OK, I'll mention you on {0}</value>
|
||||
</data>
|
||||
<data name="InvalidRemindIn" xml:space="preserve">
|
||||
<value>You need to specify when I should send you the reminder!</value>
|
||||
</data>
|
||||
|
@ -537,4 +537,13 @@
|
|||
<data name="AboutDeveloper@neroduckale" xml:space="preserve">
|
||||
<value>developer</value>
|
||||
</data>
|
||||
<data name="ReminderCreated" xml:space="preserve">
|
||||
<value>Reminder for {0} created</value>
|
||||
</data>
|
||||
<data name="Reminder" xml:space="preserve">
|
||||
<value>Reminder for {0}</value>
|
||||
</data>
|
||||
<data name="DescriptionReminder" xml:space="preserve">
|
||||
<value>You asked me to remind you {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -453,9 +453,9 @@
|
|||
<data name="MissingReminderText" xml:space="preserve">
|
||||
<value>Тебе нужно указать текст напоминания!</value>
|
||||
</data>
|
||||
<data name="FeedbackReminderAdded" xml:space="preserve">
|
||||
<value>Хорошо, я упомяну тебя <t:{0}:f></value>
|
||||
</data>
|
||||
<data name="DescriptionReminderCreated" xml:space="preserve">
|
||||
<value>Хорошо, я упомяну тебя {0}</value>
|
||||
</data>
|
||||
<data name="InvalidRemindIn" xml:space="preserve">
|
||||
<value>Нужно указать время, через которое придёт напоминание!</value>
|
||||
</data>
|
||||
|
@ -537,4 +537,13 @@
|
|||
<data name="AboutDeveloper@mctaylors" xml:space="preserve">
|
||||
<value>дизайнер лого и эмбедов, создатель Boyfriend's Wiki</value>
|
||||
</data>
|
||||
<data name="ReminderCreated" xml:space="preserve">
|
||||
<value>Напоминание для {0} создано</value>
|
||||
</data>
|
||||
<data name="Reminder" xml:space="preserve">
|
||||
<value>Напоминание для {0}</value>
|
||||
</data>
|
||||
<data name="DescriptionReminder" xml:space="preserve">
|
||||
<value>Вы просили напомнить вам {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -456,9 +456,9 @@
|
|||
<data name="MissingReminderText" xml:space="preserve">
|
||||
<value>для крафта напоминалки нужен текст</value>
|
||||
</data>
|
||||
<data name="FeedbackReminderAdded" xml:space="preserve">
|
||||
<value>вас понял, упоминание будет <t:{0}:f></value>
|
||||
</data>
|
||||
<data name="DescriptionReminderCreated" xml:space="preserve">
|
||||
<value>вас понял, упоминание будет {0}</value>
|
||||
</data>
|
||||
<data name="InvalidRemindIn" xml:space="preserve">
|
||||
<value>шизоид у меня на часах такого нету</value>
|
||||
</data>
|
||||
|
@ -537,4 +537,13 @@
|
|||
<data name="AboutDeveloper@Octol1ttle" xml:space="preserve">
|
||||
<value>САМЫЙ ВАЖНЫЙ чел написавший кода больше всех (99.99%)</value>
|
||||
</data>
|
||||
<data name="ReminderCreated" xml:space="preserve">
|
||||
<value>напоминалка для {0} скрафченА</value>
|
||||
</data>
|
||||
<data name="Reminder" xml:space="preserve">
|
||||
<value>напоминалка для {0}</value>
|
||||
</data>
|
||||
<data name="DescriptionReminder" xml:space="preserve">
|
||||
<value>ты хотел чтоб я напомнил тебе {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -5,7 +5,7 @@ using Microsoft.Extensions.Hosting;
|
|||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Rest.Core;
|
||||
|
||||
namespace Boyfriend.Services.Data;
|
||||
namespace Boyfriend.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Handles saving, loading, initializing and providing <see cref="GuildData" />.
|
|
@ -1,5 +1,4 @@
|
|||
using Boyfriend.Data;
|
||||
using Boyfriend.Services.Data;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
|
@ -95,11 +94,12 @@ public class GuildUpdateService : BackgroundService {
|
|||
/// This method does the following:
|
||||
/// <list type="bullet">
|
||||
/// <item>Automatically unbans users once their ban period has expired.</item>
|
||||
/// <item>Automatically grants users the guild's <see cref="GuildConfiguration.DefaultRole"/> if one is set.</item>
|
||||
/// <item>Automatically grants members the guild's <see cref="GuildConfiguration.DefaultRole"/> if one is set.</item>
|
||||
/// <item>Sends reminders about an upcoming scheduled event.</item>
|
||||
/// <item>Automatically starts scheduled events if <see cref="GuildConfiguration.AutoStartEvents"/> is enabled.</item>
|
||||
/// <item>Sends scheduled event start notifications.</item>
|
||||
/// <item>Sends scheduled event completion notifications.</item>
|
||||
/// <item>Sends reminders to members.</item>
|
||||
/// </list>
|
||||
/// This is done here and not in a <see cref="IResponder{TGatewayEvent}" /> for the following reasons:
|
||||
/// <list type="bullet">
|
||||
|
@ -118,20 +118,46 @@ public class GuildUpdateService : BackgroundService {
|
|||
var defaultRoleSnowflake = data.Configuration.DefaultRole.ToDiscordSnowflake();
|
||||
|
||||
foreach (var memberData in data.MemberData.Values) {
|
||||
var userIdSnowflake = memberData.Id.ToDiscordSnowflake();
|
||||
var userId = memberData.Id.ToDiscordSnowflake();
|
||||
|
||||
if (defaultRoleSnowflake.Value is not 0 && !memberData.Roles.Contains(defaultRoleSnowflake))
|
||||
_ = _guildApi.AddGuildMemberRoleAsync(
|
||||
guildId, userIdSnowflake, defaultRoleSnowflake, ct: ct);
|
||||
guildId, userId, defaultRoleSnowflake, ct: ct);
|
||||
|
||||
if (DateTimeOffset.UtcNow > memberData.BannedUntil) {
|
||||
var unbanResult = await _guildApi.RemoveGuildBanAsync(
|
||||
guildId, userIdSnowflake, Messages.PunishmentExpired.EncodeHeader(), ct);
|
||||
guildId, userId, Messages.PunishmentExpired.EncodeHeader(), ct);
|
||||
if (unbanResult.IsSuccess)
|
||||
memberData.BannedUntil = null;
|
||||
else
|
||||
_logger.LogWarning(
|
||||
"Error in automatic user unban request.\n{ErrorMessage}", unbanResult.Error.Message);
|
||||
}
|
||||
|
||||
var userResult = await _userApi.GetUserAsync(userId, ct);
|
||||
if (!userResult.IsDefined(out var user)) continue;
|
||||
|
||||
for (var i = memberData.Reminders.Count - 1; i >= 0; i--) {
|
||||
var reminder = memberData.Reminders[i];
|
||||
if (DateTimeOffset.UtcNow < reminder.RemindAt) continue;
|
||||
|
||||
var embed = new EmbedBuilder().WithSmallTitle(
|
||||
string.Format(Messages.Reminder, user.GetTag()), user)
|
||||
.WithDescription(
|
||||
string.Format(Messages.DescriptionReminder, Markdown.InlineCode(reminder.Text)))
|
||||
.WithColour(ColorsList.Magenta)
|
||||
.Build();
|
||||
|
||||
if (!embed.IsDefined(out var built)) continue;
|
||||
|
||||
var messageResult = await _channelApi.CreateMessageAsync(
|
||||
reminder.Channel, Mention.User(user), embeds: new[] { built }, ct: ct);
|
||||
if (!messageResult.IsSuccess)
|
||||
_logger.LogWarning(
|
||||
"Error in reminder send.\n{ErrorMessage}", messageResult.Error.Message);
|
||||
|
||||
memberData.Reminders.Remove(reminder);
|
||||
}
|
||||
}
|
||||
|
||||
var eventsResult = await _eventApi.ListScheduledEventsForGuildAsync(guildId, ct: ct);
|
||||
|
|
Loading…
Add table
Reference in a new issue