Add DM support
This commit is contained in:
parent
2e0c30eb5d
commit
a2c8cbb560
@ -55,16 +55,5 @@ namespace Myriad.Cache
|
||||
foreach (var mention in evt.Mentions)
|
||||
await cache.SaveUser(mention);
|
||||
}
|
||||
|
||||
public static async ValueTask<User?> GetOrFetchUser(this IDiscordCache cache, DiscordApiClient rest, ulong userId)
|
||||
{
|
||||
if (cache.TryGetUser(userId, out var cacheUser))
|
||||
return cacheUser;
|
||||
|
||||
var restUser = await rest.GetUser(userId);
|
||||
if (restUser != null)
|
||||
await cache.SaveUser(restUser);
|
||||
return restUser;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ namespace Myriad.Cache
|
||||
|
||||
public bool TryGetGuild(ulong guildId, out Guild guild);
|
||||
public bool TryGetChannel(ulong channelId, out Channel channel);
|
||||
public bool TryGetDmChannel(ulong userId, out Channel channel);
|
||||
public bool TryGetUser(ulong userId, out User user);
|
||||
public bool TryGetRole(ulong roleId, out Role role);
|
||||
|
||||
|
@ -10,19 +10,12 @@ namespace Myriad.Cache
|
||||
{
|
||||
public class MemoryDiscordCache: IDiscordCache
|
||||
{
|
||||
private readonly ConcurrentDictionary<ulong, Channel> _channels;
|
||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds;
|
||||
private readonly ConcurrentDictionary<ulong, Role> _roles;
|
||||
private readonly ConcurrentDictionary<ulong, User> _users;
|
||||
|
||||
public MemoryDiscordCache()
|
||||
{
|
||||
_guilds = new ConcurrentDictionary<ulong, CachedGuild>();
|
||||
_channels = new ConcurrentDictionary<ulong, Channel>();
|
||||
_users = new ConcurrentDictionary<ulong, User>();
|
||||
_roles = new ConcurrentDictionary<ulong, Role>();
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, Channel> _channels = new();
|
||||
private readonly ConcurrentDictionary<ulong, ulong> _dmChannels = new();
|
||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds = new();
|
||||
private readonly ConcurrentDictionary<ulong, Role> _roles = new();
|
||||
private readonly ConcurrentDictionary<ulong, User> _users = new();
|
||||
|
||||
public ValueTask SaveGuild(Guild guild)
|
||||
{
|
||||
SaveGuildRaw(guild);
|
||||
@ -35,14 +28,21 @@ namespace Myriad.Cache
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask SaveChannel(Channel channel)
|
||||
public async ValueTask SaveChannel(Channel channel)
|
||||
{
|
||||
_channels[channel.Id] = channel;
|
||||
|
||||
if (channel.GuildId != null && _guilds.TryGetValue(channel.GuildId.Value, out var guild))
|
||||
guild.Channels.TryAdd(channel.Id, true);
|
||||
|
||||
return default;
|
||||
if (channel.Recipients != null)
|
||||
{
|
||||
foreach (var recipient in channel.Recipients)
|
||||
{
|
||||
_dmChannels[recipient.Id] = channel.Id;
|
||||
await SaveUser(recipient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask SaveUser(User user)
|
||||
@ -125,6 +125,14 @@ namespace Myriad.Cache
|
||||
public bool TryGetChannel(ulong channelId, out Channel channel) =>
|
||||
_channels.TryGetValue(channelId, out channel!);
|
||||
|
||||
public bool TryGetDmChannel(ulong userId, out Channel channel)
|
||||
{
|
||||
channel = default!;
|
||||
if (!_dmChannels.TryGetValue(userId, out var channelId))
|
||||
return false;
|
||||
return TryGetChannel(channelId, out channel);
|
||||
}
|
||||
|
||||
public bool TryGetUser(ulong userId, out User user) =>
|
||||
_users.TryGetValue(userId, out user!);
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Cache;
|
||||
using Myriad.Rest;
|
||||
using Myriad.Types;
|
||||
|
||||
namespace Myriad.Extensions
|
||||
@ -41,5 +43,26 @@ namespace Myriad.Extensions
|
||||
throw new KeyNotFoundException($"User {roleId} not found in cache");
|
||||
return role;
|
||||
}
|
||||
|
||||
public static async ValueTask<User?> GetOrFetchUser(this IDiscordCache cache, DiscordApiClient rest, ulong userId)
|
||||
{
|
||||
if (cache.TryGetUser(userId, out var cacheUser))
|
||||
return cacheUser;
|
||||
|
||||
var restUser = await rest.GetUser(userId);
|
||||
if (restUser != null)
|
||||
await cache.SaveUser(restUser);
|
||||
return restUser;
|
||||
}
|
||||
|
||||
public static async Task<Channel> GetOrCreateDmChannel(this IDiscordCache cache, DiscordApiClient rest, ulong recipientId)
|
||||
{
|
||||
if (cache.TryGetDmChannel(recipientId, out var cacheChannel))
|
||||
return cacheChannel;
|
||||
|
||||
var restChannel = await rest.CreateDm(recipientId);
|
||||
await cache.SaveChannel(restChannel);
|
||||
return restChannel;
|
||||
}
|
||||
}
|
||||
}
|
@ -120,6 +120,9 @@ namespace Myriad.Rest
|
||||
_client.PostMultipart<Message>($"/webhooks/{webhookId}/{webhookToken}?wait=true",
|
||||
("ExecuteWebhook", webhookId), request, files)!;
|
||||
|
||||
public Task<Channel> CreateDm(ulong recipientId) =>
|
||||
_client.Post<Channel>($"/users/@me/channels", ("CreateDM", default), new CreateDmRequest(recipientId))!;
|
||||
|
||||
private static string EncodeEmoji(Emoji emoji) =>
|
||||
WebUtility.UrlEncode(emoji.Name) ?? emoji.Id?.ToString() ??
|
||||
throw new ArgumentException("Could not encode emoji");
|
||||
|
4
Myriad/Rest/Types/Requests/CreateDmRequest.cs
Normal file
4
Myriad/Rest/Types/Requests/CreateDmRequest.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace Myriad.Rest.Types.Requests
|
||||
{
|
||||
public record CreateDmRequest(ulong RecipientId);
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
public bool? Nsfw { get; init; }
|
||||
public ulong? ParentId { get; init; }
|
||||
public Overwrite[]? PermissionOverwrites { get; init; }
|
||||
public User[]? Recipients { get; init; }
|
||||
|
||||
public record Overwrite
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Cache;
|
||||
using Myriad.Extensions;
|
||||
using Myriad.Types;
|
||||
|
||||
using PluralKit.Bot.Utils;
|
||||
|
@ -1,6 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Extensions;
|
||||
using Myriad.Rest.Exceptions;
|
||||
using Myriad.Rest.Types.Requests;
|
||||
using Myriad.Types;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -26,22 +29,22 @@ namespace PluralKit.Bot
|
||||
try
|
||||
{
|
||||
// DM the user a security disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
var dm = await ctx.Rest.CreateDmAsync(ctx.Author.Id);
|
||||
await dm.SendMessageFixedAsync(
|
||||
$"{Emojis.Warn} Please note that this grants access to modify (and delete!) all your system data, so keep it safe and secure. If it leaks or you need a new one, you can invalidate this one with `pk;token refresh`.\n\nYour token is below:");
|
||||
await dm.SendMessageFixedAsync(token);
|
||||
var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.RestNew, ctx.AuthorNew.Id);
|
||||
await ctx.RestNew.CreateMessage(dm.Id, new MessageRequest
|
||||
{
|
||||
Content = $"{Emojis.Warn} Please note that this grants access to modify (and delete!) all your system data, so keep it safe and secure. If it leaks or you need a new one, you can invalidate this one with `pk;token refresh`.\n\nYour token is below:"
|
||||
});
|
||||
await ctx.RestNew.CreateMessage(dm.Id, new MessageRequest {Content = token});
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
// TODO: DMs
|
||||
// if (!(ctx.Channel is DiscordDmChannel))
|
||||
// await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
catch (UnauthorizedException)
|
||||
{
|
||||
// Can't check for permission errors beforehand, so have to handle here :/
|
||||
// TODO: DMs
|
||||
// if (!(ctx.Channel is DiscordDmChannel))
|
||||
// await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||
await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,25 +69,26 @@ namespace PluralKit.Bot
|
||||
|
||||
try {
|
||||
// DM the user an invalidation disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
var dm = await ctx.Rest.CreateDmAsync(ctx.Author.Id);
|
||||
await dm.SendMessageFixedAsync($"{Emojis.Warn} Your previous API token has been invalidated. You will need to change it anywhere it's currently used.\n\nYour token is below:");
|
||||
var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.RestNew, ctx.AuthorNew.Id);
|
||||
await ctx.RestNew.CreateMessage(dm.Id, new MessageRequest
|
||||
{
|
||||
Content = $"{Emojis.Warn} Your previous API token has been invalidated. You will need to change it anywhere it's currently used.\n\nYour token is below:"
|
||||
});
|
||||
|
||||
// Make the new token after sending the first DM; this ensures if we can't DM, we also don't end up
|
||||
// breaking their existing token as a side effect :)
|
||||
var token = await MakeAndSetNewToken(ctx.System);
|
||||
await dm.SendMessageFixedAsync(token);
|
||||
await ctx.RestNew.CreateMessage(dm.Id, new MessageRequest { Content = token });
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
// TODO: DMs
|
||||
// if (!(ctx.Channel is DiscordDmChannel))
|
||||
// await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
catch (UnauthorizedException)
|
||||
{
|
||||
// Can't check for permission errors beforehand, so have to handle here :/
|
||||
// TODO: DMs
|
||||
// if (!(ctx.Channel is DiscordDmChannel))
|
||||
// await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||
await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user