feat: go through some TODOs

This commit is contained in:
spiral 2021-11-26 22:02:58 -05:00
parent 04d78e3348
commit 4450ae4214
No known key found for this signature in database
GPG Key ID: A6059F0CA0E1BD31
21 changed files with 193 additions and 250 deletions

View File

@ -95,8 +95,7 @@ public class SwitchControllerV2: PKControllerBase
{
var member = await ResolveMember(memberRef);
if (member == null)
// todo: which member
throw Errors.MemberNotFound;
throw Errors.MemberNotFoundWithRef(memberRef);
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);
members.Add(member);
@ -214,8 +213,7 @@ public class SwitchControllerV2: PKControllerBase
var member = await ResolveMember(memberRef);
if (member == null)
// todo: which member
throw Errors.MemberNotFound;
throw Errors.MemberNotFoundWithRef(memberRef);
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);

View File

@ -7,13 +7,11 @@ namespace PluralKit.Bot;
public class Admin
{
private readonly BotConfig _botConfig;
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public Admin(BotConfig botConfig, IDatabase db, ModelRepository repo)
public Admin(BotConfig botConfig, ModelRepository repo)
{
_botConfig = botConfig;
_db = db;
_repo = repo;
}

View File

@ -13,7 +13,6 @@ namespace PluralKit.Bot;
public class Checks
{
private readonly Bot _bot;
private readonly BotConfig _botConfig;
private readonly IDiscordCache _cache;
private readonly IDatabase _db;
@ -29,11 +28,10 @@ public class Checks
PermissionSet.ManageWebhooks
};
public Checks(DiscordApiClient rest, Bot bot, IDiscordCache cache, IDatabase db, ModelRepository repo,
public Checks(DiscordApiClient rest, IDiscordCache cache, IDatabase db, ModelRepository repo,
BotConfig botConfig, ProxyService proxy, ProxyMatcher matcher)
{
_rest = rest;
_bot = bot;
_cache = cache;
_db = db;
_repo = repo;

View File

@ -0,0 +1,157 @@
using System.Text;
using Myriad.Builders;
using PluralKit.Core;
namespace PluralKit.Bot;
public class GroupMember
{
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public GroupMember(IDatabase db, ModelRepository repo)
{
_db = db;
_repo = repo;
}
public async Task AddRemoveGroups(Context ctx, PKMember target, Groups.AddRemoveOperation op)
{
ctx.CheckSystem().CheckOwnMember(target);
var groups = (await ctx.ParseGroupList(ctx.System.Id))
.Select(g => g.Id)
.Distinct()
.ToList();
var existingGroups = (await _repo.GetMemberGroups(target.Id).ToListAsync())
.Select(g => g.Id)
.Distinct()
.ToList();
List<GroupId> toAction;
if (op == Groups.AddRemoveOperation.Add)
{
toAction = groups
.Where(group => !existingGroups.Contains(group))
.ToList();
await _repo.AddGroupsToMember(target.Id, toAction);
}
else if (op == Groups.AddRemoveOperation.Remove)
{
toAction = groups
.Where(group => existingGroups.Contains(group))
.ToList();
await _repo.RemoveGroupsFromMember(target.Id, toAction);
}
else
{
return; // otherwise toAction "may be unassigned"
}
await ctx.Reply(GroupMemberUtils.GenerateResponse(op, 1, groups.Count, toAction.Count,
groups.Count - toAction.Count));
}
public async Task ListMemberGroups(Context ctx, PKMember target)
{
var pctx = ctx.LookupContextFor(target.System);
var groups = await _repo.GetMemberGroups(target.Id)
.Where(g => g.Visibility.CanAccess(pctx))
.OrderBy(g => g.Name, StringComparer.InvariantCultureIgnoreCase)
.ToListAsync();
var description = "";
var msg = "";
if (groups.Count == 0)
description = "This member has no groups.";
else
description = string.Join("\n", groups.Select(g => $"[`{g.Hid}`] **{g.DisplayName ?? g.Name}**"));
if (pctx == LookupContext.ByOwner)
{
msg +=
$"\n\nTo add this member to one or more groups, use `pk;m {target.Reference()} group add <group> [group 2] [group 3...]`";
if (groups.Count > 0)
msg +=
$"\nTo remove this member from one or more groups, use `pk;m {target.Reference()} group remove <group> [group 2] [group 3...]`";
}
await ctx.Reply(msg, new EmbedBuilder().Title($"{target.Name}'s groups").Description(description).Build());
}
public async Task AddRemoveMembers(Context ctx, PKGroup target, Groups.AddRemoveOperation op)
{
ctx.CheckOwnGroup(target);
var members = (await ctx.ParseMemberList(ctx.System.Id))
.Select(m => m.Id)
.Distinct()
.ToList();
var existingMembersInGroup = (await _db.Execute(conn => conn.QueryMemberList(target.System,
new DatabaseViewsExt.MemberListQueryOptions { GroupFilter = target.Id })))
.Select(m => m.Id.Value)
.Distinct()
.ToHashSet();
List<MemberId> toAction;
if (op == Groups.AddRemoveOperation.Add)
{
toAction = members
.Where(m => !existingMembersInGroup.Contains(m.Value))
.ToList();
await _repo.AddMembersToGroup(target.Id, toAction);
}
else if (op == Groups.AddRemoveOperation.Remove)
{
toAction = members
.Where(m => existingMembersInGroup.Contains(m.Value))
.ToList();
await _repo.RemoveMembersFromGroup(target.Id, toAction);
}
else
{
return; // otherwise toAction "may be undefined"
}
await ctx.Reply(GroupMemberUtils.GenerateResponse(op, members.Count, 1, toAction.Count,
members.Count - toAction.Count));
}
public async Task ListGroupMembers(Context ctx, PKGroup target)
{
var targetSystem = await GetGroupSystem(ctx, target);
ctx.CheckSystemPrivacy(targetSystem, target.ListPrivacy);
var opts = ctx.ParseMemberListOptions(ctx.LookupContextFor(target.System));
opts.GroupFilter = target.Id;
var title = new StringBuilder($"Members of {target.DisplayName ?? target.Name} (`{target.Hid}`) in ");
if (targetSystem.Name != null)
title.Append($"{targetSystem.Name} (`{targetSystem.Hid}`)");
else
title.Append($"`{targetSystem.Hid}`");
if (opts.Search != null)
title.Append($" matching **{opts.Search}**");
await ctx.RenderMemberList(ctx.LookupContextFor(target.System), target.System, title.ToString(),
target.Color, opts);
}
private async Task<PKSystem> GetGroupSystem(Context ctx, PKGroup target)
{
var system = ctx.System;
if (system?.Id == target.System)
return system;
return await _repo.GetSystem(target.System)!;
}
}

View File

@ -471,67 +471,6 @@ public class Groups
await ctx.Reply(embed: await _embeds.CreateGroupEmbed(ctx, system, target));
}
// todo: move this to MemberGroup.cs
public async Task AddRemoveMembers(Context ctx, PKGroup target, AddRemoveOperation op)
{
ctx.CheckOwnGroup(target);
var members = (await ctx.ParseMemberList(ctx.System.Id))
.Select(m => m.Id)
.Distinct()
.ToList();
var existingMembersInGroup = (await _db.Execute(conn => conn.QueryMemberList(target.System,
new DatabaseViewsExt.MemberListQueryOptions { GroupFilter = target.Id })))
.Select(m => m.Id.Value)
.Distinct()
.ToHashSet();
List<MemberId> toAction;
if (op == AddRemoveOperation.Add)
{
toAction = members
.Where(m => !existingMembersInGroup.Contains(m.Value))
.ToList();
await _repo.AddMembersToGroup(target.Id, toAction);
}
else if (op == AddRemoveOperation.Remove)
{
toAction = members
.Where(m => existingMembersInGroup.Contains(m.Value))
.ToList();
await _repo.RemoveMembersFromGroup(target.Id, toAction);
}
else
{
return; // otherwise toAction "may be undefined"
}
await ctx.Reply(GroupMemberUtils.GenerateResponse(op, members.Count, 1, toAction.Count,
members.Count - toAction.Count));
}
public async Task ListGroupMembers(Context ctx, PKGroup target)
{
var targetSystem = await GetGroupSystem(ctx, target);
ctx.CheckSystemPrivacy(targetSystem, target.ListPrivacy);
var opts = ctx.ParseMemberListOptions(ctx.LookupContextFor(target.System));
opts.GroupFilter = target.Id;
var title = new StringBuilder($"Members of {target.DisplayName ?? target.Name} (`{target.Hid}`) in ");
if (targetSystem.Name != null)
title.Append($"{targetSystem.Name} (`{targetSystem.Hid}`)");
else
title.Append($"`{targetSystem.Hid}`");
if (opts.Search != null)
title.Append($" matching **{opts.Search}**");
await ctx.RenderMemberList(ctx.LookupContextFor(target.System), _db, target.System, title.ToString(),
target.Color, opts);
}
public async Task GroupPrivacy(Context ctx, PKGroup target, PrivacyLevel? newValueFromCommand)
{
ctx.CheckSystem().CheckOwnGroup(target);

View File

@ -9,12 +9,10 @@ namespace PluralKit.Bot;
public class MemberAvatar
{
private readonly HttpClient _client;
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public MemberAvatar(IDatabase db, ModelRepository repo, HttpClient client)
public MemberAvatar(ModelRepository repo, HttpClient client)
{
_db = db;
_repo = repo;
_client = client;
}

View File

@ -13,12 +13,10 @@ namespace PluralKit.Bot;
public class MemberEdit
{
private readonly HttpClient _client;
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public MemberEdit(IDatabase db, ModelRepository repo, HttpClient client)
public MemberEdit(ModelRepository repo, HttpClient client)
{
_db = db;
_repo = repo;
_client = client;
}

View File

@ -1,87 +0,0 @@
using Myriad.Builders;
using PluralKit.Core;
namespace PluralKit.Bot;
public class MemberGroup
{
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public MemberGroup(IDatabase db, ModelRepository repo)
{
_db = db;
_repo = repo;
}
public async Task AddRemove(Context ctx, PKMember target, Groups.AddRemoveOperation op)
{
ctx.CheckSystem().CheckOwnMember(target);
var groups = (await ctx.ParseGroupList(ctx.System.Id))
.Select(g => g.Id)
.Distinct()
.ToList();
var existingGroups = (await _repo.GetMemberGroups(target.Id).ToListAsync())
.Select(g => g.Id)
.Distinct()
.ToList();
List<GroupId> toAction;
if (op == Groups.AddRemoveOperation.Add)
{
toAction = groups
.Where(group => !existingGroups.Contains(group))
.ToList();
await _repo.AddGroupsToMember(target.Id, toAction);
}
else if (op == Groups.AddRemoveOperation.Remove)
{
toAction = groups
.Where(group => existingGroups.Contains(group))
.ToList();
await _repo.RemoveGroupsFromMember(target.Id, toAction);
}
else
{
return; // otherwise toAction "may be unassigned"
}
await ctx.Reply(GroupMemberUtils.GenerateResponse(op, 1, groups.Count, toAction.Count,
groups.Count - toAction.Count));
}
public async Task List(Context ctx, PKMember target)
{
var pctx = ctx.LookupContextFor(target.System);
var groups = await _repo.GetMemberGroups(target.Id)
.Where(g => g.Visibility.CanAccess(pctx))
.OrderBy(g => g.Name, StringComparer.InvariantCultureIgnoreCase)
.ToListAsync();
var description = "";
var msg = "";
if (groups.Count == 0)
description = "This member has no groups.";
else
description = string.Join("\n", groups.Select(g => $"[`{g.Hid}`] **{g.DisplayName ?? g.Name}**"));
if (pctx == LookupContext.ByOwner)
{
msg +=
$"\n\nTo add this member to one or more groups, use `pk;m {target.Reference()} group add <group> [group 2] [group 3...]`";
if (groups.Count > 0)
msg +=
$"\nTo remove this member from one or more groups, use `pk;m {target.Reference()} group remove <group> [group 2] [group 3...]`";
}
await ctx.Reply(msg, new EmbedBuilder().Title($"{target.Name}'s groups").Description(description).Build());
}
}

View File

@ -17,37 +17,22 @@ namespace PluralKit.Bot;
public class Misc
{
private readonly Bot _bot;
private readonly BotConfig _botConfig;
private readonly IDiscordCache _cache;
private readonly Cluster _cluster;
private readonly CpuStatService _cpu;
private readonly IDatabase _db;
private readonly EmbedService _embeds;
private readonly ProxyMatcher _matcher;
private readonly IMetrics _metrics;
private readonly ProxyService _proxy;
private readonly ModelRepository _repo;
private readonly DiscordApiClient _rest;
private readonly ShardInfoService _shards;
public Misc(BotConfig botConfig, IMetrics metrics, CpuStatService cpu, ShardInfoService shards,
EmbedService embeds, ModelRepository repo, IDatabase db, IDiscordCache cache,
DiscordApiClient rest, Bot bot, Cluster cluster, ProxyService proxy, ProxyMatcher matcher)
ModelRepository repo, IDiscordCache cache)
{
_botConfig = botConfig;
_metrics = metrics;
_cpu = cpu;
_shards = shards;
_embeds = embeds;
_repo = repo;
_db = db;
_cache = cache;
_rest = rest;
_bot = bot;
_cluster = cluster;
_proxy = proxy;
_matcher = matcher;
}
public async Task Invite(Context ctx)

View File

@ -11,20 +11,15 @@ namespace PluralKit.Bot;
public class ServerConfig
{
private readonly Bot _bot;
private readonly IDiscordCache _cache;
private readonly LoggerCleanService _cleanService;
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public ServerConfig(LoggerCleanService cleanService, IDatabase db, ModelRepository repo, IDiscordCache cache,
Bot bot)
public ServerConfig(LoggerCleanService cleanService, ModelRepository repo, IDiscordCache cache)
{
_cleanService = cleanService;
_db = db;
_repo = repo;
_cache = cache;
_bot = bot;
}
public async Task SetLogChannel(Context ctx)

View File

@ -4,14 +4,12 @@ namespace PluralKit.Bot;
public class System
{
private readonly IDatabase _db;
private readonly EmbedService _embeds;
private readonly ModelRepository _repo;
public System(EmbedService embeds, IDatabase db, ModelRepository repo)
public System(EmbedService embeds, ModelRepository repo)
{
_embeds = embeds;
_db = db;
_repo = repo;
}

View File

@ -14,12 +14,10 @@ namespace PluralKit.Bot;
public class SystemEdit
{
private readonly HttpClient _client;
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public SystemEdit(IDatabase db, ModelRepository repo, HttpClient client)
public SystemEdit(ModelRepository repo, HttpClient client)
{
_db = db;
_repo = repo;
_client = client;
}

View File

@ -35,10 +35,6 @@ public class SystemFront
if (system == null) throw Errors.NoSystemError;
ctx.CheckSystemPrivacy(system, system.FrontHistoryPrivacy);
// Gotta be careful here: if we dispose of the connection while the IAE is alive, boom
// todo: this comment was here, but we're not getting a connection here anymore
// hopefully nothing breaks?
var totalSwitches = await _repo.GetSwitchCount(system.Id);
if (totalSwitches == 0) throw Errors.NoRegisteredSwitches;

View File

@ -6,12 +6,10 @@ namespace PluralKit.Bot;
public class SystemLink
{
private readonly IDatabase _db;
private readonly ModelRepository _repo;
public SystemLink(IDatabase db, ModelRepository repo)
public SystemLink(ModelRepository repo)
{
_db = db;
_repo = repo;
}

View File

@ -6,13 +6,6 @@ namespace PluralKit.Bot;
public class SystemList
{
private readonly IDatabase _db;
public SystemList(IDatabase db)
{
_db = db;
}
public async Task MemberList(Context ctx, PKSystem target)
{
if (target == null) throw Errors.NoSystemError;
@ -21,7 +14,6 @@ public class SystemList
var opts = ctx.ParseMemberListOptions(ctx.LookupContextFor(target));
await ctx.RenderMemberList(
ctx.LookupContextFor(target),
_db,
target.Id,
GetEmbedTitle(target, opts),
target.Color,

View File

@ -122,11 +122,7 @@ public class Init
var builder = new ContainerBuilder();
builder.RegisterInstance(config);
builder.RegisterModule(new ConfigModule<BotConfig>("Bot"));
builder.RegisterModule(new LoggingModule("bot", cfg =>
{
// TODO: do we need this?
// cfg.Destructure.With<EventDestructuring>();
}));
builder.RegisterModule(new LoggingModule("bot"));
builder.RegisterModule(new MetricsModule());
builder.RegisterModule<DataStoreModule>();
builder.RegisterModule<BotModule>();

View File

@ -74,12 +74,12 @@ public class BotModule: Module
builder.RegisterType<Checks>().AsSelf();
builder.RegisterType<Fun>().AsSelf();
builder.RegisterType<Groups>().AsSelf();
builder.RegisterType<GroupMember>().AsSelf();
builder.RegisterType<Help>().AsSelf();
builder.RegisterType<ImportExport>().AsSelf();
builder.RegisterType<Member>().AsSelf();
builder.RegisterType<MemberAvatar>().AsSelf();
builder.RegisterType<MemberEdit>().AsSelf();
builder.RegisterType<MemberGroup>().AsSelf();
builder.RegisterType<MemberProxy>().AsSelf();
builder.RegisterType<Misc>().AsSelf();
builder.RegisterType<ProxiedMessage>().AsSelf();

View File

@ -71,7 +71,7 @@ public class ProxyService
throw new PKError("PluralKit cannot proxy messages over 2000 characters in length.");
// Permission check after proxy match so we don't get spammed when not actually proxying
if (!await CheckBotPermissionsOrError(botPermissions, rootChannel.Id))
if (!CheckBotPermissionsOrError(botPermissions, rootChannel.Id))
return false;
// this method throws, so no need to wrap it in an if statement
@ -345,7 +345,7 @@ public class ProxyService
catch (UnauthorizedException) { }
}
private async Task<bool> CheckBotPermissionsOrError(PermissionSet permissions, ulong responseChannel)
private bool CheckBotPermissionsOrError(PermissionSet permissions, ulong responseChannel)
{
// If we can't send messages at all, just bail immediately.
// 2020-04-22: Manage Messages does *not* override a lack of Send Messages.
@ -353,25 +353,12 @@ public class ProxyService
return false;
if (!permissions.HasFlag(PermissionSet.ManageWebhooks))
{
// todo: PKError-ify these
await _rest.CreateMessage(responseChannel, new MessageRequest
{
Content = $"{Emojis.Error} PluralKit does not have the *Manage Webhooks* permission in this channel, and thus cannot proxy messages."
+ " Please contact a server administrator to remedy this."
});
return false;
}
throw new PKError("PluralKit does not have the *Manage Webhooks* permission in this channel, and thus cannot proxy messages."
+ " Please contact a server administrator to remedy this.");
if (!permissions.HasFlag(PermissionSet.ManageMessages))
{
await _rest.CreateMessage(responseChannel, new MessageRequest
{
Content = $"{Emojis.Error} PluralKit does not have the *Manage Messages* permission in this channel, and thus cannot delete the original trigger message."
+ " Please contact a server administrator to remedy this."
});
return false;
}
throw new PKError("PluralKit does not have the *Manage Messages* permission in this channel, and thus cannot delete the original trigger message."
+ " Please contact a server administrator to remedy this.");
return true;
}

View File

@ -68,19 +68,17 @@ public class LoggerCleanService
.Where(b => b.WebhookName != null)
.ToDictionary(b => b.WebhookName);
private readonly Bot _bot; // todo: get rid of this nasty
private readonly IDiscordCache _cache;
private readonly DiscordApiClient _client;
private readonly IDatabase _db;
private readonly ILogger _logger;
public LoggerCleanService(IDatabase db, DiscordApiClient client, IDiscordCache cache, Bot bot, ILogger logger)
public LoggerCleanService(IDatabase db, DiscordApiClient client, IDiscordCache cache, ILogger logger)
{
_db = db;
_client = client;
_cache = cache;
_bot = bot;
_logger = logger.ForContext<LoggerCleanService>();
}

View File

@ -104,6 +104,7 @@ public partial class BulkImporter
if (isNewMember)
{
patch.MessageCount = member.Value<int>("message_count");
var newMember = await _repo.CreateMember(_system.Id, patch.Name.Value, _conn);
memberId = newMember.Id;
}

View File

@ -47,6 +47,20 @@ public partial class BulkImporter
var multipleTags = false;
var name = tupper.Value<string>("name");
var isNewMember = false;
if (!_existingMemberNames.TryGetValue(name, out var memberId))
{
var newMember = await _repo.CreateMember(_system.Id, name, _conn);
memberId = newMember.Id;
isNewMember = true;
_result.Added++;
}
else
{
_result.Modified++;
}
var patch = new MemberPatch();
patch.Name = name;
@ -63,8 +77,7 @@ public partial class BulkImporter
patch.ProxyTags = tags.ToArray();
}
// todo: && if is new member
if (tupper.ContainsKey("posts")) patch.MessageCount = tupper.Value<int>("posts");
if (tupper.ContainsKey("posts") && isNewMember) patch.MessageCount = tupper.Value<int>("posts");
if (tupper.ContainsKey("show_brackets")) patch.KeepProxy = tupper.Value<bool>("show_brackets");
if (tupper.ContainsKey("birthday") && tupper["birthday"].Type != JTokenType.Null)
{
@ -100,19 +113,6 @@ public partial class BulkImporter
throw new ImportException($"Field {err.Key} in tupper {name} is invalid.");
}
var isNewMember = false;
if (!_existingMemberNames.TryGetValue(name, out var memberId))
{
var newMember = await _repo.CreateMember(_system.Id, name, _conn);
memberId = newMember.Id;
isNewMember = true;
_result.Added++;
}
else
{
_result.Modified++;
}
_logger.Debug(
"Importing member with identifier {FileId} to system {System} (is creating new member? {IsCreatingNewMember})",
name, _system.Id, isNewMember);