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)
|
foreach (var mention in evt.Mentions)
|
||||||
await cache.SaveUser(mention);
|
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 TryGetGuild(ulong guildId, out Guild guild);
|
||||||
public bool TryGetChannel(ulong channelId, out Channel channel);
|
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 TryGetUser(ulong userId, out User user);
|
||||||
public bool TryGetRole(ulong roleId, out Role role);
|
public bool TryGetRole(ulong roleId, out Role role);
|
||||||
|
|
||||||
|
@ -10,18 +10,11 @@ namespace Myriad.Cache
|
|||||||
{
|
{
|
||||||
public class MemoryDiscordCache: IDiscordCache
|
public class MemoryDiscordCache: IDiscordCache
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<ulong, Channel> _channels;
|
private readonly ConcurrentDictionary<ulong, Channel> _channels = new();
|
||||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds;
|
private readonly ConcurrentDictionary<ulong, ulong> _dmChannels = new();
|
||||||
private readonly ConcurrentDictionary<ulong, Role> _roles;
|
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds = new();
|
||||||
private readonly ConcurrentDictionary<ulong, User> _users;
|
private readonly ConcurrentDictionary<ulong, Role> _roles = new();
|
||||||
|
private readonly ConcurrentDictionary<ulong, User> _users = new();
|
||||||
public MemoryDiscordCache()
|
|
||||||
{
|
|
||||||
_guilds = new ConcurrentDictionary<ulong, CachedGuild>();
|
|
||||||
_channels = new ConcurrentDictionary<ulong, Channel>();
|
|
||||||
_users = new ConcurrentDictionary<ulong, User>();
|
|
||||||
_roles = new ConcurrentDictionary<ulong, Role>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask SaveGuild(Guild guild)
|
public ValueTask SaveGuild(Guild guild)
|
||||||
{
|
{
|
||||||
@ -35,14 +28,21 @@ namespace Myriad.Cache
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask SaveChannel(Channel channel)
|
public async ValueTask SaveChannel(Channel channel)
|
||||||
{
|
{
|
||||||
_channels[channel.Id] = channel;
|
_channels[channel.Id] = channel;
|
||||||
|
|
||||||
if (channel.GuildId != null && _guilds.TryGetValue(channel.GuildId.Value, out var guild))
|
if (channel.GuildId != null && _guilds.TryGetValue(channel.GuildId.Value, out var guild))
|
||||||
guild.Channels.TryAdd(channel.Id, true);
|
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)
|
public ValueTask SaveUser(User user)
|
||||||
@ -125,6 +125,14 @@ namespace Myriad.Cache
|
|||||||
public bool TryGetChannel(ulong channelId, out Channel channel) =>
|
public bool TryGetChannel(ulong channelId, out Channel channel) =>
|
||||||
_channels.TryGetValue(channelId, out 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) =>
|
public bool TryGetUser(ulong userId, out User user) =>
|
||||||
_users.TryGetValue(userId, out user!);
|
_users.TryGetValue(userId, out user!);
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Myriad.Cache;
|
using Myriad.Cache;
|
||||||
|
using Myriad.Rest;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
namespace Myriad.Extensions
|
namespace Myriad.Extensions
|
||||||
@ -41,5 +43,26 @@ namespace Myriad.Extensions
|
|||||||
throw new KeyNotFoundException($"User {roleId} not found in cache");
|
throw new KeyNotFoundException($"User {roleId} not found in cache");
|
||||||
return role;
|
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",
|
_client.PostMultipart<Message>($"/webhooks/{webhookId}/{webhookToken}?wait=true",
|
||||||
("ExecuteWebhook", webhookId), request, files)!;
|
("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) =>
|
private static string EncodeEmoji(Emoji emoji) =>
|
||||||
WebUtility.UrlEncode(emoji.Name) ?? emoji.Id?.ToString() ??
|
WebUtility.UrlEncode(emoji.Name) ?? emoji.Id?.ToString() ??
|
||||||
throw new ArgumentException("Could not encode emoji");
|
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 bool? Nsfw { get; init; }
|
||||||
public ulong? ParentId { get; init; }
|
public ulong? ParentId { get; init; }
|
||||||
public Overwrite[]? PermissionOverwrites { get; init; }
|
public Overwrite[]? PermissionOverwrites { get; init; }
|
||||||
|
public User[]? Recipients { get; init; }
|
||||||
|
|
||||||
public record Overwrite
|
public record Overwrite
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Myriad.Cache;
|
using Myriad.Cache;
|
||||||
|
using Myriad.Extensions;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using PluralKit.Bot.Utils;
|
using PluralKit.Bot.Utils;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Myriad.Extensions;
|
||||||
using Myriad.Rest.Exceptions;
|
using Myriad.Rest.Exceptions;
|
||||||
|
using Myriad.Rest.Types.Requests;
|
||||||
|
using Myriad.Types;
|
||||||
|
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
|
|
||||||
@ -26,22 +29,22 @@ namespace PluralKit.Bot
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// DM the user a security disclaimer, and then the token in a separate message (for easy copying on mobile)
|
// 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);
|
var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.RestNew, ctx.AuthorNew.Id);
|
||||||
await dm.SendMessageFixedAsync(
|
await ctx.RestNew.CreateMessage(dm.Id, new MessageRequest
|
||||||
$"{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);
|
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
|
// If we're not already in a DM, reply with a reminder to check
|
||||||
// TODO: DMs
|
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||||
// if (!(ctx.Channel is DiscordDmChannel))
|
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||||
// await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
|
||||||
}
|
}
|
||||||
catch (UnauthorizedException)
|
catch (UnauthorizedException)
|
||||||
{
|
{
|
||||||
// Can't check for permission errors beforehand, so have to handle here :/
|
// Can't check for permission errors beforehand, so have to handle here :/
|
||||||
// TODO: DMs
|
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||||
// if (!(ctx.Channel is DiscordDmChannel))
|
await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||||
// await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,25 +69,26 @@ namespace PluralKit.Bot
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// DM the user an invalidation disclaimer, and then the token in a separate message (for easy copying on mobile)
|
// 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);
|
var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.RestNew, ctx.AuthorNew.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:");
|
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
|
// 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 :)
|
// breaking their existing token as a side effect :)
|
||||||
var token = await MakeAndSetNewToken(ctx.System);
|
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
|
// If we're not already in a DM, reply with a reminder to check
|
||||||
// TODO: DMs
|
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||||
// if (!(ctx.Channel is DiscordDmChannel))
|
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||||
// await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
|
||||||
}
|
}
|
||||||
catch (UnauthorizedException)
|
catch (UnauthorizedException)
|
||||||
{
|
{
|
||||||
// Can't check for permission errors beforehand, so have to handle here :/
|
// Can't check for permission errors beforehand, so have to handle here :/
|
||||||
// TODO: DMs
|
if (ctx.ChannelNew.Type != Channel.ChannelType.Dm)
|
||||||
// if (!(ctx.Channel is DiscordDmChannel))
|
await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
||||||
// await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user