PluralKit/PluralKit.Bot/CommandSystem/Context/Context.cs

146 lines
5.3 KiB
C#
Raw Normal View History

2019-10-05 05:41:00 +00:00
using System;
using System.Threading.Tasks;
2019-12-21 20:51:41 +00:00
using App.Metrics;
2020-01-26 00:27:45 +00:00
using Autofac;
2021-11-30 02:35:21 +00:00
using NodaTime;
using Myriad.Cache;
2020-12-22 12:15:26 +00:00
using Myriad.Extensions;
using Myriad.Gateway;
2021-01-15 10:29:43 +00:00
using Myriad.Rest;
2020-12-24 13:52:44 +00:00
using Myriad.Rest.Types;
using Myriad.Rest.Types.Requests;
2020-12-22 12:15:26 +00:00
using Myriad.Types;
using PluralKit.Core;
2019-10-05 05:41:00 +00:00
namespace PluralKit.Bot;
public class Context
2019-10-05 05:41:00 +00:00
{
private readonly ILifetimeScope _provider;
private readonly IMetrics _metrics;
private readonly CommandMessageService _commandMessageService;
private Command? _currentCommand;
public Context(ILifetimeScope provider, Shard shard, Guild? guild, Channel channel, MessageCreateEvent message, int commandParseOffset,
2021-11-30 02:35:21 +00:00
PKSystem senderSystem, SystemConfig config, MessageContext messageContext)
2019-10-05 05:41:00 +00:00
{
Message = (Message)message;
Shard = shard;
Guild = guild;
Channel = channel;
System = senderSystem;
2021-11-30 02:35:21 +00:00
Config = config;
MessageContext = messageContext;
Cache = provider.Resolve<IDiscordCache>();
Database = provider.Resolve<IDatabase>();
Repository = provider.Resolve<ModelRepository>();
_metrics = provider.Resolve<IMetrics>();
_provider = provider;
_commandMessageService = provider.Resolve<CommandMessageService>();
Parameters = new Parameters(message.Content?.Substring(commandParseOffset));
Rest = provider.Resolve<DiscordApiClient>();
Cluster = provider.Resolve<Cluster>();
}
public readonly IDiscordCache Cache;
public readonly DiscordApiClient Rest;
2019-10-05 05:41:00 +00:00
public readonly Channel Channel;
public User Author => Message.Author;
public GuildMemberPartial Member => ((MessageCreateEvent)Message).Member;
public readonly Message Message;
public readonly Guild Guild;
public readonly Shard Shard;
public readonly Cluster Cluster;
public readonly MessageContext MessageContext;
2021-01-15 10:29:43 +00:00
public Task<PermissionSet> BotPermissions => Cache.PermissionsIn(Channel.Id);
public Task<PermissionSet> UserPermissions => Cache.PermissionsFor((MessageCreateEvent)Message);
2020-04-24 19:50:28 +00:00
2020-12-22 12:15:26 +00:00
public readonly PKSystem System;
2021-11-30 02:35:21 +00:00
public readonly SystemConfig Config;
public DateTimeZone Zone => Config?.Zone ?? DateTimeZone.Utc;
2020-04-24 19:50:28 +00:00
public readonly Parameters Parameters;
2021-08-27 15:03:47 +00:00
internal readonly IDatabase Database;
internal readonly ModelRepository Repository;
public async Task<Message> Reply(string text = null, Embed embed = null, AllowedMentions? mentions = null)
{
var botPerms = await BotPermissions;
2019-10-05 05:41:00 +00:00
if (!botPerms.HasFlag(PermissionSet.SendMessages))
// Will be "swallowed" during the error handler anyway, this message is never shown.
throw new PKError("PluralKit does not have permission to send messages in this channel.");
2019-10-05 05:41:00 +00:00
if (embed != null && !botPerms.HasFlag(PermissionSet.EmbedLinks))
throw new PKError("PluralKit does not have permission to send embeds in this channel. Please ensure I have the **Embed Links** permission enabled.");
var msg = await Rest.CreateMessage(Channel.Id, new MessageRequest
{
Content = text,
Embed = embed,
// Default to an empty allowed mentions object instead of null (which means no mentions allowed)
AllowedMentions = mentions ?? new AllowedMentions()
});
2021-08-27 15:03:47 +00:00
if (embed != null)
2019-10-05 05:41:00 +00:00
{
// Sensitive information that might want to be deleted by :x: reaction is typically in an embed format (member cards, for example)
// This may need to be changed at some point but works well enough for now
await _commandMessageService.RegisterMessage(msg.Id, msg.ChannelId, Author.Id);
2019-10-05 05:41:00 +00:00
}
return msg;
}
2021-08-27 15:03:47 +00:00
2021-11-30 02:35:21 +00:00
public async Task Execute<T>(Command? commandDef, Func<T, Task> handler, bool deprecated = false)
{
_currentCommand = commandDef;
try
{
using (_metrics.Measure.Timer.Time(BotMetrics.CommandTime, new MetricTags("Command", commandDef?.Key ?? "null")))
await handler(_provider.Resolve<T>());
2021-08-27 15:03:47 +00:00
_metrics.Measure.Meter.Mark(BotMetrics.CommandsRun);
}
catch (PKSyntaxError e)
{
await Reply($"{Emojis.Error} {e.Message}\n**Command usage:**\n> pk;{commandDef?.Usage}");
}
catch (PKError e)
{
await Reply($"{Emojis.Error} {e.Message}");
}
catch (TimeoutException)
{
// Got a complaint the old error was a bit too patronizing. Hopefully this is better?
await Reply($"{Emojis.Error} Operation timed out, sorry. Try again, perhaps?");
}
2021-11-30 02:35:21 +00:00
if (deprecated && commandDef != null)
await Reply($"{Emojis.Warn} This command is deprecated and will be removed soon. In the future, please use `pk;{commandDef.Key}`.");
2019-10-05 05:41:00 +00:00
}
public LookupContext LookupContextFor(PKSystem target) =>
System?.Id == target.Id ? LookupContext.ByOwner : LookupContext.ByNonOwner;
public LookupContext LookupContextFor(SystemId systemId) =>
System?.Id == systemId ? LookupContext.ByOwner : LookupContext.ByNonOwner;
public LookupContext LookupContextFor(PKMember target) =>
System?.Id == target.System ? LookupContext.ByOwner : LookupContext.ByNonOwner;
public IComponentContext Services => _provider;
2019-10-05 05:41:00 +00:00
}