feat: upgrade to .NET 6, refactor everything
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web;
|
||||
using System.Linq;
|
||||
|
||||
using Dapper;
|
||||
|
||||
@@ -13,131 +9,137 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
namespace PluralKit.Bot
|
||||
{
|
||||
public class Member
|
||||
{
|
||||
private readonly IDatabase _db;
|
||||
private readonly ModelRepository _repo;
|
||||
private readonly EmbedService _embeds;
|
||||
private readonly HttpClient _client;
|
||||
private readonly DispatchService _dispatch;
|
||||
namespace PluralKit.Bot;
|
||||
|
||||
public Member(EmbedService embeds, IDatabase db, ModelRepository repo, HttpClient client, DispatchService dispatch)
|
||||
public class Member
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private readonly IDatabase _db;
|
||||
private readonly DispatchService _dispatch;
|
||||
private readonly EmbedService _embeds;
|
||||
private readonly ModelRepository _repo;
|
||||
|
||||
public Member(EmbedService embeds, IDatabase db, ModelRepository repo, HttpClient client,
|
||||
DispatchService dispatch)
|
||||
{
|
||||
_embeds = embeds;
|
||||
_db = db;
|
||||
_repo = repo;
|
||||
_client = client;
|
||||
_dispatch = dispatch;
|
||||
}
|
||||
|
||||
public async Task NewMember(Context ctx)
|
||||
{
|
||||
if (ctx.System == null) throw Errors.NoSystemError;
|
||||
var memberName = ctx.RemainderOrNull() ?? throw new PKSyntaxError("You must pass a member name.");
|
||||
|
||||
// Hard name length cap
|
||||
if (memberName.Length > Limits.MaxMemberNameLength)
|
||||
throw Errors.StringTooLongError("Member name", memberName.Length, Limits.MaxMemberNameLength);
|
||||
|
||||
// Warn if there's already a member by this name
|
||||
var existingMember = await _repo.GetMemberByName(ctx.System.Id, memberName);
|
||||
if (existingMember != null)
|
||||
{
|
||||
_embeds = embeds;
|
||||
_db = db;
|
||||
_repo = repo;
|
||||
_client = client;
|
||||
_dispatch = dispatch;
|
||||
var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?";
|
||||
if (!await ctx.PromptYesNo(msg, "Create")) throw new PKError("Member creation cancelled.");
|
||||
}
|
||||
|
||||
public async Task NewMember(Context ctx)
|
||||
{
|
||||
if (ctx.System == null) throw Errors.NoSystemError;
|
||||
var memberName = ctx.RemainderOrNull() ?? throw new PKSyntaxError("You must pass a member name.");
|
||||
await using var conn = await _db.Obtain();
|
||||
|
||||
// Hard name length cap
|
||||
if (memberName.Length > Limits.MaxMemberNameLength)
|
||||
throw Errors.StringTooLongError("Member name", memberName.Length, Limits.MaxMemberNameLength);
|
||||
// Enforce per-system member limit
|
||||
var memberCount = await _repo.GetSystemMemberCount(ctx.System.Id);
|
||||
var memberLimit = ctx.System.MemberLimitOverride ?? Limits.MaxMemberCount;
|
||||
if (memberCount >= memberLimit)
|
||||
throw Errors.MemberLimitReachedError(memberLimit);
|
||||
|
||||
// Warn if there's already a member by this name
|
||||
var existingMember = await _repo.GetMemberByName(ctx.System.Id, memberName);
|
||||
if (existingMember != null)
|
||||
// Create the member
|
||||
var member = await _repo.CreateMember(ctx.System.Id, memberName);
|
||||
memberCount++;
|
||||
|
||||
// Try to match an image attached to the message
|
||||
var avatarArg = ctx.Message.Attachments.FirstOrDefault();
|
||||
Exception imageMatchError = null;
|
||||
var sentDispatch = false;
|
||||
if (avatarArg != null)
|
||||
try
|
||||
{
|
||||
var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?";
|
||||
if (!await ctx.PromptYesNo(msg, "Create")) throw new PKError("Member creation cancelled.");
|
||||
}
|
||||
await AvatarUtils.VerifyAvatarOrThrow(_client, avatarArg.Url);
|
||||
await _db.Execute(conn =>
|
||||
_repo.UpdateMember(member.Id, new MemberPatch { AvatarUrl = avatarArg.Url }, conn));
|
||||
|
||||
await using var conn = await _db.Obtain();
|
||||
|
||||
// Enforce per-system member limit
|
||||
var memberCount = await _repo.GetSystemMemberCount(ctx.System.Id);
|
||||
var memberLimit = ctx.System.MemberLimitOverride ?? Limits.MaxMemberCount;
|
||||
if (memberCount >= memberLimit)
|
||||
throw Errors.MemberLimitReachedError(memberLimit);
|
||||
|
||||
// Create the member
|
||||
var member = await _repo.CreateMember(ctx.System.Id, memberName);
|
||||
memberCount++;
|
||||
|
||||
// Try to match an image attached to the message
|
||||
var avatarArg = ctx.Message.Attachments.FirstOrDefault();
|
||||
Exception imageMatchError = null;
|
||||
bool sentDispatch = false;
|
||||
if (avatarArg != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await AvatarUtils.VerifyAvatarOrThrow(_client, avatarArg.Url);
|
||||
await _db.Execute(conn => _repo.UpdateMember(member.Id, new MemberPatch { AvatarUrl = avatarArg.Url }, conn));
|
||||
|
||||
_ = _dispatch.Dispatch(member.Id, new()
|
||||
{
|
||||
Event = DispatchEvent.CREATE_MEMBER,
|
||||
EventData = JObject.FromObject(new { name = memberName, avatar_url = avatarArg.Url }),
|
||||
});
|
||||
sentDispatch = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
imageMatchError = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sentDispatch)
|
||||
_ = _dispatch.Dispatch(member.Id, new()
|
||||
_ = _dispatch.Dispatch(member.Id, new UpdateDispatchData
|
||||
{
|
||||
Event = DispatchEvent.CREATE_MEMBER,
|
||||
EventData = JObject.FromObject(new { name = memberName }),
|
||||
EventData = JObject.FromObject(new { name = memberName, avatar_url = avatarArg.Url }),
|
||||
});
|
||||
sentDispatch = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
imageMatchError = e;
|
||||
}
|
||||
|
||||
// Send confirmation and space hint
|
||||
await ctx.Reply($"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Check out the getting started page for how to get a member up and running: https://pluralkit.me/start#create-a-member");
|
||||
// todo: move this to ModelRepository
|
||||
if (await _db.Execute(conn => conn.QuerySingleAsync<bool>("select has_private_members(@System)",
|
||||
if (!sentDispatch)
|
||||
_ = _dispatch.Dispatch(member.Id, new UpdateDispatchData
|
||||
{
|
||||
Event = DispatchEvent.CREATE_MEMBER,
|
||||
EventData = JObject.FromObject(new { name = memberName }),
|
||||
});
|
||||
|
||||
// Send confirmation and space hint
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Check out the getting started page for how to get a member up and running: https://pluralkit.me/start#create-a-member");
|
||||
// todo: move this to ModelRepository
|
||||
if (await _db.Execute(conn => conn.QuerySingleAsync<bool>("select has_private_members(@System)",
|
||||
new { System = ctx.System.Id }))) //if has private members
|
||||
await ctx.Reply($"{Emojis.Warn} This member is currently **public**. To change this, use `pk;member {member.Hid} private`.");
|
||||
if (avatarArg != null)
|
||||
if (imageMatchError == null)
|
||||
await ctx.Reply($"{Emojis.Success} Member avatar set to attached image.\n{Emojis.Warn} If you delete the message containing the attachment, the avatar will stop working.");
|
||||
else
|
||||
await ctx.Reply($"{Emojis.Error} Couldn't set avatar: {imageMatchError.Message}");
|
||||
if (memberName.Contains(" "))
|
||||
await ctx.Reply($"{Emojis.Note} Note that this member's name contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it, or just use the member's 5-character ID (which is `{member.Hid}`).");
|
||||
if (memberCount >= memberLimit)
|
||||
await ctx.Reply($"{Emojis.Warn} You have reached the per-system member limit ({memberLimit}). You will be unable to create additional members until existing members are deleted.");
|
||||
else if (memberCount >= Limits.WarnThreshold(memberLimit))
|
||||
await ctx.Reply($"{Emojis.Warn} You are approaching the per-system member limit ({memberCount} / {memberLimit} members). Please review your member list for unused or duplicate members.");
|
||||
}
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Warn} This member is currently **public**. To change this, use `pk;member {member.Hid} private`.");
|
||||
if (avatarArg != null)
|
||||
if (imageMatchError == null)
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Success} Member avatar set to attached image.\n{Emojis.Warn} If you delete the message containing the attachment, the avatar will stop working.");
|
||||
else
|
||||
await ctx.Reply($"{Emojis.Error} Couldn't set avatar: {imageMatchError.Message}");
|
||||
if (memberName.Contains(" "))
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Note} Note that this member's name contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it, or just use the member's 5-character ID (which is `{member.Hid}`).");
|
||||
if (memberCount >= memberLimit)
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Warn} You have reached the per-system member limit ({memberLimit}). You will be unable to create additional members until existing members are deleted.");
|
||||
else if (memberCount >= Limits.WarnThreshold(memberLimit))
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Warn} You are approaching the per-system member limit ({memberCount} / {memberLimit} members). Please review your member list for unused or duplicate members.");
|
||||
}
|
||||
|
||||
public async Task ViewMember(Context ctx, PKMember target)
|
||||
{
|
||||
var system = await _repo.GetSystem(target.System);
|
||||
await ctx.Reply(embed: await _embeds.CreateMemberEmbed(system, target, ctx.Guild, ctx.LookupContextFor(system)));
|
||||
}
|
||||
public async Task ViewMember(Context ctx, PKMember target)
|
||||
{
|
||||
var system = await _repo.GetSystem(target.System);
|
||||
await ctx.Reply(
|
||||
embed: await _embeds.CreateMemberEmbed(system, target, ctx.Guild, ctx.LookupContextFor(system)));
|
||||
}
|
||||
|
||||
public async Task Soulscream(Context ctx, PKMember target)
|
||||
{
|
||||
// this is for a meme, please don't take this code seriously. :)
|
||||
public async Task Soulscream(Context ctx, PKMember target)
|
||||
{
|
||||
// this is for a meme, please don't take this code seriously. :)
|
||||
|
||||
var name = target.NameFor(ctx.LookupContextFor(target));
|
||||
var encoded = HttpUtility.UrlEncode(name);
|
||||
var name = target.NameFor(ctx.LookupContextFor(target));
|
||||
var encoded = HttpUtility.UrlEncode(name);
|
||||
|
||||
var resp = await _client.GetAsync($"https://onomancer.sibr.dev/api/generateStats2?name={encoded}");
|
||||
if (resp.StatusCode != HttpStatusCode.OK)
|
||||
// lol
|
||||
return;
|
||||
var resp = await _client.GetAsync($"https://onomancer.sibr.dev/api/generateStats2?name={encoded}");
|
||||
if (resp.StatusCode != HttpStatusCode.OK)
|
||||
// lol
|
||||
return;
|
||||
|
||||
var data = JObject.Parse(await resp.Content.ReadAsStringAsync());
|
||||
var scream = data["soulscream"]!.Value<string>();
|
||||
var data = JObject.Parse(await resp.Content.ReadAsStringAsync());
|
||||
var scream = data["soulscream"]!.Value<string>();
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
.Color(DiscordUtils.Red)
|
||||
.Title(name)
|
||||
.Url($"https://onomancer.sibr.dev/reflect?name={encoded}")
|
||||
.Description($"*{scream}*");
|
||||
await ctx.Reply(embed: eb.Build());
|
||||
}
|
||||
var eb = new EmbedBuilder()
|
||||
.Color(DiscordUtils.Red)
|
||||
.Title(name)
|
||||
.Url($"https://onomancer.sibr.dev/reflect?name={encoded}")
|
||||
.Description($"*{scream}*");
|
||||
await ctx.Reply(embed: eb.Build());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user